前言
本篇内容:
提示語的國際化傳回,自定義多語言。
本文使用aop方式,攔截接口傳回的資料,進行轉換。
正文
先看這次示例教學的項目 目錄結構:
(當然resource裡面的i18n檔案夾和三個properties檔案也是要我們自己建的,但是 那個Resource Bundle 不用管,這個在yml加上對應配置項自動生成的。 不清楚的繼續往下看教學就好)
開始敲(CV)代碼:
pom.xml 依賴:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
傳回碼的枚舉
CodeEnum.java
/**
* @author JCccc
*/
public enum CodeEnum {
SUCCESS(1000, "請求成功"),
FAIL(2000, "請求失敗");
public final int code;
public final String msg;
public Integer getCode() {
return this.code;
}
CodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
public String getMsg() {
return this.msg;
}
}
傳回資料的簡單封裝
ResultData.java
import com.test.myi18n.enums.CodeEnum;
import lombok.Data;
/**
* @author JCccc
*/
@Data
public class ResultData<T> {
private Integer code;
private String message;
private T data;
public ResultData(int code, String message) {
this.code = code;
this.message = message;
}
public static ResultData success(CodeEnum codeEnum) {
return new ResultData(codeEnum.code, codeEnum.msg);
}
public static ResultData success(String msg) {
return new ResultData(CodeEnum.SUCCESS.getCode(),msg);
}
}
Locale、 MessageSource的簡單方法封裝
LocaleMessage.java
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;
/**
* @author JCccc
*/
@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); }
}
i18n語言轉換工具類
I18nUtils.java
import java.util.Locale;
import com.test.myi18n.message.LocaleMessage;
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;
}
}
接下來是我們轉換的一個關鍵環節, aop方式攔截 controller接口傳回的資料:
LanguageAspect.java
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
/**
* @author JCccc
*/
@Aspect
@Component
@AllArgsConstructor
@ConditionalOnProperty(prefix = "lang", name = "open", havingValue = "true")
public class LanguageAspect {
@Autowired
I18nUtils i18nUtils;
@Pointcut("execution(* com.test.myi18n.controller.*.*(..)))")
public void annotationLangCut() {
}
/**
* 攔截controller層傳回的結果,修改msg字段
*
* @param point
* @param obj
*/
@AfterReturning(pointcut = "annotationLangCut()", returning = "obj")
public void around(JoinPoint point, Object obj) {
Object resultObject = obj;
try {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//從擷取RequestAttributes中擷取HttpServletRequest的資訊
HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
String langFlag = request.getHeader("lang");
if (null != langFlag) {
ResultData r = (ResultData) obj;
String msg = r.getMessage().trim();
if (StringUtils.isNotEmpty(msg)) {
if ("CN".equals(langFlag)) {
Locale locale = Locale.CHINA;
msg = i18nUtils.getKey(msg, locale);
} else if ("EN".equals(langFlag)) {
Locale locale = Locale.US;
msg = i18nUtils.getKey(msg, locale);
} else {
msg = i18nUtils.getKey(msg);
}
}
r.setMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
//傳回原值
obj = resultObject;
}
}
}
代碼簡單解讀:
1. annotationLangCut 上面切點管控的位址 需要自己改下,改成自己想管控的檔案夾路徑
2. @ConditionalOnProperty 注解,讀取yml 裡面lang開頭的配置項,key為 open ,value 為true
隻有為true,這個aop攔截才會生效
3. String langFlag = request.getHeader("lang");
從這句可以看到我這次文章采取的是讓對接接口方(前端)在header裡面傳入需要使用的語言flag。 例如傳入 EN (英文),意思就是需要把提示語轉為英文。
大家可以結合自己的項目實際情況,改為從yml讀取或者從資料庫讀取或者從redis讀取等等都可以。
4. ResultData r = (ResultData) obj;
String msg = r.getMessage().trim();
這兩行代碼為了就是把攔截到的obj中的message提示語擷取出來, 如果大家項目的傳回資料不是我文中使用的 ResultData,則需要自己進行魔改調整。
最後是 三份 mess properties檔案:
mess.properties
自定義的傳回語= 您好,如果文章對你有用,請關注+收藏+評論
這個檔案按照本文裡aop的攔截方式,會先檢測 目前 的 語言flag值,如果檢測不到就h會到
mess.properties 檔案裡面找。
mess_en_US.properties
請求成功=success
請求失敗=fail
mess_zh_CN.properties
請求成功=請求成功
請求失敗=請求失敗
success=請求成功
fail=請求失敗
最後寫個測試接口給大家示範一下效果:
@GetMapping("test")
public ResultData test(@RequestParam int testNum) {
if (1==testNum){
return ResultData.success(CodeEnum.SUCCESS);
}
if (2==testNum){
return ResultData.success(CodeEnum.FAIL);
}
if (3==testNum){
return ResultData.success("自定義的傳回語");
}
return ResultData.success(CodeEnum.SUCCESS);
}
調用測試: