SpringBoot项目国际化

目录

1. 建立国际化文件Resource Bundle

项目结构图: html

springboot项目工程详细结构

国际化文件结构图: spring

springboot国际化文件

在IntelliJ IDEA中建立国际化文件: springboot

添加en_US的英文国际化文件

添加zh_CN的中文国际化文件

最终国际化添加完成的界面

2. 国际化配置类InternationalConfig

springboot国际化配置类

代码:bash

@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

springboot国际化处理类

代码:服务器

@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;
    }
}
复制代码

注意:app

  • 若是是根据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()方法便可。ide

@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的问题

如图: 学习

中文国际化出现乱码

中文国际化出现\uXXXX

乱码问题根源:ui

<1> 建立国际化文件,IDEA默认工程的初始默认编码是GBK,以下图: this

IDEA默认工程初始编码为GBK

<2> 当我添加了一些国际化内容时,此时意识到编码不是UTF-8,我修改了一下默认的工程编码和系统properties编码,改成UTF-8,以下图所示。

因为我是在GBK编码下加的中文国际化内容,后又把工程编码和properties编码改成了UTF-8,两边编码不一致,致使出现乱码。

修改了工程编码和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,见下截图:

IntelliJ官网截图

总结:输入汉字(非ASCII码),在IntelliJ资源编译器中显示转义的Unicode码(\uXXXX(X大写)),勾上"Transparent native-to-ascii conversion",则在资源编译器中转换显示为汉字,其实际存储为转义的Unicode码。

解决方法:

IntelliJ的编码设置

有关编码的文章,可参考: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中配置国际化文件路径。

自定义与默认的messages国际化文件

国际化处理类见上面 4. 国际化处理类MessageSourceHandler,国际化使用是同样的。

扩展学习

  1. 简书上一篇“SpringBoot - Web开发国际化”的文章:www.jianshu.com/p/01e0c7251…

  2. 阮老师一篇关于编码的文章:www.ruanyifeng.com/blog/2007/1…

回到目录

相关文章
相关标签/搜索