如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換
簡(jiǎn)介
AOP也是我們常說(shuō)的面向切面編程,AOP在我們開發(fā)過(guò)程中應(yīng)用也比較多,在這里我們就基于AOP來(lái)實(shí)現(xiàn)一個(gè)數(shù)據(jù)字典轉(zhuǎn)換的案例。
案例介紹
相信各位在寫代碼的時(shí)候肯定有過(guò)這樣的經(jīng)歷,我們?cè)O(shè)計(jì)數(shù)據(jù)庫(kù)時(shí)對(duì)于字典類的數(shù)據(jù)一般都會(huì)采用字典碼進(jìn)行存儲(chǔ),而不是直接使用字典值。首先是因?yàn)檫@是一種開發(fā)規(guī)范,其次使用編碼也會(huì)利于數(shù)據(jù)存儲(chǔ),數(shù)據(jù)整體也會(huì)比較干凈整潔。
數(shù)據(jù)字典編碼的定義一般也會(huì)做一些分類,比如說(shuō)U01開頭代表用戶類型,U02開頭代表用戶性別等等,這樣也有助于我們進(jìn)行數(shù)據(jù)分析。
下面我們就簡(jiǎn)單以一個(gè)用戶表來(lái)做數(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)代碼可由逆向工程去生成,我們就簡(jiǎn)單的編寫了從控制層請(qǐng)求到服務(wù)層的業(yè)務(wù)處理再到dao層的數(shù)據(jù)處理,在這里我就一一將代碼展示出來(lái)了各位還需要自己多動(dòng)手。下面就直接上代碼結(jié)構(gòu)圖
測(cè)試接口:
接下來(lái)我們?cè)赨serController類中寫一個(gè)測(cè)試接口,根據(jù)userCode查詢用戶信息如下:
@GetMapping("/{userCode}") public UserVo queryUser(@PathVariable("userCode") String userCode) { UserDto userDto = userService.queryUserByCode(userCode); return userMapStruct.userDtoToUserVo(userDto); }
初始化測(cè)試數(shù)據(jù):
切面定義
定義注解類:用于標(biāo)記哪個(gè)地方需要進(jìn)行數(shù)據(jù)字典轉(zhuǎn)換切面。
@Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DictParam { /** * 映射目標(biāo)屬性,為空默認(rèn)直接映射到field,替換掉原來(lái)的field * @return */ String targetField() default ""; /** * 映射來(lái)源屬性 * @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); }
如上代碼主要分三個(gè)步驟:
- 根據(jù)
@DictParam
注解配置的數(shù)據(jù)來(lái)源字段通過(guò)返回調(diào)用數(shù)據(jù)返回對(duì)象獲取數(shù)據(jù)來(lái)源字典編碼。 - 根據(jù)字典編碼通過(guò)字典編碼表(這里直接使用靜態(tài)
DictConfig
直接調(diào)用)找到對(duì)應(yīng)字典值。 - 根據(jù)
@DictParam
注解配置的目標(biāo)數(shù)據(jù)字典,將匹配到的數(shù)據(jù)字典值通過(guò)反射將數(shù)據(jù)回填到對(duì)象中。
注意:各位開發(fā)者朋友們,看到這里是不是以為很簡(jiǎn)單呢,但是在實(shí)際開發(fā)過(guò)程中我們更注重的是程序的安全、穩(wěn)定、可靠,所以這也不難看出上面的代碼當(dāng)中省去了許多校驗(yàn)
靜態(tài)字典:實(shí)際開發(fā)過(guò)程中,不建議這么配置,因?yàn)檫@樣是完全不靈活的,這里只是為了方便演示而已。實(shí)際業(yè)務(wù)當(dāng)中可以自定義一種數(shù)據(jù)字典加載策略(服務(wù)啟動(dòng)成功后加載或者定期刷新加載),將字典加載到內(nèi)存,或者使用數(shù)據(jù)庫(kù)結(jié)合redis做內(nèi)存也可以,數(shù)據(jù)字典還是要避免頻繁直接的去查數(shù)據(jù)庫(kù)。
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)換也僅僅只是冰山一角,像用的比較多的分頁(yè)處理我們也一樣可以用這種方式去做。
數(shù)據(jù)字典在我們開發(fā)設(shè)計(jì)當(dāng)中是必不可少的,合理的使用好數(shù)據(jù)字典還是很有必要的。
到此這篇關(guān)于如何利用Java使用AOP實(shí)現(xiàn)數(shù)據(jù)字典轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)Java AOP字典轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot指定profiles啟動(dòng)失敗問(wèn)題及解決
這篇文章主要介紹了springboot指定profiles啟動(dòng)失敗問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04Spring整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案
這篇文章主要介紹了Spring 整合Mybatis 掃描注解創(chuàng)建Bean報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10spring boot 2整合swagger-ui過(guò)程解析
這篇文章主要介紹了spring boot 2整合swagger-ui過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12Spring Security攔截器引起Java CORS跨域失敗的問(wèn)題及解決
這篇文章主要介紹了Spring Security攔截器引起Java CORS跨域失敗的問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07springboot使用spring-data-jpa操作MySQL數(shù)據(jù)庫(kù)
這篇文章主要介紹了springboot使用spring-data-jpa操作MySQL數(shù)據(jù)庫(kù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-07-07基于Java Springboot + Vue + MyBatis實(shí)現(xiàn)音樂(lè)播放系統(tǒng)
這篇文章主要介紹了一個(gè)完整的音樂(lè)播放系統(tǒng)是基于Java Springboot + Vue + MyBatis編寫的,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-08-08Java實(shí)現(xiàn)駝峰、下劃線互轉(zhuǎn)的方法
這篇文章主要介紹了Java實(shí)現(xiàn)駝峰、下劃線互轉(zhuǎn)的示例代碼,主要有使用 Guava 實(shí)現(xiàn)和自定義代碼轉(zhuǎn),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05java自定義日志輸出文件(log4j日志文件輸出多個(gè)自定義日志文件)
打印日志的在程序中是必不可少的,如果需要將不同的日志打印到不同的地方,則需要定義不同的Appender,然后定義每一個(gè)Appender的日志級(jí)別、打印形式和日志的輸出路徑,下面看一個(gè)示例吧2014-01-01使用Maven搭建SpringMVC項(xiàng)目的步驟(圖文教程)
本篇文章主要介紹了使用Maven搭建SpringMVC項(xiàng)目的步驟(圖文教程),非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-09-09