• Spring对国际化的支持


    前言

    i18n(其来源是英文单词 internationalization 的首末字符i和n,18为中间的字符数)是"国际化"的简称。对程序来说,可以在不修改内部代码的情况下,根据不同语言及地区显示不同的页面。

    准备工作

    IDEA中properties文件默认的编码为GBK,需要修改为UTF-8。

    Java支持

    java内部提供了对 i18n 的支持,使用ResourceBundle工具类。

    配置资源文件

    配置不同语言的资源文件,需要配置在classpath下,因为我的是SpringBoot项目,所以放在了resources目录下

    en_US表示美国,

    name=lisi
    

    zh_CN表示中国

    name=李四
    

    没有后缀表示默认,设置为其他配置的父配置文件

    name=lisi
    age=23
    

    代码处理

    import java.util.Locale;
    import java.util.ResourceBundle;
    
    public class TestI18n {
    
      public static void main(String[] args) {
        //获取US(美国)的配置信息
        ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n/messages", Locale.CHINA);
        for (String key : resourceBundle.keySet()) {
          System.out.println(resourceBundle.getObject(key));//lisi age
        }
        //测试默认的配置
        resourceBundle = ResourceBundle.getBundle("i18n/messages", Locale.ITALY);
        System.out.println(resourceBundle.keySet());//name,age
      }
    
    }
    

    先根据传入的Locale查询到配置文件,如果查询不到,再查询默认的配置文件。

    Spring支持

    Spring在Java的基础上做了封装,加了一层缓存,并且支持模板信息。

    配置文件

    默认配置文件有变动,其他不变

    name=lisi
    age={0}
    

    代码处理

    import java.util.Locale;
    import org.springframework.context.support.ResourceBundleMessageSource;
    
    public class TestSpringI18n {
    
      public static void main(String[] args) {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        //需要设置为UTF-8,默认为ISO-8859-1
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.addBasenames("i18n/messages");
        System.out.println(messageSource.getMessage("name", null, Locale.CHINA));//李四
        System.out.println(messageSource.getMessage("age", new Object[]{"12"}, Locale.CHINA));//12
      }
    
    }
    

    模板消息是使用Java中的MessageFormat实现的,格式为{index}

    Spring内部对ResourceBundle的缓存处理。

    SpringBoot支持

    SpringBoot在Spring的基础上添加了自动配置。这里我们简单实现一个功能,根据不同的语言返回不同的name。

    配置路径

    server:
      port: 8880
      servlet:
        context-path: /i18n
    
    spring:
      messages:
        basename: i18n/messages
    

    可以看到SpringBoot默认使用的就是ResourceBundleMessageSource。

    配置自定义Locale解析器

    import java.util.Locale;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.stereotype.Service;
    import org.springframework.web.servlet.DispatcherServlet;
    import org.springframework.web.servlet.i18n.AbstractLocaleResolver;
    
    /**
     * bean名称必须为localeResolver
     */
    @Service(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)
    public class CustomLocaleReslover extends AbstractLocaleResolver {
    
      @Override
      public Locale resolveLocale(HttpServletRequest request) {
        String language = request.getHeader("language");
        if ("zh".equals(language)) {
          return Locale.CHINA;
        }
        if ("en".equals(language)) {
          return Locale.US;
        }
        return Locale.CHINA;
      }
    
      @Override
      public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
    
      }
    }
    

    bean名称必须为localeResolver,因为DispatcherServlet中就是根据这个name来获取实例的。

    配置Controller

    import javax.servlet.http.HttpServletRequest;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.support.RequestContext;
    
    @RestController
    @RequestMapping("/test")
    public class TestController {
    
      @GetMapping("/testI18n")
      public String testI18n(HttpServletRequest request) {
        RequestContext requestContext = new RequestContext(request);
        return requestContext.getMessage("name");
      }
    }
    

    HibernateValidator支持

    SpringBoot自动注入了HibernateValidator

    但使用的是默认的ResourceBundleLocator,默认的ResourceBundle路径为ValidationMessages。我们需要自定义路径。

    配置自定义消息处理器

    @Configuration
    public class HibernateValidatorConfig {
    
      @Bean
      @ConditionalOnMissingBean(Validator.class)
      public static LocalValidatorFactoryBean defaultValidator(MessageSource messageSource) {
        LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
        ResourceBundleMessageInterpolator messageInterpolator = new ResourceBundleMessageInterpolator(
            new MessageSourceResourceBundleLocator(messageSource));
        factoryBean.setMessageInterpolator(messageInterpolator);
        return factoryBean;
      }
    
    }
    

    实体类

    import javax.validation.constraints.NotBlank;
    
    public class TestRequest {
    
      @NotBlank(message = "{username.errormsg}")
      private String username;
    
      public void setUsername(String username) {
        this.username = username;
      }
    
      public String getUsername() {
        return username;
      }
    }
    

    配置文件

    默认配置文件有变动,其他不变

    name=lisi
    username.errormsg=用户名称不能为空
    

    配置Controller

    @RestController
    @RequestMapping("/test")
    public class TestController {
    
      @GetMapping("/testI18n")
      public String testI18n(HttpServletRequest request, @Valid @RequestBody TestRequest testRequest,
          BindingResult bindingResult) {
        RequestContext requestContext = new RequestContext(request);
        if (bindingResult.hasErrors()) {
          return bindingResult.getAllErrors().get(0).getDefaultMessage();//用户名称不能为空
        }
        return requestContext.getMessage("name");
      }
    }
    

    如果没有传username,就会返回"用户名称不能为空"的错误信息。

  • 相关阅读:
    P1288 取数游戏II
    设置ip的bat
    oracle 服务器配置
    查看硬盘空间
    oracle 备份还原相关_转贴
    ssh 乱码
    inno setup regedit
    db locked ?
    用户控件和页面
    什么是接口?接口有哪些好处,抽象类(abstract)和接口(interface)的区别
  • 原文地址:https://www.cnblogs.com/strongmore/p/16101895.html
Copyright © 2020-2023  润新知