國際化是什麼?
國際化是開發支持多語言和數據格式的技術。其實就是根據外部特徵動態的將本地化資源響應給用戶。
本地化資源配置文件
在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;
}