原理: 使用 spring 的 request bean 保存相应的国际化组件, 这样保证同一个请求的国际化相同, 也是在微服务处理国际化的一种方式. 需要针对每个请求做不同的国际化
实现所以需要, 相应的拦截器去处理对应请求域中的国际化组件
配置文件:
spring 容器配置 applicationContext.xml, 中添加取得信息的 messageSource, 放在 spring 容器而非 springmvc 容器加载是因为代码中有 Service 的注解依赖于他
- <!-- 国际换的 service 依赖于他, 所以从 mvc 提到前面 -->
- <bean id="messageSource"
- class="org.springframework.context.support.ResourceBundleMessageSource">
- <!-- 国际化信息所在的文件名 -->
- <property name="basename" value="messages/messages" />
- <property name="defaultEncoding" value="UTF-8"/>
- <!-- 如果在国际化资源文件中找不到对应代码的信息, 就用这个代码作为名称 -->
- <property name="useCodeAsDefaultMessage" value="true" />
- </bean>
springmvc 容器配置拦截器, 注意拦截器的顺序, 国际化的拦截器在处理请求的拦截器前面
- <mvc:interceptors>
- <mvc:interceptor>
- <mvc:mapping path="/**"/>
- <!-- 国际化操作拦截器 如果采用基于 (请求 / Session/Cookie) 则必需配置 -->
- <bean id="localeChangeInterceptor"
- class="org.springframework.web.servlet.I18N.LocaleChangeInterceptor">
- <property name="paramName" value="locale"/>
- </bean>
- </mvc:interceptor>
- <mvc:interceptor>
- <!-- 需拦截的地址 -->
- <!-- 级目录 -->
- <mvc:mapping path="/*" />
- <mvc:mapping path="/*/*" />
- <!-- 需排除拦截的地址 -->
- <mvc:exclude-mapping path="/*.html"/>
- <bean class="cn.xx.xx.xx.interceptor.ControllerInterceptor" />
- </mvc:interceptor>
- </mvc:interceptors>
- <!-- 基于 url 的国际化 id 必须为 localeResolver 否则国际化组件无法识别, UrlAcceptHeaderLocaleResolver 为自定义实现部分 -->
- <bean id="localeResolver" class="cn.abcsys.devops.application.service.UrlAcceptHeaderLocaleResolver"/>
UrlAcceptHeaderLocaleResolver 作为 localeResolver 国际 urlLocal
- /**
- * Copyright: Copyright (c) 2018 LanRu-Caifu
- * @author xzg
- * 2018 年 2 月 6 日
- * @ClassName: UrlAcceptHeaderLocaleResolver.java
- * @Description: 国际化拦截请求后对请求更改 Local
- * @version: v1.0.0
- */
- public class UrlAcceptHeaderLocaleResolver extends AcceptHeaderLocaleResolver {
- private Locale urlLocal;
- public Locale resolveLocale(HttpServletRequest request) {
- return urlLocal != null?urlLocal:request.getLocale();
- }
- @Override
- public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
- urlLocal = locale;
- }
- }
spring 中的 request bean 依赖于接口实现, 下面是其接口和对应的实现类
- public interface I18nSessionService {
- public void setRc(RequestContext rc);
- public void setRcByRequest(HttpServletRequest request);
- public String getMessage(String key);
- public String getMessage(String key,Object info);
- public String getMessage(String key,Object...objects);
- }
下面注解主要为设置作用域为 request, 注入 messageSource 组件, 并提供 RequestContext 用于切换语言配置国际化
- @Component
- @RequestScope(proxyMode = ScopedProxyMode.INTERFACES)
- public class I18nSessionServiceImpl implements I18nSessionService {
- @Autowired
- @Qualifier("messageSource")
- private MessageSource resources;
- // 前端设置切换语言是设置
- private RequestContext rc ;
- public RequestContext getRc() {
- return rc;
- }
- @Override
- public void setRcByRequest(HttpServletRequest request) {
- // TODO Auto-generated method stub
- this.rc = new RequestContext(request);
- }
- @Override
- public void setRc(RequestContext rc) {
- this.rc = rc;
- }
- @Override
- public String getMessage(String key) {
- // TODO Auto-generated method stub
- if(null != getRc()){
- return getRc().getMessage(key);
- }
- return resources.getMessage(key, null, null);
- }
- @Override
- public String getMessage(String key, Object info) {
- // TODO Auto-generated method stub
- if(null != getRc()){
- return getRc().getMessage(key, new Object[]{info});
- }
- return resources.getMessage(key, new Object[]{info}, null);
- }
- @Override
- public String getMessage(String key, Object... objects) {
- if(null != getRc()){
- return getRc().getMessage(key, objects);
- }
- return resources.getMessage(key, objects, null);
- }
- }
自定义的拦截器中处理, 国际化组件的请求 bean
- @Component
- public class ControllerInterceptor implements HandlerInterceptor {
- /**
- * 在 Controller 方法前进行拦截
- */
- @Resource
- private I18nSessionService i18nSessionService;
- private static Logger log = Logger.getLogger("ControllerInterceptor");
- public boolean preHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler) throws Exception {
- log.info("RequestURI :"+request.getRequestURI());
- // 解决跨域
- response.setHeader("Access-Control-Allow-Origin", "*");
- response.setHeader("Access-Control-Allow-Methods","POST");
- response.setHeader("Access-Control-Allow-Headers","x-requested-with,content-type");
- // 拦截器中对所有的请求处理, 保存到 request bean 中
- i18nSessionService.setRcByRequest(request);
- return true;
- }
- public void postHandle(HttpServletRequest request,
- HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
- }
- /**
- * 在 Controller 方法后进行拦截
- */
- public void afterCompletion(HttpServletRequest request,
- HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- }
- }
使用方式
- // 发送请求 http://localhost:8080/testI18n.do?locale=en_US 或者 http://localhost:8080/testI18n.do?locale=zh_CN
- @Resource
- private I18nSessionService is;
- @RequestMapping(value = "/testI18n.do", method = { RequestMethod.POST,RequestMethod.GET})
- public @ResponseBody
- Result testI18n(){
- return new Result(true, is.getMessage("argument.required"), "");
- }
总结: 以上就是基本实现过程. 在微服务中由于服务发现提供的服务模块会自适应调整所以不适合使用 session 的方式处理国际化. 这里使用 request 和 url 将粒度划分的更细, 处理也更灵活
来源: http://www.jianshu.com/p/987a6b1fc187