如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換
簡介
AOP也是我們常說的面向切面編程,AOP在我們開發(fā)過程中應(yīng)用也比較多,在這里我們就基于AOP來實(shí)現(xiàn)一個數(shù)據(jù)字典轉(zhuǎn)換的案例。
案例介紹
相信各位在寫代碼的時候肯定有過這樣的經(jīng)歷,我們設(shè)計數(shù)據(jù)庫時對于字典類的數(shù)據(jù)一般都會采用字典碼進(jìn)行存儲,而不是直接使用字典值。首先是因?yàn)檫@是一種開發(fā)規(guī)范,其次使用編碼也會利于數(shù)據(jù)存儲,數(shù)據(jù)整體也會比較干凈整潔。
數(shù)據(jù)字典編碼的定義一般也會做一些分類,比如說U01開頭代表用戶類型,U02開頭代表用戶性別等等,這樣也有助于我們進(jìn)行數(shù)據(jù)分析。
下面我們就簡單以一個用戶表來做數(shù)據(jù)字典轉(zhuǎn)換。
案例實(shí)現(xiàn)
創(chuàng)建表:
CREATE TABLE `t_user` ( `id` BIGINT(12) NOT NULL AUTO_INCREMENT, `user_code` VARCHAR(20) NOT NULL, `user_name` VARCHAR(50) NOT NULL, `user_type` CHAR(5) NOT NULL COMMENT '用戶類型 -> U0101:普通用戶,U0102:VIP用戶', `gender` CHAR(5) NOT NULL COMMENT '用戶性別 -> U0299:未知,U0201:男,U0202:女', PRIMARY KEY (`id`) ) CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
代碼結(jié)構(gòu):
相關(guān)代碼可由逆向工程去生成,我們就簡單的編寫了從控制層請求到服務(wù)層的業(yè)務(wù)處理再到dao層的數(shù)據(jù)處理,在這里我就一一將代碼展示出來了各位還需要自己多動手。下面就直接上代碼結(jié)構(gòu)圖

測試接口:
接下來我們在UserController類中寫一個測試接口,根據(jù)userCode查詢用戶信息如下:
@GetMapping("/{userCode}")
public UserVo queryUser(@PathVariable("userCode") String userCode) {
UserDto userDto = userService.queryUserByCode(userCode);
return userMapStruct.userDtoToUserVo(userDto);
}初始化測試數(shù)據(jù):

