如何利用Java使用AOP实现数据字典转换

目录
  • 简介
  • 案例介绍
  • 案例实现
  • 切面定义
  • 总结

简介

AOP也是我们常说的面向切面编程,AOP在我们开发过程中应用也比较多,在这里我们就基于AOP来实现一个数据字典转换的案例。

案例介绍

相信各位在写代码的时候肯定有过这样的经历,我们设计数据库时对于字典类的数据一般都会采用字典码进行存储,而不是直接使用字典值。首先是因为这是一种开发规范,其次使用编码也会利于数据存储,数据整体也会比较干净整洁。

数据字典编码的定义一般也会做一些分类,比如说U01开头代表用户类型,U02开头代表用户性别等等,这样也有助于我们进行数据分析。

下面我们就简单以一个用户表来做数据字典转换。

案例实现

创建表:

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;

代码结构:

相关代码可由逆向工程去生成,我们就简单的编写了从控制层请求到服务层的业务处理再到dao层的数据处理,在这里我就一一将代码展示出来了各位还需要自己多动手。下面就直接上代码结构图

测试接口:

接下来我们在UserController类中写一个测试接口,根据userCode查询用户信息如下:

@GetMapping("/{userCode}")
public UserVo queryUser(@PathVariable("userCode") String userCode) {
    UserDto userDto = userService.queryUserByCode(userCode);
    return userMapStruct.userDtoToUserVo(userDto);
}

初始化测试数据:

切面定义

定义注解类:用于标记哪个地方需要进行数据字典转换切面。

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictParam {
    /**
     * 映射目标属性,为空默认直接映射到field,替换掉原来的field
     * @return
     */
    String targetField() default "";

    /**
     * 映射来源属性
     * @return
     */
    String field();

    /**
     * 数据字典类型
     * @return
     */
    String dictType();
}
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DictHelper {
    /**
    * 字典转换参数配置
    */
    DictParam[] value();
}

定义注解切面类:主要实现字典转换的核心内容。

@Slf4j
@Aspect
public class DictHelperAspect {
    public DictHelperAspect() {
    }
    @Around("@annotation(dictHelper)")
    public Object doAround(ProceedingJoinPoint joinPoint, DictHelper dictHelper) {
        try {
            // 执行方法得到结果
            Object result = joinPoint.proceed();

            DictParam[] values = dictHelper.values();
            if (values == null || values.length == 0) {
                return result;
            }

            // 字典转换开始(使用反射)
            for (DictParam value : values) {
                Class<?> clazz = result.getClass();
                // 反射调用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());
                // 获取目标方法进行设值
                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层添加字典转换的切面扫描注解:

@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);
}

如上代码主要分三个步骤:

  • 根据@DictParam注解配置的数据来源字段通过返回调用数据返回对象获取数据来源字典编码。
  • 根据字典编码通过字典编码表(这里直接使用静态DictConfig直接调用)找到对应字典值。
  • 根据@DictParam注解配置的目标数据字典,将匹配到的数据字典值通过反射将数据回填到对象中。

注意:各位开发者朋友们,看到这里是不是以为很简单呢,但是在实际开发过程中我们更注重的是程序的安全、稳定、可靠,所以这也不难看出上面的代码当中省去了许多校验

静态字典:实际开发过程中,不建议这么配置,因为这样是完全不灵活的,这里只是为了方便演示而已。实际业务当中可以自定义一种数据字典加载策略(服务启动成功后加载或者定期刷新加载),将字典加载到内存,或者使用数据库结合redis做内存也可以,数据字典还是要避免频繁直接的去查数据库。

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);
    }
}

运行结果:

总结

利用切面编程还可以做很多事,本文所展示的数据字典转换也仅仅只是冰山一角,像用的比较多的分页处理我们也一样可以用这种方式去做。

数据字典在我们开发设计当中是必不可少的,合理的使用好数据字典还是很有必要的。

