国际化是什么?
国际化是开发支持多语言和数据格式的技术。其实就是根据外部特征动态的将本地化资源响应给用户。
本地化资源配置文件
在SpringMVC
中实现国际化,是将每一个地区的语言保存在配置文件中,配置的内容是key/value
对,key
是字符串,value
可以是字符串,也可以是其他任意类型的对象。
一个配置文件表示一种语言,如果要同时支持中文和英文,那么就需要提供两个属性文件,并且中英文内容相同的value
,要对应相同的key
。
配置文件的命名是:basename_languageCode_countryCode.properties
,例如默认文件messages.properties
,中文的messages_zh_CN.properties
。当根据languageCode
获取不到配置文件时,就会使用默认的配置文件
汉语的配置文件,要将汉字转换成Unicode
,创建文件分两步:
- 随意创建文本文件
- 将文本文件的内容转换成
unicode
表示
在idea
中创建如下,注意,messages_en_US.properties
中的US
实际上可以去掉,通常情况下是去掉的;Resource Bundle 'messages'
不是文件夹,当生成配置文件后就出现了这个,实际表示的是messages
是basename
。
如果idea
中的中文已经是unicode
,但是想看中文
SpringMVC
配置
-
注解驱动
<mvc:annotation-driven validator="validator" />
-
加载国际化资源文件
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <!-- 指定配置文件路径及basename --> <property name="basename" value="classpath:config/i18n/messages" /> <property name="fileEncodings" value="utf-8" /> <!-- 缓存120s,可以动态加载messages.properties中的数据(修改文件数据,不需要重启) --> <property name="cacheSeconds" value="120" /> </bean>
-
加载校验器,需要注入到注解驱动中
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator" /> <property name="validationMessageSource" ref="messageSource" /> </bean>
-
加载国际化语言区域解析器:浏览器语言解析器
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver" />
-
语言区域更改拦截器,测试验证时,发现不配置也可以
<mvc:interceptors> <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"></bean> </mvc:interceptors>
测试代码
// 校验工具类
public class ValidatorUtils {
private static final Logger logger = LoggerFactory.getLogger(ValidatorUtils.class);
public static void beanValid(BindingResult bindingResult, LocaleService localeService) {
if (bindingResult.hasErrors()) {
StringBuilder joinMessage = new StringBuilder();
List<ObjectError> allErrors = bindingResult.getAllErrors();
for (ObjectError objectError : allErrors) {
joinMessage.append(",").append(localeService.getMessage(objectError.getDefaultMessage()));
}
if (joinMessage.length() > 0) {
String message = joinMessage.deleteCharAt(0).toString();
logger.info("i18n message:" + message);
throw new RequestParamException(message);
}
}
}
}
// 从messages中替换显示内容
@Component
public class LocaleService {
@Autowired
private MessageSource messageSource;
public String getMessage(String code) {
Locale locale = LocaleContextHolder.getLocale();
String message = messageSource.getMessage(code, new Object[]{}, locale);
if (StringUtils.isNotBlank(message)) {
return message;
}
return code;
}
}
// 异常
@RestControllerAdvice
public class ExceptionHandle {
@ExceptionHandler(RequestParamException.class)
public Object handleRequestParamException(RequestParamException e) {
Map result = new HashMap();
result.put("code", 200);
result.put("message", e.getMsg());
return result;
}
}
public class RequestParamException extends RuntimeException{
public RequestParamException(String msg) {
this.msg = msg;
}
private String msg;
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
// 测试接口及实体
@RestController
@RequestMapping("/bindingResult")
public class BindingResultController {
@Resource
private LocaleService localeService;
@RequestMapping("/test")
public Object test(@Valid Person person, BindingResult result) {
ValidatorUtils.beanValid(result, localeService);
return new Object();
}
}
// 省略了set和get方法
public class Person implements Serializable {
@NotNull(message = "person.name_is_null")
private String name;
@NotNull(message = "person.age_is_null")
@Range(min = 1, max = 200, message = "person.age_is_illegal")
private Integer age;
}