1.在resource文件夹下添加i18n 夹及相关国际化配置properties文件
例如:message_zh_CN.properties 中文国际化文件里内容如下:
以实际的responseCode 获取对应的msg 翻译值。
0=成功
9999=系统异常
4=结果为空
message.properties是必须的,内容可以为空,但是必须有这个文件
2.项目配置文件里添加国际化配置,注:springboot项目里默认有国际化相关组件
spring:
messages:
basename: i18n/message #相对路径 开头不要添加斜杠
encoding: UTF-8
3.代码连接国际化文件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import java.util.Locale;
@Component
public class LocaleMessage {
@Autowired
private MessageSource messageSource;
public String getMessage(String code){
return this.getMessage(code,new Object[]{});
}
public String getMessage(String code,String defaultMessage){
return this.getMessage(code,null,defaultMessage);
}
public String getMessage(String code,String defaultMessage,Locale locale){ return this.getMessage(code,null,defaultMessage,locale); }
public String getMessage(String code,Locale locale){
return this.getMessage(code,null,"",locale);
}
public String getMessage(String code,Object[] args){ return this.getMessage(code,args,""); }
public String getMessage(String code,Object[] args,Locale locale){
return this.getMessage(code,args,"",locale);
}
public String getMessage(String code,Object[] args,String defaultMessage){ return this.getMessage(code,args, defaultMessage,LocaleContextHolder.getLocale()); }
public String getMessage(String code,Object[]args,String defaultMessage,Locale locale){
return messageSource.getMessage(code,args, defaultMessage,locale); }
}
I18nUtils
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class I18nUtils {
@Autowired
private LocaleMessage localeMessage;
/**
* 获取key
*
* @param key
* @return
*/
public String getKey(String key) {
String name = localeMessage.getMessage(key);
return name;
}
/**
* 获取指定哪个配置文件下的key
*
* @param key
* @param local
* @return
*/
public String getKey(String key, Locale local) {
String name = localeMessage.getMessage(key, local);
return name;
}
}
4.切面中加入国际化处理
import com.midea.cloud.user.common.Response;
import com.midea.cloud.user.i18n.I18nUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Locale;
/**
* weblog切面
*
* @author huangchong7
* @date 2021/3/30 17:59
*/
@Aspect
@Component
public class WebI18nAspectConfig {
public static final Logger log = LoggerFactory.getLogger(WebLogAspectConfig.class);
@Autowired
I18nUtils i18nUtils;
public WebI18nAspectConfig () {
}
/**
* 定义请求日志切入点,其切入点表达式有多种匹配方式,这里是指定路径
*/
@Pointcut("execution(public * com.midea.cloud.user.controller.*.*(..))")
public void i18nPointcut() {
}
/**
* 前置通知:
* 1. 在执行目标方法之前执行,比如请求接口之前的登录验证;
* 2. 在前置通知中设置请求日志信息,如开始时间,请求参数,注解内容等
*
* @param joinPoint
* @throws Throwable
*/
@Before("i18nPointcut()")
public void doBefore(JoinPoint joinPoint) {
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//打印请求的内容
log.info("请求Url : {}", request.getRequestURL().toString());
log.info("请求方式 : {}", request.getMethod());
log.info("请求ip : {}", request.getRemoteAddr());
log.info("请求方法 : {}", joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
log.info("请求参数 : {}", Arrays.toString(joinPoint.getArgs()));
}
/**
* 返回通知:
* 1. 在目标方法正常结束之后执行
* 2. 在返回通知中补充请求日志信息,如返回时间,方法耗时,返回值,并且保存日志信息
* 3. 国际化
*
* @param ret
* @throws Throwable
*/
@AfterReturning(returning = "ret", pointcut = "i18nPointcut()")
public void doAfterReturning(Object ret) throws Throwable {
Object resultObject = ret;
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//从获取RequestAttributes中获取HttpServletRequest的信息
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
//在header里面传入需要使用的语言flag
String langFlag = request.getHeader("lang");
//在参数里传入需要的语言flag
if (StringUtils.isEmpty(langFlag))
langFlag = request.getParameter("lang");
if (null != langFlag) {
Response r = (Response) ret;
String code = String.valueOf(r.getCode());
String msg = r.getMsg().trim();
if (StringUtils.isNotEmpty(msg)) {
if ("CN".equals(langFlag)) {
Locale locale = Locale.CHINA;
msg = i18nUtils.getKey(code, locale);
} else if ("EN".equals(langFlag)) {
Locale locale = Locale.US;
msg = i18nUtils.getKey(code, locale);
} else {
msg = i18nUtils.getKey(code);
}
}
r.setMsg(msg);
}
} catch (Exception e) {
e.printStackTrace();
//返回原值
ret = resultObject;
}
// 处理完请求,返回内容
log.info("请求返回 : {}", ret);
}
/**
* 异常通知:
* 1. 在目标方法非正常结束,发生异常或者抛出异常时执行
* 1. 在异常通知中设置异常信息,并将其保存
*
* @param throwable
*/
@AfterThrowing(value = "i18nPointcut()", throwing = "throwable")
public void doAfterThrowing(Throwable throwable) {
// 保存异常日志记录
log.error("发生异常时间:{}", LocalDateTime.now());
log.error("抛出异常:{}", throwable.getMessage());
}
}
5.相关测试
响应码
package com.midea.cloud.user.enums;
public enum ResponseCode {
//================== 通用系统错误码 ==================
ERROR(9999, "system error"),
SUCCESS(0, "success"),
EMPTY(4, "result is empty");
private int code;
private String msg;
ResponseCode(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getStrCode() {
return String.valueOf(code);
}
public String getMsg() {
return msg;
}
/**
* 通过错误码获取code对象
*
* @param errorCode
* @return
*/
public static ResponseCode getCode(int errorCode) {
for (ResponseCode c : ResponseCode.values()) {
if (errorCode == c.getCode()) {
return c;
}
}
return ERROR;
}
}
响应类
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* 响应类
*/
@Accessors(chain = true) //setter类型的链式编程
@Data
@ToString
public class Response implements Serializable {
private static final long serialVersionUID = 1L;
private int code = 0;
private String msg = "success";
private Long timestamp = System.currentTimeMillis();
private Object data = null;
public Response() {
}
public Response(Object data) {
this.code = 0;
this.timestamp = System.currentTimeMillis();
this.msg = "success";
this.data = data;
}
public Response(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.timestamp = timestamp;
this.data = data;
}
public Response(int code, String msg, Object data, Long timestamp) {
this.code = code;
this.msg = msg;
this.timestamp = timestamp;
this.data = data;
}
public Response(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
controller层
@GetMapping("/getUserById")
public Object getUserById(Integer id) {
Response response = new Response();
UserEntity userEntity = (UserEntity) redisUtils.get("BASE_USER_ID_" + id);
if (null != userEntity)
return response.setCode(ResponseCode.SUCCESS.getCode()).setMsg(ResponseCode.SUCCESS.getMsg()).setData(userEntity);
userEntity = userMapper.selectByPrimaryKey(id);
if (null != userEntity)
redisUtils.set("BASE_USER_ID_" + id, userEntity);
if (null!=userEntity)
return response.setCode(ResponseCode.SUCCESS.getCode()).setMsg(ResponseCode.SUCCESS.getMsg()).setData(userEntity);
return response.setCode(ResponseCode.EMPTY.getCode()).setMsg(ResponseCode.EMPTY.getMsg());
}