springboot 国际化处理

国际化处理的关键类

Locale 语言设置,由language 和 country 组成

LocaleContextHolder 语言上下文,实际为ThreadLocal,

   其中包含两个ThreadLocal:
    	一个为当前线程的语言环境localeContextHolder
        一个为inheritableLocaleContextHolder
        关键方法:
           setLocale():设置当前语言环境
           getLocale():获取当前语言环境
           resetLocaleContext():重置语言环境

MessageSource 语言包

   关键方法:
     getMessage(key, null, locale):根据key和语言获取消息

LocaleResolver 默认使用的语言包

     当未找到相应语言时,使用的语言环境,需注册为bean       

接入流程:

概述:

spring 环境下 spring-context-5.2.14.RELEASE.jar 中,已有i18n相关依赖
在请求到来时,获取用户设置的语言环境,并将该环境设置进上下文
后续需要国际化的地方,使用MessageSource,根据key进行信息获取
请求结束后,对上下文环境进行reset

接入关键点

  1. 在resources下,新建i18n文件夹,并在其中创建

       message.properties:当未找到相应的语言环境时,会使用此语言包的内容
       message_zh_CN.properties:中文:中国
       message_en_US.properties:英文:美国
      内容为key=value形式
    
  2. 配置:

     spring:
       messages:
         basename: i18n/messages  # 资源存放位置
         encoding: UTF-8
         use-code-as-default-message: true  # 当找不到code对应的消息时,是否使用code作为消息
    
  3. 注册LocaleResolver,设置默认语言环境。

  4. 在相应的位置进行语言设置:

     前端设置:在header或cookies中进行语言设置,请求时传递,由后台解析
     后台方案一:注册interceptor,获取语言环境,并使用LocaleContextHolder.setLocale()进行设置
     后台方案二:注册filter,获取语言环境,并使用LocaleContextHolder.setLocale()进行设置
       注意事项:interceptor在filter之后执行,如果在filter中有做预处理或者请求拦截,则需要在filter中进行语言设置,不然走不到interceptor中,也就不生效
    
  5. 在需要返回国际化消息的类中,注入 MessageSource,根据key和并使用LocaleContextHolder.getLocale()调用 getMessage方法

可考虑的优化处理:

    新建常量类,保存所有的messageKey,避免在代码中使用魔法值
    新建MessageSourceUtil,静态注入MessageSource,在静态方法中进行消息获取,在需要使用国际化消息的地方直接调用
    新建ResponseBodyAdvice对返回结果进行处理,不用在所有返回结果的地方进行message的获取

关键代码:

SpringBoot 配置:

spring:
  messages:
    basename: i18n/messages  # 资源存放位置
    encoding: UTF-8
    use-code-as-default-message: true  # 当找不到code对应的消息时,是否使用code作为消息

默认语言设置为简体中文

 @Bean
  public LocaleResolver localeResolver() {
      SessionLocaleResolver localeResolver = new SessionLocaleResolver();
      localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
      return localeResolver;
  }

setLocale方法:

考虑写在filter中,还是写在interceptor中,
此处使用cookies进行语言设置:

 Cookie[] cookies = request.getCookies();
        Cookie langCookie = null;
        Cookie countryCookie = null;
        if (ArrayUtils.isNotEmpty(cookies)) {
            for (Cookie cookie : cookies) {
                if (langCookie != null && countryCookie != null) break;
                if (cookie.getName().equals("lang")) {
                    langCookie = cookie;
                    continue;
                }
                if (cookie.getName().equals("country")) {
                    countryCookie = cookie;
                    continue;
                }
            }
        }
        if (langCookie == null) {
            langCookie = new Cookie("lang", Locale.SIMPLIFIED_CHINESE.getLanguage());
            langCookie.setMaxAge(604800);
            countryCookie = new Cookie("country", Locale.SIMPLIFIED_CHINESE.getCountry());
            countryCookie.setMaxAge(604800);
            response.addCookie(langCookie);
            response.addCookie(countryCookie);
        }
        Locale locale; 
        if (null == countryCookie) {
            locale = new Locale(langCookie.getValue());
        } else {
            locale = new Locale(langCookie.getValue(), countryCookie.getValue());
        }

        LocaleContextHolder.setLocale(locale);
        return true;

MessageSourceUtil

@Component
public class MessageSourceUtil {
    private static MessageSource messageSource;

    @Autowired
    public void setMessageSource(MessageSource messageSource) {
        MessageSourceUtil.messageSource = messageSource;
    }

    public static String getMessage(String code) {
        Locale locale = LocaleContextHolder.getLocale();
        return getMessageByLocale( locale,code);
    }

    public static String getMessageByLocale(Locale locale, String key) {
        return messageSource.getMessage(key, null, locale);
    }

}

ResponseBodyAdvice

@RestControllerAdvice
public class ResponseBodyConfig implements ResponseBodyAdvice<封装的返回类型||Object> {
// 对所有内容进行支持
 @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
    
  /** 真正的处理方法,
     * 如果在filter 中进行直接res.write,不会走到此方法,所以filter中的返回要单独处理
     */
    @Override
    public 封装的返回类型||Object beforeBodyWrite(封装的返回类型||Object body,
                                  MethodParameter returnType,
                                  MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request,
                                  ServerHttpResponse response) {
       // 根据业务代码中返回的内容,从语言包进行获取
        body.setMessgae(MessageSourceUtil.getMessage(body.getMessgae()));
        return body;}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值