SpringBoot 公共字段自动填充
发表于更新于
字数总计:990阅读时长:3分钟 南京
在使用 SpringBoot 框架开发项目时,经常会遇到 「创建时间」「修改时间」等公共字段,这些字段每次都需要我们手动去设置,十分麻烦。
本文使用 SpringBoot 中的切面功能来实现这些公共字段的自动填充
定义注解
首先我们定义一个注解用于标记哪些方法需要实现自动填充
1 2 3 4 5 6 7 8 9 10 11 12
|
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface AutoFill {
OperationType value(); }
|
@Target(ElementType.METHOD)
标记该注解用于方法上面
@Retention(RetentionPolicy.RUNTIME)
指定注解在运行阶段可用
OperationType value();
函数指定注解需要指定一个参数 value
,值为 OperationType
类型,OperationType
是定义的一个枚举类,用于指定数据库操作的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public enum OperationType {
UPDATE,
INSERT
}
|
定义切面类
切入点
首先使用切入点表达式标记这个切面类会在哪些方法上执行
1 2 3 4 5
|
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotations.AutoFill)") public void autoFillPointCut(){}
|
该表达式说明切入点是 mapper 包下的任意函数,但是需要使用了上述定义的 AutoFill
注解
通知方法
使用前置通知,在 mapper 函数执行之前,完成字段自动填充过程
首先, 我们需要获取到数据库操作类型,使用 joinPoint.getSignature()
先获取需要填充字段的方法的签名,然后利用 java 的反射机制获取到该方法上的注解对象 signature.getMethod().getAnnotation(AutoFill.class)
, 从而获取到该注解对象携带的数据库操作类型。
1 2 3 4 5 6
| MethodSignature signature = (MethodSignature) joinPoint.getSignature();
AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
OperationType op = annotation.value();
|
然后获取该方法的参数,即我们需要填充字段的实体对象, 我们约定实体对象放在方法的第一个参数。
1 2 3 4 5 6
| Object[] args = joinPoint.getArgs(); if(args == null || args.length == 0) return;
Object entity = args[0];
|
然后根据数据库操作类型判断需要填充哪些字段,利用反射获取到实体对象中相应字段的 set
方法并 invoke
该方法设置相应字段的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| if(op == OperationType.INSERT){ try { entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setCreateUser", Long.class).invoke(entity, currentId); entity.getClass().getDeclaredMethod("setUpdateUser", Long.class).invoke(entity, currentId); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } } else if(op == OperationType.UPDATE){ try { entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setUpdateUser", Long.class).invoke(entity, currentId); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } }
|
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
@Aspect @Component @Slf4j public class AutoFillAspect {
@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotations.AutoFill)") public void autoFillPointCut(){}
@Before("autoFillPointCut()") public void autoFill(JoinPoint joinPoint){ MethodSignature signature = (MethodSignature) joinPoint.getSignature(); AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class); OperationType op = annotation.value();
Object[] args = joinPoint.getArgs(); if(args == null || args.length == 0) return; Object entity = args[0];
LocalDateTime now = LocalDateTime.now(); Long currentId = BaseContext.getCurrentId();
if(op == OperationType.INSERT){ try { entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setCreateUser", Long.class).invoke(entity, currentId); entity.getClass().getDeclaredMethod("setUpdateUser", Long.class).invoke(entity, currentId); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } } else if(op == OperationType.UPDATE){ try { entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(entity, now); entity.getClass().getDeclaredMethod("setUpdateUser", Long.class).invoke(entity, currentId); } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { throw new RuntimeException(e); } } }
}
|
使用
要使用自动填充功能,只需要在 mapper
方法上加上 @AutoFill
注解即可
1 2
| @AutoFill(value = OperationType.UPDATE) void update(Category category);
|