到此这篇关于如何利用Java使用AOP实现数据字典转换的文章就介绍到这了,更多相关Java AOP字典转换内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java SpringAOP技术之注解方式详解

    目录 1.配置xml扫描注解 2.配置注解 3.配置文件中开启自动代理 4.通知类型注解 5.测试类 6.结果 总结 1.配置xml扫描注解 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchem

  • java实现对map的字典序排序操作示例

    本文实例讲述了java实现对map的字典序排序操作.分享给大家供大家参考,具体如下: java中对map的字典序排序,算法验证比对微信官网https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115&token=&lang=zh_CN,搜索关键字"附录1-JS-SDK使用权限签名算法" import java.util.ArrayList; import java.util.Collectio

  • 详细解读Java Spring AOP

    一.对AOP的初印象 首先先给出一段比较专业的术语(来自百度): 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. 然后我们举一个比较容易理解的例

  • 详解Java Spring AOP

    目录 前言 一.AOP底层原理 1.AOP底层使用动态代理 二.AOP术语 1.连接点 2.切入点 3.通知(增强) 4.切面 三.AOP 操作(准备工作) Spring 框架一般都是基于 AspectJ 实现 AOP 操作 方式一:使用Spring的接口实现增添功能 方式二:自定义类 方式三:全注解配置实现 总结 前言 面向切面编程,利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率.即不改变源代码而添加新功能,可插

  • Java Spring AOP源码解析之事务实现原理

    目录 不用Spring管理事务? 编程式事务管理 使用PlatformTransactionManager 使用TransactionTemplate 声明式事务管理 使用@Transactional注解 源码解析 参考博客 总结 不用Spring管理事务? 让我们先来看一下不用spring管理事务时,各种框架是如何管理事务的 使用JDBC来管理事务 使用Hibernate来管理事务 业务逻辑和事务代码是耦合到一块的,并且和框架的具体api绑定了.当我们换一种框架来实现时,里面对事务控制的代码就

  • 详解Java SpringAOP切面类

    目录 切面类是什么 为什么需要切面类? 下面用日志功能来讲解切面类怎么创建 日志的作用 AOP的五大通知 Spring AOP类的实现技术 一.准备工作 切面类中有什么? 这些通知有什么用? 为什么命名为切面类? 下面来看代码 总结 切面类是什么 简单的来说,就是动态的在方法的指定位置添加指定的代码. 为什么需要切面类? 在软件开发的过程中,有很多业务,特别是在编写核心业务的时候,往往需要很多其他的辅助业务,比如说身份验证(银行转账需要身份验证).数据缓存.日志输出.这些往往在某个核心业务中处于

  • java通过AOP实现全局日志打印详解

    目录 几个常用的切点注解,这次使用了@Before和@Around 切Controller打印请求的接口.参数.返回值以及耗时情况. 切Service打印日志,URL,请求方式,IP,类名,方法 总结 几个常用的切点注解,这次使用了@Before和@Around 1.@Before 前置增强(目标方法执行之前,执行注解标注的内容) 2.@AfterReturning 后置增强(目标方法正常执行完毕后,执行) 3.@Around 环绕增强(目标方法执行前后,分别执行一些代码) 4.@AfterTh

  • 如何利用Java使用AOP实现数据字典转换

    目录 简介 案例介绍 案例实现 切面定义 总结 简介 AOP也是我们常说的面向切面编程,AOP在我们开发过程中应用也比较多,在这里我们就基于AOP来实现一个数据字典转换的案例. 案例介绍 相信各位在写代码的时候肯定有过这样的经历,我们设计数据库时对于字典类的数据一般都会采用字典码进行存储,而不是直接使用字典值.首先是因为这是一种开发规范,其次使用编码也会利于数据存储,数据整体也会比较干净整洁. 数据字典编码的定义一般也会做一些分类,比如说U01开头代表用户类型,U02开头代表用户性别等等,这样也

  • java中进制的转换,Byte与16进制的转换方法

    java中对于进制的转换有很多方式,其中对于常见的基本的二进制 八进制 十进制 十六进制等的转换有对于的包装类实现,不需要通过二外的算法来进行实现,具体如下: 首先关于最简单的二进制转换的方法有: 十进制转成十六进制: String Integer.toHexString(int i) 十进制转成八进制 String Integer.toOctalString(int i) 十进制转成二进制  String Integer.toBinaryString(int i) 十六进制转成十进制 Inte

  • Java+Windows+ffmpeg实现视频转换功能

    最近由于项目需要,研究了一下如何用Java实现视频转换,"着实"废了点心思,整理整理,写出给自己备忘下. 思路 由于之前没有没法过相关功能的经验,一开始来真不知道从哪里入手.当然,这个解决,google一下立马就发现了ffmpeg,网上讲解用Java+ffmpeg来进行视频转换的文章也不在少数,我主要参考的这篇文章. 上文提到的这篇文章,基本已经把开发流程什么的讲的很清楚了,这里总结下: 1)核心是利用ffmpeg进行视频转换,我们自己并不写转换视频的代码,只是调用ffmpeg,它会帮

  • 利用Java搭建个简单的Netty通信实例教程

    前言 看过dubbo源码的同学应该都清楚,使用dubbo协议的底层通信是使用的netty进行交互,而最近看了dubbo的Netty部分后,自己写了个简单的Netty通信例子. 准备 工程截图 模块详解 rpc-common rpc-common作为各个模块都需使用的模块,工程中出现的是一些通信时请求的参数以及返回的参数,还有一些序列化的工具. rpc-client rpc-client中目前只是单单的一个NettyClient启动类. rpc-server rpc-client中目前也只是单单的

  • 利用JAVA反射,读取数据库表名,自动生成对应实体类的操作

    本代码是利用java反射,读取数据库表自动根据表名生成实体类,数据库采用老牌SQLSERVER 2000,驱动为JTDS,其他数据库可根据情况自定修改. 代码中包含了大部分数据库类型与JAVA类型的转换,少数未包含进去的会在生成代码时打印出来,方面后期查找修改. import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.sq

  • 利用Java对PDF文件进行电子签章的实战过程

    目录 一. 概述 二. 技术选型 三. 生成一个图片签章 1. 生成一个如下图的签章图片 2. 相关代码 四. 如何按模板生成PDF文件 1. 制作PDF模板 2. 制作一个如下图的PDF模板,该模板是带有PDF的表单域的 五. 如何生成PKCS12证书 1. PKCS的简单介绍 2. 使用JAVA生成一个PKCS12证书并进行存贮,相关分析见代码注解 六. 如何生成一个高清晰的签章 1. 由PDF模板生成一个PDF文件,见代码注解 2. 对PDF文件进行签章 3. 高清签章 七. 如何进行多次

  • Java实现任意进制转换

    本文实例为大家分享了Java实现任意进制转换的具体代码,供大家参考,具体内容如下 问题描述 编写程序实现任意进制间的相互转换 (一).进制转换思想 1.先把任意进制转化为十进制 2.再把十进制转化为任意进制 3.本算法结合了十以下进制利用公式转换以及十以上进制调用函数转换 (二).问题分析 1.输入当前数进制 输入当前进制 m ,且保证 m>1 public static void main (String[] args){ int l,m,n; String l16; Scanner sc =

  • Java实现AOP代理的三种方式详解

    目录 1.JDK实现 2.CGLIB实现 3.boot注解实现[注意只对bean有效] 业务场景:首先你有了一个非常好的前辈无时无刻的在“教育”你.有这么一天,它叫你将它写好的一个方法进行改进测试,这时出现了功能迭代的情况.然后前辈好好“教育”你的说,不行改我的代码!改就腿打折!悲催的你有两条路可走,拿出你10年跆拳道的功夫去火拼一波然后拍拍屁股潇洒走人,要么就是悲催的开始百度...这时你会发现,我擦怎么把AOP代理这种事给忘了?[其实在我们工作中很少去手写它,但是它又是很常见的在使用(控制台日

  • 利用Java实现调用http请求

    目录 一.概述 二. Java调用第三方http接口的方式 2.1.通过JDK网络类Java.net.HttpURLConnection 2.2 通过apache common封装好的HttpClient 2.3 通过Apache封装好的CloseableHttpClient 2.4 通过SpringBoot-RestTemplate 2.5 通过okhttp 一.概述 在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适.很多项目都会封装规定好本身项目的接口规范,所以大多

随机推荐