avatar

04.CURD实验之国际化

一、导入页面

  1. 把js、css、img文件导入到resources/public目录下。这样静态资源就可以被浏览器访问得到。因为SpringMVC的自动配置里面声明了/**的访问路径。
  2. 把页面放入resources/templates下。以便于Thymeleaf去渲染。

二、国际化

  1. 之前写国际化的步骤

    1. 编写国际化资源文件
    2. 使用ResourceBundleMessageSource管理国际化资源文件
    3. 在页面使用标签取出国际化内容。
  2. SpringBoot中国际化的步骤:

    1. 编写国际化资源文件
    2. SpringBoot已经为我们配置好了管理国际化资源的组件<MessageSourceAutoConfiguration>
    3. 在页面使用标签取出国际化内容即可。
  3. MessageSourceAutoConfiguration 简析

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public class MessageSourceAutoConfiguration {

    private static final Resource[] NO_RESOURCES = {};

    @Bean
    @ConfigurationProperties(prefix = "spring.messages") //为MessageSourceProperties绑定了配置文件属性
    public MessageSourceProperties messageSourceProperties() {
    return new MessageSourceProperties();
    }

    @Bean
    public MessageSource messageSource() {
    MessageSourceProperties properties = messageSourceProperties();//获取绑定了配置文件的类
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();//创建了管理国际化资源文件类
    if (StringUtils.hasText(properties.getBasename())) {
    //设置资源文件的基础名(去除语言国家代码的)
    messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
    StringUtils.trimAllWhitespace(properties.getBasename())));
    }
    if (properties.getEncoding() != null) {
    //设置编码
    messageSource.setDefaultEncoding(properties.getEncoding().name());
    }
    messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
    Duration cacheDuration = properties.getCacheDuration();
    if (cacheDuration != null) {
    messageSource.setCacheMillis(cacheDuration.toMillis());
    }
    messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
    messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
    return messageSource;
    }
    }

    可见,自动配置中帮我们创建了一个ResourceBundleMessageSource,并且设置了基础名。默认的资源文件的基础名是messages 这个可以在MessageSourceProperties 中看到。

  4. 动手实现国际化。

    1. 编写application.properties文件。指定我们自己的基础包名。这里我们改成yml文件。

      1
      2
      3
      4
      5
      spring:
      messages:
      #指定message的basename,多个以逗号分隔,如果不加包名的话,默认从classpath路径开始,默认: messages
      basename: i18n/login # 也可以写成i18n.login方式
      encoding: UTF-8

      配置文件位置

    2. 编写国际化资源文件

    3. 在页面引用,使用#{}引用

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      <!DOCTYPE html>
      <html lang="en" xmlns:th="http://www.thymeleaf.org">
      <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
      <meta name="description" content="">
      <meta name="author" content="">
      <title>Signin Template for Bootstrap</title>
      <!-- Bootstrap core CSS -->
      <link href="asserts/css/bootstrap.min.css" rel="stylesheet">
      <!-- Custom styles for this template -->
      <link href="asserts/css/signin.css" rel="stylesheet">
      </head>

      <body class="text-center">
      <form class="form-signin" action="dashboard.html">
      <img class="mb-4" src="asserts/img/bootstrap-solid.svg" alt="" width="72" height="72">
      <h1 class="h3 mb-3 font-weight-normal" th:text="#{login.welcome}">Please sign in</h1>
      <label class="sr-only" th:text="#{login.username}">Username</label>
      <input type="text" class="form-control" th:placeholder="#{login.username}" required="" >
      <label class="sr-only" th:text="#{login.password}">Password</label>
      <input type="password" class="form-control" th:placeholder="#{login.password}" required="">
      <div class="checkbox mb-3">
      <label>
      <input type="checkbox" value="remember-me"> [[#{login.remember}]]<!--[[]]为thymeleaf的内联表达式-->
      </label>
      </div>
      <button class="btn btn-lg btn-primary btn-block" type="submit" th:text="#{login.loginBtn}">
      Sign in
      </button>
      <p class="mt-5 mb-3 text-muted">© 2017-2018</p>
      <a class="btn btn-sm">中文</a>
      <a class="btn btn-sm">English</a>
      </form>

      </body>

      </html>
  5. 国际化文件加载原理

    • LocalResolve 在SpringMVC自动配置类WebMvcAutoConfiguration 中有如下代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      @Bean //把bean加入到容器中
      @ConditionalOnMissingBean //容器中没有localeResolver这个bean才会生效。
      @ConditionalOnProperty(prefix = "spring.mvc", name = "locale") //绑定配置文件spring.mvc.locale
      public LocaleResolver localeResolver() {
      if (this.mvcProperties
      .getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
      return new FixedLocaleResolver(this.mvcProperties.getLocale());
      }
      //默认是通过请求中的Accept-Language来确定区域信息的。
      AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
      localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
      return localeResolver;
      }

      可以明确的知道,默认是通过获取请求头的Accept-Language信息(可在AcceptHeaderLocaleResolver的resolveLocale方法中得到)来确定Locale<区域信息>,来进行国际化。

  6. 如何覆盖默认的获取请求头方式的LocaleResolver?自定义我们自己的规则,比如在请求的时候传递language参数来确定国际化文件。

    • 我们只需要自己写一个类,实现LocaleResolver 类,然后写我们自己的实现。并在配置类中(加了@Configuration注解的类)使用@Bean配置即可。当SpringMVC自动配置是,发现容器中已经有了一个LocaleResolver 的实例,他就不会加载默认的LocaleResolver 。实现代码如下:
      • 自定义LocaleResolver

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        public class MyLocaleResolver implements LocaleResolver {
        /**
        * 根据参数:language来确定要显示的语言
        * @param request
        * @return
        */
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
        //获取参数
        String language = request.getParameter("language");
        //创建个默认的Locale
        Locale locale = Locale.getDefault();
        //如果language为null,或空字符串。则我们按照请求头Accept-Language信息来确定
        if(!StringUtils.hasText(language)){
        //获取请求头
        String header = request.getHeader("Accept-Language");
        //如果header中也没有,则按默认的。
        if(StringUtils.hasText(header)){
        String[] split = header.split(",");
        locale = new Locale(split[0]);
        }
        }else{
        //如果language不为空,则按language参数
        String[] split = language.split("_");
        locale = new Locale(split[0],split[1]);
        }
        return locale;
        }

        @Override
        public void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale) {

        }
        }
      • 配置类

        1
        2
        3
        4
        @Bean
        public LocaleResolver localeResolver(){ //注意,这里的方法名一定要是localeResolver。不然不会生效。原因看自动配置
        return new MyLocaleResolver();
        }

登录功能实现(包含拦截器)


评论