基于springboot i18n国际化后台多种语言设置的方式
作者:从心归零 发布时间:2022-03-28 16:02:56
之前有做过手机端后台的国际化,因为手机统一传递了language参数
所以只要设置LocaleChangeInterceptor就行了
/**
* 配置国际化语言
*/
@Configuration
public class LocaleConfig extends WebMvcConfigurerAdapter{
/**
* 默认解析器 其中locale表示默认语言
*/
@Bean
public LocaleResolver localeResolver() {
SessionLocaleResolver localeResolver = new SessionLocaleResolver();
localeResolver.setDefaultLocale(Locale.CHINA);
return localeResolver;
}
//springboot1.5
@Override
public void addInterceptors(InterceptorRegistry registry) {
LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
localeInterceptor.setParamName("language");
registry.addInterceptor(localeInterceptor);
}
}
对于某些特殊的后台运行代码,比如定时器,我则使用getByLanguage方法
/**
* 国际化工具类
*/
@Component
public class MessageUtils{
private static MessageSource messageSource;
static SysErrorLogDao sysErrorLogDao;
@Resource
public void setSysErrorLogDao(SysErrorLogDao sysErrorLogDao) {
MessageUtils.sysErrorLogDao = sysErrorLogDao;
}
private static Logger logger = LoggerFactory.getLogger(MessageUtils.class);
public MessageUtils(MessageSource messageSource) {
MessageUtils.messageSource = messageSource;
}
/**
* 获取单个国际化翻译值
* @param msgKey
* @param defaultMsg
* @return
*/
public static String get(String msgKey, String defaultMsg) {
try {
return messageSource.getMessage(msgKey, null, LocaleContextHolder.getLocale());
} catch (Exception e) {
logger.error(e.getMessage(), e);
String message = StringUtils.getExceptionStackTraceMessage(e);
if(message != null && message.length() > 1000) {
message = message.substring(0, 999);
}
SysErrorLogModel errorLog = new SysErrorLogModel();
errorLog.setContent(msgKey);
errorLog.setType("messageUtils");
errorLog.setCreateDate(new Date());
errorLog.setClassName(MessageUtils.class.getName());
errorLog.setMessage(message);
sysErrorLogDao.save(errorLog);
return defaultMsg;
}
}
/**
* 获取多个参数取代的国际化翻译值
* @param msgKey
* @param defaultMsg
* @param arg
* @return
*/
public static String get(String msgKey, String defaultMsg, Object... arg) {
try {
msgKey = messageSource.getMessage(msgKey, arg, LocaleContextHolder.getLocale());
return msgKey;
} catch (Exception e) {
logger.error(e.getMessage(), e);
String message = StringUtils.getExceptionStackTraceMessage(e);
if(message != null && message.length() > 1000) {
message = message.substring(0, 999);
}
SysErrorLogModel errorLog = new SysErrorLogModel();
errorLog.setContent(msgKey);
errorLog.setType("messageUtils");
errorLog.setCreateDate(new Date());
errorLog.setClassName(MessageUtils.class.getName());
errorLog.setMessage(message);
sysErrorLogDao.save(errorLog);
return MessageFormat.format(defaultMsg, arg);
}
}
/**
* 指定语言获得单个国际化翻译值
* @param msgKey
* @param defaultMsg
* @param language
* @return
*/
public static String getByLanguage(String msgKey, String defaultMsg, String language) {
try {
Locale locale = new Locale(language);
msgKey = messageSource.getMessage(msgKey, null, locale);
return msgKey;
} catch (Exception e) {
logger.error(e.getMessage(), e);
String message = StringUtils.getExceptionStackTraceMessage(e);
if(message != null && message.length() > 1000) {
message = message.substring(0, 999);
}
SysErrorLogModel errorLog = new SysErrorLogModel();
errorLog.setContent(msgKey);
errorLog.setType("messageUtils");
errorLog.setCreateDate(new Date());
errorLog.setClassName(MessageUtils.class.getName());
errorLog.setMessage(message);
sysErrorLogDao.save(errorLog);
return defaultMsg;
}
}
/**
* 指定语言获取多参数取代的国际化翻译值
* @param msgKey
* @param defaultMsg
* @param language
* @param arg
* @return
*/
public static String getByLanguage(String msgKey, String defaultMsg, String language, Object... arg) {
try {
Locale locale = new Locale(language);
msgKey = messageSource.getMessage(msgKey, arg, locale);
return msgKey;
} catch (Exception e) {
logger.error(e.getMessage(), e);
String message = StringUtils.getExceptionStackTraceMessage(e);
if(message != null && message.length() > 1000) {
message = message.substring(0, 999);
}
SysErrorLogModel errorLog = new SysErrorLogModel();
errorLog.setContent(msgKey);
errorLog.setType("messageUtils");
errorLog.setCreateDate(new Date());
errorLog.setClassName(MessageUtils.class.getName());
errorLog.setMessage(message);
sysErrorLogDao.save(errorLog);
return MessageFormat.format(defaultMsg, arg);
}
}
}
但是后面又要做网页的国际化,因为网页没有传递统一的语言参数,如果要一一添加的话太过麻烦,于是就要用到cookie来保存传递语言
这个时候就要实现自己的解析器了
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
Locale locale = Locale.getDefault();
{
//通过参数解析locale,language参数优先
String temp = httpServletRequest.getParameter("language");
if (!StringUtils.isEmpty(temp)) {
locale = new Locale(temp);
return locale;
}
}
//得到cookie,解析locale
Cookie[] cookies = httpServletRequest.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("userLanguage")) {
String temp = cookie.getValue();
if (!StringUtils.isEmpty(temp)) {
locale = new Locale(temp);
}
continue;
}
}
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
@Configuration
public class LocaleConfig extends WebMvcConfigurerAdapter{
@Bean
public LocaleResolver localeResolver() {
MyLocaleResolver localeResolver = new MyLocaleResolver();
return localeResolver;
}
}
这样就实现了使用cookie来设置语言
不过最后还是有所遗漏,因为我们的分布式项目中用到了很多http的内部调用,用不上cookie,也没有language参数。
但是大部分的内部调用都有传递公司id,可以通过公司获得公司对应的语言。
可以在 * 里面直接加入对companyId的解析但是我考虑有没有通用的实现方法,就是在任何地方,甚至的运行到一半中途设置语言的办法。
初步想法是拿到线程中的Locale进行设置
然后我看了下源码LocaleContextHolder.getLocale()
发现调用的是一个LocaleContext类的方法。
然后查询哪些地方调用了LocaleResolver.resolveLocale
发现第一个方法里面返回了一个匿名函数LocaleContext,其getLocale就是直接调用localeResolver.resolveLocale方法。
于是我合理的猜想框架里不是通过 * 设置一个locale,而是每次调用LocaleContextHolder.getLocale()都会执行localeResolver.resolveLocale(request)方法,所以我们只要设置request属性就行了
public class MyLocaleResolver implements LocaleResolver {
@Override
public Locale resolveLocale(HttpServletRequest httpServletRequest) {
//得到cookie,解析locale
Locale locale = Locale.getDefault();
{
//通过参数解析locale
String temp = httpServletRequest.getParameter("language");
if (!StringUtils.isEmpty(temp)) {
locale = new Locale(temp);
return locale;
}
}
{
String temp = (String) httpServletRequest.getAttribute("language");
if (!StringUtils.isEmpty(temp)) {
locale = new Locale(temp);
return locale;
}
}
Cookie[] cookies = httpServletRequest.getCookies();
if(cookies != null) {
for (Cookie cookie : cookies) {
if (cookie.getName().equals("userLanguage")) {
String temp = cookie.getValue();
if (!StringUtils.isEmpty(temp)) {
locale = new Locale(temp);
}
continue;
}
}
}
return locale;
}
@Override
public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {
}
}
@RequestMapping("/test")
public String test(HttpServletRequest request) {
String result = "";
request.setAttribute("language", "ch");
result += MessageUtils.get("test", "测试");
request.setAttribute("language", "en");
result += MessageUtils.get("test", "测试");
return result;
}
messages_ch.properties
test=测试
messages_en.properties
test=test
这样我们就实现了在任何地点,甚至中途变换语言了
发现LocaleContextHolder.getLocale()在实体类中也可以调用。因此可以后台保存json格式,在get方法中根据语言返回相应的值。
我本来想直接改造原来的字段,但是发现缓存会直接读取get中的值,下次读取就不是json了,所以只好麻烦点增加一个字段了
public String getFullNameByLanguage() {
String language = LocaleContextHolder.getLocale().getLanguage();
Map<String, String> map;
try {
map = JsonUtil.string2Obj(fullName);
return map.get(language);
} catch (IOException e) {
return fullName;
}
}
当使用@Async异步方法时,LocaleContext就是空的。这时候需要强制设置语言LocaleContextHolder.setLocale(Locale locale),当然一般的方法也可以用这个来设置语言,不过这样的话就不会再调用localeResolver.resolveLocale(request)方法了
来源:https://blog.csdn.net/qq_36804701/article/details/108282775


