日常开发的数据库设计环节,相信大家都会有这样一种感受,每张表都会有这些基本信息, creator_id, creator, created_at, updater_id, updater, updated_at , 我暂且称为元数据(MetaInfo)吧。
几乎每张表都会有这些字段,而且在你编写 CRUD 操作代码的时候,都需要对这些字段进行赋值或修改。从我个人感觉,这会带来至少两点问题:第一、代码重复率较高,第二、容易出错,一不小心忘了修改某个字段,测试人员就会给你提个 bug。
所以,我就通过 AOP 的思想进行了统一处理。
实体封装
既然所有的表都有这些字段,实体设计的时候就可以通过继承的方式进行统一管理。
1. 定义 BaseEntity
public class BaseEntity implements Serializable {
/**
* 创建人id
*/
private Long creatorId;
/**
* 创建人
*/
private String createdBy;
/**
* 创建时间
*/
private Date createdAt;
/**
* 修改人id
*/
private Long updaterId;
/**
* 修改人
*/
private String updatedBy;
/**
* 修改时间
*/
private Date updatedAt;
}
2. 定义业务Entity:
public class Goods extends BaseEntity {
}
自定义 AOP
1. 自定义注解,用来标识 某个接口是 新增还是修改操作。
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MetaInfoAnnotation {
OperateTypeEnum value();
}
2. 自定义的 OperateTypeEnum
public enum OperateTypeEnum {
ADD,
DELETE,
UPDATE;
}
3. 自定义 aop 操作
public class MetaInfoAop {
@Pointcut("@annotation(com.xx.aop.MetaInfoAnnotation))")
public void doSet(){}
/**
* 环绕增强,相当于MethodInterceptor
*/
@Around("doSet()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
Object res = null;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
MetaInfoAnnotation annotation = signature.getMethod().getAnnotation(MetaInfoAnnotation.class);
OperateTypeEnum value = annotation.value();
Object[] args = joinPoint.getArgs();
if (args.length > 0) {
BaseEntity arg = (BaseEntity) args[0];
Date now = new Date();
UserSessionMsg sessionUser = OperateSessionUserUtil.getUserSessionMsg();
UserInfo user = sessionUser.getUserInfo();
Long userId = user.getUserId();
String userName = user.getRealName();
if (value == OperateTypeEnum.ADD) {
arg.setCreatorId(userId);
arg.setCreatedBy(userName);
arg.setCreatedAt(now);
arg.setUpdaterId(userId);
arg.setUpdatedBy(userName);
arg.setUpdatedAt(now);
}
if (value == OperateTypeEnum.UPDATE || value == OperateTypeEnum.DELETE) {
arg.setUpdaterId(userId);
arg.setUpdatedBy(userName);
arg.setUpdatedAt(now);
}
}
return joinPoint.proceed(args);
}
}
使用
在 controller 中使用,以 添加操作为例:
@RestController
@RequestMapping("/goods")
public class GoodsController {
@MetaInfoAnnotation(value = OperateTypeEnum.ADD)
@PostMapping("/save")
public ResponseBean save(@RequestBody Goods goods){
try {
goodsService.add(goods);
} catch (URISyntaxException e) {
e.printStackTrace();
}
return new ResponseBean(true, "保存成功", ResponseCode.SUCCESS);
}
通过以上操作,你开发新业务时,就不用再关心实体元数据,专心处理你的核心业务字段即可。
如果觉得还不错的话,关注、分享、在看(关注不失联~), 原创不易,且看且珍惜~