Aop+自定義註解實現資料字典翻譯
前言
一般來說,專案開發會用自定義註解去實現日誌監控等操作
在實際專案中,前後臺資料互動時,每次都需要根據一個code值去進行查詢資料庫進行中間操作進行獲取text值
本博文用自定義註解結合aop實現資料字典的自動翻譯
原始碼
首先附上資料庫表結構:
資料字典表(dict)
資料字典型別中間表(dict_type)
使用者表(user)
註解類(Dict)
package com.xiaoyang.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author xiaoyang
* @create 2020-11-27 10:36
* 資料字典的數字轉漢字的自定義註解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
/**
* 資料dataSource
*
* @return
*/
String dictDataSource();
/**
* 返回put到json中的文字key
* @return
*/
String dictText() default "";
}
Controller:
package com.xiaoyang.controller;
import com.xiaoyang.model.User;
import com.xiaoyang.service.UserService;
import com.xiaoyang.util.PageBean;
import com.xiaoyang.util.PageUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @author xiaoyang
* @create 2020-11-27 16:47
*/
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@ResponseBody
@RequestMapping("/QueryPager")
public PageUtils QueryPager(HttpServletRequest req) {
User user=new User();
user.setName("a");
PageBean pageBean = new PageBean();
pageBean.setRequest(req);
List<User> users = this.userService.QueryPager(user, pageBean);
PageUtils pageUtils = new PageUtils(users, pageBean.getTotal());
return pageUtils;
}
}
aop切面類:
package com.xiaoyang;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiaoyang.annotation.Dict;
import com.xiaoyang.service.DictService;
import com.xiaoyang.util.ObjConvertUtils;
import com.xiaoyang.util.PageUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
@author xiaoyang
@create 2020-11-27 16:52
*/
@Aspect
@Component
@Slf4j
public class DictAspect {
//這是運算元據字典那張表的 service
@Autowired
private DictService dictService;
//翻譯後拼接的內容
private static String DICT_TEXT_SUFFIX = "_dictText";
// 定義切點Pointcut 攔截所有對伺服器的請求
@Pointcut("execution( * com.xiaoyang..controller.*.*(..))")
public void excudeService() {
}
/**
* 這是觸發 excudeService 的時候會執行的
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("excudeService()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
//這是定義開始事件
long time1 = System.currentTimeMillis();
//這是方法並獲取返回結果
Object result = pjp.proceed();
//這是獲取到 結束時間
long time2 = System.currentTimeMillis();
log.debug("獲取JSON資料 耗時:" + (time2 - time1) + "ms");
//解析開始時間
long start = System.currentTimeMillis();
//開始解析(翻譯欄位內部的值凡是打了 @Dict 這玩意的都會被翻譯)
this.parseDictText(result);
//解析結束時間
long end = System.currentTimeMillis();
log.debug("解析注入JSON資料 耗時" + (end - start) + "ms");
return result;
}
/**
* 本方法針對返回物件為Result 的IPage的分頁列表資料進行動態字典注入
* 字典注入實現 通過對實體類新增註解@dict 來標識需要的字典內容,字典分為單字典code即可 ,table字典 code table text配合使用與原來jeecg的用法相同
* 示例為SysUser 欄位為sex 新增了註解@Dict(dicCode = "sex") 會在字典服務立馬查出來對應的text 然後在請求list的時候將這個字典text,已欄位名稱加_dictText形式返回到前端
* 例輸入當前返回值的就會多出一個sex_dictText欄位
* {
* sex:1,
* sex_dictText:"男"
* }
* 前端直接取值sext_dictText在table裡面無需再進行前端的字典轉換了
* customRender:function (text) {
* if(text==1){
* return "男";
* }else if(text==2){
* return "女";
* }else{
* return text;
* }
* }
* 目前vue是這麼進行字典渲染到table上的多了就很麻煩了 這個直接在服務端渲染完成前端可以直接用
*
* @param result
*/
private void parseDictText(Object result) {
if (result instanceof PageUtils) {
List<JSONObject> items = new ArrayList<>();
PageUtils pageUtils = (PageUtils) result;
//迴圈查詢出來的資料
for (Object record : pageUtils.getData()) {
ObjectMapper mapper = new ObjectMapper();
String json = "{}";
try {
//解決@JsonFormat註解解析不了的問題詳見SysAnnouncement類的@JsonFormat
json = mapper.writeValueAsString(record);
} catch (JsonProcessingException e) {
log.error("json解析失敗" + e.getMessage(), e);
}
JSONObject item = JSONObject.parseObject(json);
//update-begin--Author:scott -- Date:20190603 ----for:解決繼承實體欄位無法翻譯問題------
//for (Field field : record.getClass().getDeclaredFields()) {
for (Field field : ObjConvertUtils.getAllFields(record)) {
//update-end--Author:scott -- Date:20190603 ----for:解決繼承實體欄位無法翻譯問題------
if (field.getAnnotation(Dict.class) != null) {
String code = field.getAnnotation(Dict.class).dictDataSource();
String text = field.getAnnotation(Dict.class).dictText();
//獲取當前帶翻譯的值
String key = String.valueOf(item.get(field.getName()));
//翻譯字典值對應的txt
String textValue = translateDictValue(code, key);
// CommonConstant.DICT_TEXT_SUFFIX的值為,是預設值:
// public static final String DICT_TEXT_SUFFIX = "_dictText";
log.debug(" 字典Val : " + textValue);
log.debug(" __翻譯字典欄位__ " + field.getName() + DICT_TEXT_SUFFIX + ": " + textValue);
//如果給了文字名
if (!StringUtils.isEmpty(text)) {
item.put(text, textValue);
} else {
//走預設策略
item.put(field.getName() + DICT_TEXT_SUFFIX, textValue);
}
}
//date型別預設轉換string格式化日期
if (field.getType().getName().equals("java.util.Date") && field.getAnnotation(JsonFormat.class) == null && item.get(field.getName()) != null) {
SimpleDateFormat aDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
item.put(field.getName(), aDate.format(new Date((Long) item.get(field.getName()))));
}
}
items.add(item);
}
pageUtils.setData(items);
}
}
/**
* 翻譯字典文字
*
* @param code
* @param key
* @return
*/
private String translateDictValue(String code, String key) {
//如果key為空直接返回就好了
if (ObjConvertUtils.isEmpty(key)) {
return null;
}
StringBuffer textValue = new StringBuffer();
//分割 key 值
System.out.println(code+":::::"+key);
String[] keys = key.split(",");
//迴圈 keys 中的所有值
for (String k : keys) {
String tmpValue = null;
log.debug(" 字典 key : " + k);
if (k.trim().length() == 0) {
continue; //跳過迴圈
}
tmpValue = dictService.selectByDatasourceCode(code,k.trim());
if (tmpValue != null) {
if (!"".equals(textValue.toString())) {
textValue.append(",");
}
textValue.append(tmpValue);
}
}
//返回翻譯的值
return textValue.toString();
}
}
工具類(反射類):
package com.xiaoyang.util;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author xiaoyang
* @create 2020-11-29 8:32
*/
public class ObjConvertUtils {
/**
* 獲取類的所有屬性,包括父類
*
* @param object
* @return
*/
public static Field[] getAllFields(Object object) {
Class<?> clazz = object.getClass();
List<Field> fieldList = new ArrayList<>();
while (clazz != null) {
fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
clazz = clazz.getSuperclass();
}
Field[] fields = new Field[fieldList.size()];
fieldList.toArray(fields);
return fields;
}
public static boolean isEmpty(Object object) {
if (object == null) {
return (true);
}
if ("".equals(object)) {
return (true);
}
if ("null".equals(object)) {
return (true);
}
return (false);
}
}
在User
的實體類中使用註解(可傳兩個引數,這裡使用註解後會在切面類進行獲取註解的內容進行資料庫查詢,例如這裡userlevel
屬性註解傳入的是user_level
,那麼controller層查詢出結果集合後,在切面類進行字典表對應欄位的查詢):
結果:
思維導圖
自定義註解運用aop的思想去進行資料字典的轉譯從根本上來說就是為了簡化我們的程式碼,實現後不需要每次都呼叫方法去查詢(需結合快取)
最後附上流程圖供理解:
over…
相關文章
- redis分散式鎖-spring boot aop+自定義註解實現分散式鎖Redis分散式Spring Boot
- 工作常備:自定義註解實現資料脫敏
- 基於SpringBoot 、AOP與自定義註解轉義字典值Spring Boot
- 使用AOP+自定義註解完成spring boot的介面許可權校驗Spring Boot
- SpringBoot中搭配AOP實現自定義註解Spring Boot
- 筆記3:自定義註解的實現筆記
- 自定義註解+反射 實現給註解新增功能的效果反射
- 自定義註解進行資料脫敏
- 自定義註解完成資料庫切庫資料庫
- 安卓自定義註解支援和示例實現安卓
- 自定義註解
- Java註解-後設資料、註解分類、內建註解和自定義註解Java
- Feign通過自定義註解實現路徑的轉義
- 使用自定義註解透過BeanPostProcessor實現策略模式Bean模式
- Springboot AOP 自定義註解實現系統日誌Spring Boot
- 自定義註解例項實現SQL語句生成SQL
- Spring 實現策略模式--自定義註解方式解耦if...elseSpring模式解耦
- 自定義JAVA註解Java
- 自定義ConditionalOnXX註解
- Clang 之旅--[翻譯]新增自定義的 attribute
- Java中的註解-自定義註解Java
- IDEA自定義類註釋和方法註釋(自定義groovyScript方法實現多行引數註釋)Idea
- Spring系列之aAOP AOP是什麼?+xml方式實現aop+註解方式實現aopSpringXML
- 聊聊如何通過自定義註解實現springmvc和sentinel整合SpringMVC
- [非專業翻譯] Mapster - 自定義對映
- JAVA-註解(2)-自定義註解及反射註解Java反射
- Spring Boot中自定義註解+AOP實現主備庫切換Spring Boot
- java中如何自定義註解Java
- Spring Boot 自定義註解失效Spring Boot
- SpringBoot自定義校驗註解Spring Boot
- springBoot自定義註解的使用Spring Boot
- 自定義校驗註解ConstraintValidatorAI
- [非專業翻譯] Mapster - 自定義命名約定
- Java實現Web操作介面以及返回資料的翻譯JavaWeb
- [非專業翻譯] Mapster - 自定義對映邏輯
- 自定義註解以及註解在反射中的應用反射
- [Flutter翻譯]如何在Backendless Flutter SDK中使用自定義類Flutter
- app直播原始碼,java自定義註解APP原始碼Java