spring 项目国际化,前后端分离
一般一个项目稍微有可能的话国际化是基本需求,提前做好。
国际化嘛,首先是时间,其次就是语言了。我这边就不谈时间了,主要针对语言。
注:防止乱码国际化(数据库和服务器)肯定统一UTF-8编码。
项目后端提示国际化
1. LocalResolwer
利用spring对国际化的支持,使用内置的语言处理器。
重写LocalResolwer,这个类其实已经得到了官方实现,但是我的项目是基于jwt的,所以决定自定义比较适合。
然后将自定义的处理器添加到WebMVCConfig中。
注意:通过获取浏览器请求中自带的header中的Accept-Language参数,也可以通过前后端约定自己设置的来。
2.国际化资源配置
IDEA环境下,在resources下新建Resource Bound文件,加上英文key和value。
在yml配置文件中,加上以下配置,注意空格对齐问题。
spring
#国际化
messages:
basename: i18n/message
encoding: UTF-8
# 失效时间,-1永不
cache-duration: -1
2.MessageSource
通过上面的配置,我们就可以拿到MessageSource,在代码中可以通过@Autowired来注入使用。
3.统一定义返回类
像我的项目,所以的返回和异常都是从Result 继承下去的,所以会形成一个很好的规范,同时在所有返回中只能存在资源文件中的key,在后面做替换。有助于下一步骤。
4.自定义过滤器
通过自定义过滤器I18NFilter,该类基础自javax.servlet.Filter;
在I18NFilter中,对所以的返回进行过滤,将所有的key替换为对应语言的国际化资源。
项目中的枚举类型或者常量国际化
1、对枚举类型的GET方法进行改造。
2、资源文件中将枚举值进行配置。
public enum EnumSuccessOrError {
SUCCESS(0, “SUCCESS”),
ERROR(1, “ERROR”);
/**
* 返回状态码
*/
private int statusCode;
/**
* 返回状态信息
*/
private String statusMsg;
EnumSuccessOrError(int statusCode, String statusMsg) {
this.statusCode = statusCode;
this.statusMsg = statusMsg;
}
private MessageSource messageSource;
public EnumSuccessOrError setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
return this;
}
//通过静态内部类的方式注入bean,并赋值到枚举中
@Component
public static class ReportTypeServiceInjector {
@Autowired
private MessageSource messageSource;
@PostConstruct
public void postConstruct() {
for (EnumSuccessOrError rt : EnumSet.allOf(EnumSuccessOrError.class))
rt.setMessageSource(messageSource);
}
}
/**
* @return the statusCode
*/
public int getStatusCode() {
return statusCode;
}
/**
* @return the statusMsg,根据语言环境返回国际化字符串
*/
public String getStatusMsg() {
return messageSource.getMessage(statusMsg,null,statusMsg, LocaleContextHolder.getLocale());
}
数据库部分
对于数据库比如字典表这类表,只能做特殊处理,增加language字段,通过请求中的header语言进行特殊查询。
也有看到用资源表,进行整个翻译的这种说法,但是感觉明显就很奇怪,比较这种表的情况属于特例,其他的表一般不会存在这个问题,都是用户自己存自己看。
还有那种实在是需要多个语言,而且业务需要的,比如存文章,就是非要多个语言,这种有看到多表或者多库做处理的,具体也没了解。基本上这种肯定就分布式,不通地区访问不同地区的服务器,NGINX就处理了,反而不需要这么麻烦了。
代码地址:github,过两天放上去
/**
*国际化工具类
*@author Angel–守护天使
*@version v.0.1
*@date 2016年8月5日下午2:44:03
*/
@Component
publicclassLocaleMessageSourceService {
@Resource
private MessageSourcemessageSource;
/**
*@param code:对应messages配置的key.
*@return
*/
public StringgetMessage(Stringcode){
returnthis.getMessage(code,new Object[]{});
}
public StringgetMessage(Stringcode,StringdefaultMessage){
returnthis.getMessage(code,null,defaultMessage);
}
public StringgetMessage(Stringcode,StringdefaultMessage,Localelocale){
returnthis.getMessage(code,null,defaultMessage,locale);
}
public StringgetMessage(Stringcode,Localelocale){
returnthis.getMessage(code,null,"",locale);
}
/**
*
*@param code:对应messages配置的key.
*@param args :数组参数.
*@return
*/
public StringgetMessage(Stringcode,Object[]args){
returnthis.getMessage(code,args,"");
}
public StringgetMessage(Stringcode,Object[]args,Localelocale){
returnthis.getMessage(code,args,"",locale);
}
/**
*
*@param code:对应messages配置的key.
*@param args :数组参数.
*@param defaultMessage :没有设置key的时候的默认值.
*@return
*/
public StringgetMessage(Stringcode,Object[]args,StringdefaultMessage){
//这里使用比较方便的方法,不依赖request.
Locale locale =LocaleContextHolder.getLocale();
returnthis.getMessage(code,args,defaultMessage,locale);
}
/**
*指定语言.
*@param code
*@param args
*@param defaultMessage
*@param locale
*@return
*/
public StringgetMessage(Stringcode,Object[]args,StringdefaultMessage,Localelocale){
returnmessageSource.getMessage(code,args,defaultMessage,locale);
}