国际化方案
前后端分离的国际化方案,如果每个接口都增加参数,代码量和测试量会很大,最好把语言变量加到请求头并通过拦截器解析。
具体过程如下:
- 客户端增加请求头 Accept-Language;
- 服务端增加拦截器,解析请求头Accept-Language中的语言值,并通过LanguageUtil设置到当前线程的语言环境中;
- 服务端需要返回多语言结果的地方,通过LanguageUtil获取当前请求客户端的语言。
除了请求头,也可以通过cookie实现,但是有些客户端不支持cookie,而且cookie存在被篡改的危险,因此更建议使用标准的请求头。
实现代码
通过 SpringMVC 的RequestContextUtils
和java.util.Local
,可以很轻松地解析请求头中的语言标识。
SpringMVC提供了多种国际化的实现方式。
下面一步步讲解代码实现。
pom.xml
使用SpringBoot搭建项目,并且引入Lombok用于简化JavaBean。
复制代码 4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.3.RELEASE net.ijiangtao.tech.framework.spring.ispringboot.demo demo-i18n 0.0.1-SNAPSHOT demo-i18n Demo Spring Boot project for i18n 1.8 org.springframework.boot spring-boot-starter-web org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.boot spring-boot-maven-plugin
application.properties
配置当前服务的端口。
server.port=8303复制代码
LanguageUtil.java
使用ThreadLocal保存当前线程的环境语言。
/** * @author ijiangtao.net */public class LanguageUtil { public static final String ZH_CN = "zh_CN"; public static final String EN_US = "en_US"; public static final String DEFAULT_LANGUAGE = ZH_CN; private String lang; private static final ThreadLocalcontext = new ThreadLocal () { @Override protected LanguageUtil initialValue() { return new LanguageUtil(); } }; public LanguageUtil() { lang = DEFAULT_LANGUAGE; } public static LanguageUtil getCurrentContext() { return (LanguageUtil) context.get(); } public static String getCurrentLang() { return getCurrentContext().lang; } public static void setCurrentLang(String lang) { getCurrentContext().lang = lang; } public static void remove() { context.remove(); }}复制代码
LanguageInterceptor.java
实现HandlerInterceptor
接口,拦截并解析请求头中的环境语言,并设置到LanguageUtil中。
import lombok.extern.slf4j.Slf4j;import net.ijiangtao.tech.framework.spring.ispringboot.demo.i18n.util.LanguageUtil;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.LocaleResolver;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.support.RequestContextUtils;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.util.Locale;@Slf4jpublic class LanguageInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("preHandle:请求前调用"); //请求头 当前语言 // Accept-Language: zh-CN // Accept-Language: en-US LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request); Locale local= localeResolver.resolveLocale(request); log.info("local={} , localDisplayName={}",local.toString(),local.getDisplayName()); LanguageUtil.setCurrentLang(local.toString()); log.info("LanguageUtil.getCurrentLang() = {}",LanguageUtil.getCurrentLang()); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { log.info("postHandle:请求后调用"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { log.info("afterCompletion:请求调用完成后回调方法,即在视图渲染完成后回调"); }}复制代码
InterceptorConfig.java
配置拦截器并使之生效。
import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configurationpublic class InterceptorConfig extends WebMvcConfigurationSupport { @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(new LanguageInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/noi18n") .excludePathPatterns("/onelang"); }}复制代码
LanguageController.java
从LanguageController中获取当前线程设置的环境语言,测试效果。
import net.ijiangtao.tech.framework.spring.ispringboot.demo.i18n.util.LanguageUtil;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.ResponseBody;/** * * @author ijiangtao.net */@Controllerpublic class LanguageController { @GetMapping("/lang/current") @ResponseBody public String currentLanguage(){ return LanguageUtil.getCurrentLang(); }}复制代码
测试
使用IDEA的Rest Client发起请求
测试请求的response
en_US复制代码
总结
本教程介绍了如何通过客户端的请求头设置服务端的语言环境,从而实现服务端响应内容的国际化。
希望对你有所帮助。