切面定義
定義注解類:用于標(biāo)記哪個地方需要進(jìn)行數(shù)據(jù)字典轉(zhuǎn)換切面。
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictParam {
/**
* 映射目標(biāo)屬性,為空默認(rèn)直接映射到field,替換掉原來的field
* @return
*/
String targetField() default "";
/**
* 映射來源屬性
* @return
*/
String field();
/**
* 數(shù)據(jù)字典類型
* @return
*/
String dictType();
}@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictHelper {
/**
* 字典轉(zhuǎn)換參數(shù)配置
*/
DictParam[] value();
}定義注解切面類:主要實(shí)現(xiàn)字典轉(zhuǎn)換的核心內(nèi)容。
@Slf4j
@Aspect
public class DictHelperAspect {
public DictHelperAspect() {
}
@Around("@annotation(dictHelper)")
public Object doAround(ProceedingJoinPoint joinPoint, DictHelper dictHelper) {
try {
// 執(zhí)行方法得到結(jié)果
Object result = joinPoint.proceed();
DictParam[] values = dictHelper.values();
if (values == null || values.length == 0) {
return result;
}
// 字典轉(zhuǎn)換開始(使用反射)
for (DictParam value : values) {
Class<?> clazz = result.getClass();
// 反射調(diào)用get方法獲取字段值
Method sourceMethod = clazz.getMethod("get" + firstToUppercase(value.field()));
Object fieldValue = sourceMethod.invoke(result);
// 獲取字典值
String dictValue = DictConfig.DICT_MAPPER.get(value.dictType()).get(fieldValue.toString());
// 獲取目標(biāo)方法進(jìn)行設(shè)值
String targetField = StringUtils.isBlank(value.targetField()) ? value.field() : value.targetField();
Method targetMethod = clazz.getMethod("set" + firstToUppercase(targetField), dictValue.getClass());
targetMethod.invoke(result, dictValue);
}
return result;
}
catch (Throwable throwable) {
log.error("error:", throwable);
return null;
}
}
private String firstToUppercase(String str) {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}Service層添加字典轉(zhuǎn)換的切面掃描注解:
@DictHelper(values = {
@DictParam(field = "userType", targetField = "userTypeShow", dictType = "USER_TYPE"),
@DictParam(field = "gender", targetField = "genderShow", dictType = "GENDER")
})
public UserDto queryUserByCode(String userCode) {
UserEntity userEntity = userMapper.selectUser(userCode);
return userMapStruct.userEntityToUserDto(userEntity);
}如上代碼主要分三個步驟:
- 根據(jù)
@DictParam注解配置的數(shù)據(jù)來源字段通過返回調(diào)用數(shù)據(jù)返回對象獲取數(shù)據(jù)來源字典編碼。 - 根據(jù)字典編碼通過字典編碼表(這里直接使用靜態(tài)
DictConfig直接調(diào)用)找到對應(yīng)字典值。 - 根據(jù)
@DictParam注解配置的目標(biāo)數(shù)據(jù)字典,將匹配到的數(shù)據(jù)字典值通過反射將數(shù)據(jù)回填到對象中。
注意:各位開發(fā)者朋友們,看到這里是不是以為很簡單呢,但是在實(shí)際開發(fā)過程中我們更注重的是程序的安全、穩(wěn)定、可靠,所以這也不難看出上面的代碼當(dāng)中省去了許多校驗(yàn)
靜態(tài)字典:實(shí)際開發(fā)過程中,不建議這么配置,因?yàn)檫@樣是完全不靈活的,這里只是為了方便演示而已。實(shí)際業(yè)務(wù)當(dāng)中可以自定義一種數(shù)據(jù)字典加載策略(服務(wù)啟動成功后加載或者定期刷新加載),將字典加載到內(nèi)存,或者使用數(shù)據(jù)庫結(jié)合redis做內(nèi)存也可以,數(shù)據(jù)字典還是要避免頻繁直接的去查數(shù)據(jù)庫。
public class DictConfig {
public static final Map<String, Map<String, String>> DICT_MAPPER = new HashMap<>();
static {
Map<String, String> USER_TYPE = new HashMap<>();
USER_TYPE.put("U0101", "普通用戶");
USER_TYPE.put("U0102", "VIP用戶");
DICT_MAPPER.put("USER_TYPE", USER_TYPE);
Map<String, String> GENDER = new HashMap<>();
GENDER.put("U0201", "男");
GENDER.put("U0202", "女");
GENDER.put("U0299", "未知");
DICT_MAPPER.put("GENDER", GENDER);
}
}運(yùn)行結(jié)果:

總結(jié)
利用切面編程還可以做很多事,本文所展示的數(shù)據(jù)字典轉(zhuǎn)換也僅僅只是冰山一角,像用的比較多的分頁處理我們也一樣可以用這種方式去做。
數(shù)據(jù)字典在我們開發(fā)設(shè)計當(dāng)中是必不可少的,合理的使用好數(shù)據(jù)字典還是很有必要的。
到此這篇關(guān)于如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)Java AOP字典轉(zhuǎn)換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring cloud gateway跨域全局CORS配置方式
這篇文章主要介紹了spring cloud gateway跨域全局CORS配置方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
mybatis 查詢sql中in條件用法詳解(foreach)
這篇文章主要介紹了mybatis 查詢sql中in條件用法詳解(foreach),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02
JAVA設(shè)置手動提交事務(wù),回滾事務(wù),提交事務(wù)的操作
這篇文章主要介紹了JAVA設(shè)置手動提交事務(wù),回滾事務(wù),提交事務(wù)的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-04-04
java執(zhí)行SQL語句實(shí)現(xiàn)查詢的通用方法詳解
這篇文章主要介紹了java執(zhí)行SQL語句實(shí)現(xiàn)查詢的通用方法詳解,具有一定借鑒價值,需要的朋友可以參考下。2017-12-12
一小時迅速入門Mybatis之實(shí)體類別名與多參數(shù) 動態(tài)SQL
這篇文章主要介紹了一小時迅速入門Mybatis之實(shí)體類別名與多參數(shù) 動態(tài)SQL,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-09-09
自制Java工具實(shí)現(xiàn)翻譯鼠標(biāo)選中文本
這篇文章主要為大家詳細(xì)介紹了如何自制Java工具實(shí)現(xiàn)ctrl+c+c翻譯鼠標(biāo)選中文本,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2024-01-01
Java項(xiàng)目中添加外部jar包的兩種方式(收藏版)
這篇文章主要介紹了java項(xiàng)目中添加外部jar包的兩種方式,第二種方式是將外部jar包引入到本地maven倉庫中,本文給大家講解的非常詳細(xì),需要的朋友可以參考下2023-03-03

