代码自动填充
引言:
- 关于代码自动填充,在项目开发当中,有许多重复代码,而使用代码自动填充,可以让我们不去写那么多重复的代码,大大提高写代码的效率,比如,在项目中,新增的时候会有新增时间,新增人,修改的时候有修改时间,修改人,一个一个写,太浪费时间了,每次对数据进行新增、修改和删除都需要对这些字段进行设置。传统的做法是在进行这些操作前,对实体类的字段进行set赋值,然后再进行数据库操作。这种做法的坏处不仅容易忘记导致出错、而且显得代码冗余。
问题分析
- 创建时间,创建人,修改时间,修改人等字段都属于公共字段,能否将这些公共字段在某个地方统一处理,来简化开发呢?
自定义注解:
-
首先,定义一个自定义注解
-
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill { OperationType value();//OperationType类是一个枚举类,里面定义了两个属性,insert和update }
枚举类
-
枚举类
-
/** * 数据库操作类型 */ public enum OperationType { /** * 更新操作 */ UPDATE, /** * 插入操作 */ INSERT }
切面类
-
再创建一个切面类,用来实现自动填充
-
/** * 自定义切面,实现公共字段自动填充处理逻辑 */ @Aspect @Component @Slf4j public class AutoFillAspect { /** * 切入点 */ @Pointcut("execution(* com.XXX.mapper.*.*(..)) && @annotation(com.XXX.annotation.AutoFill)")//直接在mapper包中找AutoFill注解,快 public void autoFillPointCut(){} /** * 前置通知,在通知中进行公共字段的赋值 */ @Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint){ log.info("开始进行公共字段自动填充..."); //获取到当前被拦截的方法上的数据库操作类型 MethodSignature signature = (MethodSignature) joinPoint.getSignature();//方法签名对象 AutoFill autoFill = signature.getMethod().getAnnotation(AutoFill.class);//获得方法上的注解对象 OperationType operationType = autoFill.value();//获得数据库操作类型 //获取到当前被拦截的方法的参数--实体对象 Object[] args = joinPoint.getArgs(); if(args == null || args.length == 0){ return; } Object entity = args[0];//让实体类都在0号索引,需要开发人员之间约定好,将实体类入参时放在第一个位置 //准备赋值的数据 LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId();//封装ThreadLocal //根据当前不同的操作类型,为对应的属性通过反射来赋值 if(operationType == OperationType.INSERT){ //为4个公共字段赋值 try { Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class); Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class); Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); //通过反射为对象属性赋值 setCreateTime.invoke(entity,now); setCreateUser.invoke(entity,currentId); setUpdateTime.invoke(entity,now); setUpdateUser.invoke(entity,currentId); } catch (Exception e) { e.printStackTrace(); } }else if(operationType == OperationType.UPDATE){ //为2个公共字段赋值 try { Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class); Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class); //通过反射为对象属性赋值 setUpdateTime.invoke(entity,now); setUpdateUser.invoke(entity,currentId); } catch (Exception e) { e.printStackTrace(); } } } }
- 注意:
Object entity = args[0];
//让实体类都在0号索引,需要开发人员之间约定好,将实体类入参时放在第一个位置 - 注意:
@Pointcut("execution(* com.XXX.mapper.*.*(..)) && @annotation(com.XXX.annotation.AutoFill)")
//直接在mapper包中找AutoFill注解,快
- 注意:
使用自定义注解:
-
在mapper中的更新和插入接口加上我们自定义的注解,@AutoFill
-
@AutoFill(value = OperationType.UPDATE) void update(Employee employee);
-
这时,自动填充就做好了
但是,有一个新的问题,怎样获取修改人的id呢?我这里用的是ThreadLocal,如需了解请转到ThreadLocal文章