SpringAop实现公共字段数据填充

背景

由于我们系统的很多表都用到了一些公共的字段,所以就考虑将这些公共字段抽离出来做一个基础的公共类,便于维护和减少代码量

实现

原理

原理其实很简单,就是讲抽离的字段集成到一个实体类,然后再contoller层写一个自定义注解,再使用springboot的切面功能,再进入方法之前为我们的实体set基类里面的值

1. 基础实体类

将抽离的字段写一个公共基础类,目前处于业务需求考虑,暂时就只有 firsttime,lasttime,operator,operatorId这四个字段

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

/**
* 实体类基类
*
*
* @version 1.0
* @date 2021-04-02 14:45
*/
@Data
public class BaseEntity {
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date firsttime;

/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date lasttime;

/**
* 操作人名称
*/
private String operator;

/**
* 操作人ID
*/
private String operatorId;
}

2. 开启AOP切面

  1. 先引入maven配置
1
2
3
4
5
<!-- aop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 在配置文件处添加开启AOP的配置
1
2
3
spring:
aop:
auto: true

3. 写一个自定义注解 AutoFillBaseEntity

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
/**
* 自动填充基础实体类数据注解
*
*
* @version 1.0
* @date 2021-04-02 15:52
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AutoFillBaseEntity {
/**
* 自动生成 firsttime
* @return
*/
boolean setFirsttime() default true;

/**
* 自动生成 lasttime
* @return
*/
boolean setLasttime() default true;


/**
* 自动生成 操作人信息
* @return
*/
boolean setOperator() default true;


/**
* 自动生成 操作人Id信息
* @return
*/
boolean setOperatorId() default true;
}

4. 写一个切面

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


/**
* 自动填充基础实体类数据切面
*
*
* @version 1.0
* @date 2021-04-02 14:07
*/
@Slf4j
@Component
@Aspect
public class AutoFillBaseAspect {

/**
* 切点定义在自己的注解上面
*/
@Pointcut("@annotation(cn.com.cninfo.ace.web.manage.annotation.AutoFillBaseEntity)")
public void pointcut() {

}

@Around("pointcut()")
public void Around(ProceedingJoinPoint pj) throws Throwable {
MethodSignature signature = (MethodSignature) pj.getSignature();
// 获取方法上的注解
AutoFillBaseEntity annotation = signature.getMethod().getAnnotation(AutoFillBaseEntity.class);
if (annotation == null) {
pj.proceed();
}
Object[] args = pj.getArgs();
if (args == null) {
pj.proceed();
}
for (Object arg : args) {
// 判断是否和BaseEntity
if (arg instanceof BaseEntity) {
// 这里获取注解上的内容
BaseEntity entity = (BaseEntity) arg;
if (annotation.setFirsttime()) {
entity.setFirsttime(new Date());
}
if (annotation.setLasttime()) {
entity.setLasttime(new Date());
}
if (annotation.setOperator()) {
entity.setOperator("操作用户");
}
if (annotation.setOperatorId()) {
entity.setOperatorId("操作用户ID");
}
}
}
pj.proceed();
}
}

使用方法

使用说明

该基类的使用主要是可以减少我们去写setLasttime,和setFirsttime 等操作,不使用一样是没问题的

1. 对我们需要的实体集成公共基础实体类

1
2
3
4
5
6
7
8
9
10
/**
* 系统通用文件管理
*
*
* @version 1.0
* @date 2021-04-02 13:50
*/
@Data
public class SysFileDto extends BaseEntity implements Serializable {
}

2. 在需要controller方法上加入我们的自定义注解

1
2
3
4
5
6
7
8
9
10
11
/**
* 修改系统参数接口
*
* @param sysVariableVo
* @return
*/
@PostMapping("update")
@AutoFillBaseEntity(setFirsttime = false)
public SysVariableDto update(@Validated @RequestBody SysVariableVo sysVariableVo){
return sysVariableService.update(sysVariableVo);
}