基於請求URL的國際化實現方式
基於請求URL的國際化實現方式
原理:使用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)則必需配置 --> <beanid="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 I18nSessionServicei18nSessionService; 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將粒度劃分的更細,處理也更靈活