猜你喜欢
- import java.io.FileNotFoundException;import java.io.FileOutputStream;i
- 前面介绍了Spring Boot 整合mybatis 使用注解的方式实现数据库操作,介绍了如何自动生成注解版的mapper 和pojo类。
- 本文研究的主要是java中的null“类型”的相关实例,具体介绍如下。先给出一道简单的null相关的题目,引发我们对null的探讨,后面会根
- 概述在Spring中,我们可以通过 @Autowired注解的方式为一个方法中注入参数,那么这种方法背后到底发生了什么呢,这篇文章将讲述如何
- 本文实例讲述了C#基于简单工厂模式实现的计算器功能。分享给大家供大家参考,具体如下:子类拥有父类除私有之外的所有属性字段和方法using S
- 目录什么是异常?编译时还是运行时?“受检异常”究竟可不可取?我的观点什么是异常?要了解受检异常,首先要了解什么是异常。在Java中,异常是一
- 一、快速生成main输入psvm二、快速生成System.out.print使用sout三、文件保存IDEA是自动保存的,不需要我们去Ctr
- 本文实例讲述了java实现MD5加密的方法。分享给大家供大家参考,具体如下:private String getMD5Str(String
- mybatis-plus作为mybatis的增强工具,简化了开发中的数据库操作。一旦遇到left join或right join的左右连接,
- 本文实例为大家分享了Android自定义View实现遥控器按钮的具体代码,供大家参考,具体内容如下效果图:原理:onSizeChanged拿
- 在日常的开发中、我们都知道,Java的内存清理是通过垃圾回收器进行的,那么其是如何将没用的对象被被清理掉的呢?Java 语言的内存自动回收称
- 接上一篇文章:Android实现图片区域裁剪功能上一篇文章提及了通过调用系统相册或拍照来实现图片的缩放\裁剪。不过这对于笔者项目的要求同样不
- 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很
- 一、修改ReadOnly属性1、设置整个DataGridView只读:DataGridView.ReadOnly=true;此时用户的新增行
- 微服务的特点决定了功能模块的部署是分布式的,大部分功能模块都是运行在不同的机器上,彼此通过服务调用进行交互,前后台的业务流会经过很多个微服务
- 简介今天给大家带来的是使用ShareSDK实现应用分享的功能。下面我们先看下效果图。效果图步骤 1. 获取AppKey访问mob官网http
- 原项目基于mybatis开发,新功能基于mybatis-plus开发,同时依赖如下两个jar包mybatis-spring-boot-sta
- 注:如果没有 root 权限也是可以试试,一般情况下,都需要 root 权限,才能连接成功。1.需要确保你的开发 PC 和 Android
- 一、介绍Android的大部分自定义软键盘主要是通过android自带控件KeyboardView实现的。那么,有没有其他简单易上手的方法来
- 本文实例讲述了Android开发中4个常用的工具类。分享给大家供大家参考,具体如下:1、土司工具类(Toast管理)/** * Toast统