spring国际化locale的代码原理以及拓展配置

一、原理

两种不同的LocaleResolve

LocaleResolver

public interface LocaleResolver {

  	//解析Lcoale
   Locale resolveLocale(HttpServletRequest request);

    //设置Locale
   void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, 
                  @Nullable Locale locale);

LocaleContextResolver多了解析时区的功能

/**
 * Extension of {@link LocaleResolver}, adding support for a rich locale context
 * (potentially including locale and time zone information).
 */
public interface LocaleContextResolver extends LocaleResolver {

   LocaleContext resolveLocaleContext(HttpServletRequest request);

   void setLocaleContext(HttpServletRequest request, 
                         @Nullable HttpServletResponse response,
        				 @Nullable LocaleContext localeContext);

LocaleContext

public interface LocaleContext {
    @Nullable
    Locale getLocale();
}

在DispatchServlet配置新的LocaleContext

//每次请求都会解析配置新的LocaleContext
@Override
protected LocaleContext buildLocaleContext(final HttpServletRequest request) {
    LocaleResolver lr = this.localeResolver;
    //根据locale不同等级进行调用
    if (lr instanceof LocaleContextResolver) {
        return ((LocaleContextResolver) lr).resolveLocaleContext(request);
    }
    else {
        //lumbda表达式返回一个类(重写了LcoaleContext的getLocale方法)
        return () -> (lr != null ? lr.resolveLocale(request) : request.getLocale());
    }
}

通过rend方法,使用response渲染

protected void render(ModelAndView mv, HttpServletRequest request,
                      HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale =
        (this.localeResolver != null ?
         this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);//在response方法写出Locale

二、实现

/**
 *自定义的LocaleReslover和Controller(可以根据URL设置Locale并且放在Session当中)
 */
public class ParamLocaleResolver implements LocaleResolver {
	//Session域的键的名称
    public static final String LOCALE_SESSION_ATTRIBUTE_NAME 
        = ParamLocaleResolver.class.getName() + ".LOCALE";
    
    private String localeAttributeName = LOCALE_SESSION_ATTRIBUTE_NAME;
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        //每次从Session当中获取,不需要重新创建。
        Locale locale 
            = ((Locale) WebUtils.getSessionAttribute(request, localeAttributeName));
        if (locale == null) {
            //第一次将浏览器默认的locale写入Session
            locale = request.getLocale();
            WebUtils.setSessionAttribute(request, localeAttributeName, locale);
        }
        return locale;
    }
    @Override
    public void setLocale(HttpServletRequest request, 
                          HttpServletResponse response, Locale locale) {
        if (locale != null) {
            //重新写入Session当中
            WebUtils.setSessionAttribute(request, localeAttributeName, locale);
        }
    }
}
@Controller
public class LocaleController {

    @RequestMapping("/setLocal")
    public String setLocale(HttpServletRequest request,
                            @Autowired ParamLocaleResolver resolver) {
        //根据参数获取Locale
        String param = request.getParameter("locale");

        if (!StringUtils.isEmpty(param)) {
            String[] split = param.split("_");
            Locale locale = new Locale(split[0], split[1]);
            //locale解析成功设置新的locale
            resolver.setLocale(request, null, locale);
        }
        return "login";
    }
}

三、配置

(spring国际化locale的代码原理以及拓展配置

applications.properties

# 默认放在类路径下的 message.properties
#eg:classpath:/message/login.properties basename写为message.login (会将‘.’解析为 ‘/’)
spring.messages.basename=message