目錄
- 1. 建立國際化檔案Resource Bundle
- 2. 國際化配置類InternationalConfig
- 3. application.yml配置檔案中配置國際化檔案路徑
- 4. 國際化處理類MessageSourceHandler
- 5. 國際化使用
- 6. FAQ
- 7. 擴充套件學習
1. 建立國際化檔案Resource Bundle
專案結構圖:
國際化檔案結構圖:
在IntelliJ IDEA中建立國際化檔案:
2. 國際化配置類InternationalConfig
程式碼:
@Configuration
public class InternationalConfig {
@Value(value = "${spring.messages.basename}")
private String basename;
@Bean(name = "messageSource")
public ResourceBundleMessageSource getMessageResource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename(basename);
return messageSource;
}
}
複製程式碼
3. application.yml配置檔案中配置國際化檔案路徑
spring:
profiles:
active: dev
# 配置國際化檔案路徑
messages:
basename: i18n/messages
---
spring:
profiles: dev
---
spring:
profiles: test
---
spring:
profiles: prod
複製程式碼
4. 國際化處理類MessageSourceHandler
程式碼:
@Component
public class MessageSourceHandler {
@Autowired
private HttpServletRequest request;
@Autowired
private MessageSource messageSource;
public String getMessage(String messageKey) {
String message = messageSource.getMessage(messageKey, null, RequestContextUtils.getLocale(request));
return message;
}
}
複製程式碼
注意:
- 如果是根據Request請求的語言來決定國際化:
@Autowired
private HttpServletRequest request;
public String getMessage(String messageKey) {
String message = messageSource.getMessage(messageKey, null, RequestContextUtils.getLocale(request));
return message;
}
複製程式碼
- 如果是根據應用部署的伺服器系統來決定國際化:
public String getMessage(String messageKey) {
String message = messageSource.getMessage(messageKey, null, LocaleContextHolder.getLocale());
return message;
}
複製程式碼
5. 國際化使用
引入MessageSourceHandler類的物件messageSourceHandler,呼叫其messageSourceHandler.getMessage()方法即可。
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
// 引入國際化處理類
@Autowired
private MessageSourceHandler messageSourceHandler;
private String handleException(Exception e, String code) {
return handleException(e, code, null);
}
// 具體異常處理類
private String handleException(Exception e, String code, Object body) {
String msgKey = e.getMessage();
String msg = msgKey;
try {
msg = messageSourceHandler.getMessage(msgKey);
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
if (StringUtils.isEmpty(msg)) {
if (StringUtils.isEmpty(msgKey)) {
msg = messageSourceHandler.getMessage(ErrorTypeEnum.INTERNAL_SERVER_ERROR.getMessage());
} else {
msg = msgKey;
}
}
log.error("Return Error Message : " + msg);
return msg;
}
// 請求錯誤異常處理
@ExceptionHandler(BadRequestException.class)
public String handleBadRequest(BadRequestException e) {
return handleException(e, e.getCode());
}
// 伺服器內部異常處理
@ExceptionHandler(InternalServerException.class)
public String handleInternalServerError(InternalServerException e) {
return handleException(e, e.getCode());
}
// 呼叫其他服務異常處理
@ExceptionHandler(InvokeOtherServerException.class)
public String handleInvokeOtherServerError(InvokeOtherServerException e) {
return handleException(e, e.getCode(), e.getBody());
}
// DAO異常處理
@ExceptionHandler(DaoException.class)
public String handleDaoError(DaoException e) {
return handleException(e, e.getCode());
}
}
複製程式碼
FAQ:
1. 中文國際化出現亂碼或\uXXXX的問題
如圖:
亂碼問題根源:
<1> 建立國際化檔案,IDEA預設工程的初始預設編碼是GBK,如下圖:
<2> 當我新增了一些國際化內容時,此時意識到編碼不是UTF-8,我修改了一下預設的工程編碼和系統properties編碼,改為UTF-8,如下圖所示。
由於我是在GBK編碼下加的中文國際化內容,後又把工程編碼和properties編碼改為了UTF-8,兩邊編碼不一致,導致出現亂碼。
\uXXXX問題根源:
\uXXXX是Unicode的轉義字元,和\n,\r同屬於轉義字元,看一下IntelliJ官網對此說明,如下:
IntelliJ官網的文件地址:www.jetbrains.com/help/idea/2…
## 在properties檔案中格式為\uXXXX的所有轉義字元,在資源編譯器中被顯示為未轉義的Unicode字元
All escaped characters in the *.properties files in the format \uXXXX, are displayed in the resource bundle editor as un-escaped unicode literals.
## 反之亦然,如果在資源編譯器中輸入非ASCII字元,則它將反映在底層的properties檔案中作為相應的格式為\uXXXX的轉義字元
Vice versa, if a non-ASCII character is entered in the resource bundle editor, it is reflected in the underlying *.properties file as a corresponding escaped character in the format \uXXXX.
##下面是舉了個例子
For example, if the *.properties file contains a property value
Was ich nicht wei\u00df, macht mich nicht hei\u00df
then the resource bundle editor will show
Was ich nicht weiß, macht mich nicht heiß
## 資源編譯器本身不做任何轉換。若要在屬性檔案中正確解析轉義序列,請在“設定/首選項”對話方塊的“檔案編碼頁”中選擇“透明本機到ascii轉換”核取方塊。
Resource bundle editor itself does not perform any conversion. To have escape sequences properly resolved in properties files, select the check box Transparent native-to-ascii conversion in the File Encoding page of the Settings/Preferences dialog.
## 可以使用大寫和小寫十六進位制符號(例如'\u00E3'與'\u00e3')對非ascii符號進行編碼。大寫預設使用。要使用小寫,請將bin/idea.properties檔案(安裝IntelliJ的資料夾)中的'idea.native2ascii.lowercase'屬性設定為true。
It is possible to encode non-ascii symbols using both upper- and lower-case hex symbols (e.g. '\u00E3' vs '\u00e3'). Upper case is used by default. To use lower case, set 'idea.native2ascii.lowercase' property in the bin/idea.properties file to true.
Refer to the section Tuning IntelliJ IDEA for details.
複製程式碼
繼續跳轉Tuning IntelliJ IDEA for details,見下截圖:
總結:輸入漢字(非ASCII碼),在IntelliJ資源編譯器中顯示轉義的Unicode碼(\uXXXX(X大寫)),勾上"Transparent native-to-ascii conversion",則在資源編譯器中轉換顯示為漢字,其實際儲存為轉義的Unicode碼。
解決方法:
有關編碼的文章,可參考:www.ruanyifeng.com/blog/2007/1…
2. SpringBoot有沒有自帶的國際化資源配置類?
有,當然有。
SpringBoot提供了自動配置類MessageSourceAutoConfiguration,
@Configuration
@ConditionalOnMissingBean(value = MessageSource.class, search = SearchStrategy.CURRENT)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Conditional(ResourceBundleCondition.class)
@EnableConfigurationProperties
public class MessageSourceAutoConfiguration {
private static final Resource[] NO_RESOURCES = {};
@Bean
@ConfigurationProperties(prefix = "spring.messages")
public MessageSourceProperties messageSourceProperties() {
return new MessageSourceProperties();
}
// 配置了MessageSource的Bean,並裝配了上面MessageSourceProperties的Bean
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
if (StringUtils.hasText(properties.getBasename())) {
messageSource.setBasenames(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(properties.getBasename())));
}
if (properties.getEncoding() != null) {
messageSource.setDefaultEncoding(properties.getEncoding().name());
}
messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
Duration cacheDuration = properties.getCacheDuration();
if (cacheDuration != null) {
messageSource.setCacheMillis(cacheDuration.toMillis());
}
messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
return messageSource;
}
...
}
// 國際化資原始檔配置類Properties
public class MessageSourceProperties {
/**
* Comma-separated list of basenames (essentially a fully-qualified classpath
* location), each following the ResourceBundle convention with relaxed support for
* slash based locations. If it doesn't contain a package qualifier (such as
* "org.mypackage"), it will be resolved from the classpath root.
*/
// 預設國際化資原始檔名為messages,預設放在類路徑下,在application.yml中不需要做任何國際化路徑配置
private String basename = "messages";
/**
* Message bundles encoding.
*/
private Charset encoding = StandardCharsets.UTF_8;
/**
* Loaded resource bundle files cache duration. When not set, bundles are cached
* forever. If a duration suffix is not specified, seconds will be used.
*/
@DurationUnit(ChronoUnit.SECONDS)
private Duration cacheDuration;
/**
* Whether to fall back to the system Locale if no files for a specific Locale have
* been found. if this is turned off, the only fallback will be the default file (e.g.
* "messages.properties" for basename "messages").
*/
private boolean fallbackToSystemLocale = true;
/**
* Whether to always apply the MessageFormat rules, parsing even messages without
* arguments.
*/
private boolean alwaysUseMessageFormat = false;
/**
* Whether to use the message code as the default message instead of throwing a
* "NoSuchMessageException". Recommended during development only.
*/
private boolean useCodeAsDefaultMessage = false;
...
}
複製程式碼
如果建立自定義的國際化資源(Resource Bundle)檔案,例如:i18n/messages,則需要在application.yml中配置該自定義國際化檔案的路徑。
如果在resources資料夾路徑下直接建立messages國際化資原始檔(名字必須為messages),則不需要在applicaiton.yml中配置國際化檔案路徑。
國際化處理類見上面 4. 國際化處理類MessageSourceHandler,國際化使用是一樣的。
擴充套件學習
-
簡書上一篇“SpringBoot - Web開發國際化”的文章:www.jianshu.com/p/01e0c7251…
-
阮老師一篇關於編碼的文章:www.ruanyifeng.com/blog/2007/1…