Spring AOP + 自定义注解 实现公共字段的填充
代码冗,不利于后期维护.
定义操作这些字段的方法类型
实现步骤:
- 自定义注解
AutoFill
,用于表示操作这些公共字段的方法 - 自定义切面类
AutoFillAspect
,统一拦截,通过反射获取方法入参,并填充公共字段 - 在Mapper的insert、update的方法上加上自定义的
AutoFill
注解
代码:
- 不使用mybatis-plus自带的填充注解
必要依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.18</version>
</dependency>
1、自定义注解AutoFill
,用于表示操作这些公共字段的方法
import com.cwh.mpdemo.enums.OpreaType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义注解,表示方法
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
/**
* 操作类型
*
* @return
*/
OpreaType value() default OpreaType.INSERT;
}
2、自定义切面类AutoFillAspect
,统一拦截,通过反射获取方法入参,并填充公共字段
import com.cwh.mpdemo.annotation.AutoFill;
import com.cwh.mpdemo.enums.OpreaType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
/**
* @Aspect 标注为切面类
*/
@Aspect
@Component
@Slf4j
public class AutoFillaspect {
// 定义切点
@Pointcut("execution(* com.cwh.mpdemo.mapper.*.*(..)) && @annotation(com.cwh.mpdemo.annotation.AutoFill)")
public void pointcut(){}
// 定义通知
@Before("pointcut()")
public void before(JoinPoint joinPoint){
log.info("auto fill start...");
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);
OpreaType value = annotation.value();
//获取签名方法的入参
Object[] args = joinPoint.getArgs();
if (args.length ==0 ||args == null) {
return;
}
Object arg = args[0];
try {
// 填充字段
if (value == OpreaType.INSERT){
//通过反射给入参对象的字段赋值
arg.getClass().getDeclaredMethod("setCreateTime", Date.class)
.invoke(arg, Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)));
//实际中从ThreadLocal获取用户id
arg.getClass().getDeclaredMethod("setCreateUser",String.class).invoke(arg,"test");
}
arg.getClass(). getDeclaredMethod("setUpdateTime",Date.class).invoke(arg,Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)));
//实际中从ThreadLocal获取用户id
arg.getClass().getDeclaredMethod("setUpdateUser",String.class).invoke(arg,"test");
}catch (Exception exception){
log.error("auto fill error:{}",exception.getMessage());
}
log.info("auto fill end...");
}
}
public enum OpreaType {
INSERT,
UPDATE;
}
3、在Mapper的insert、update的方法上加上自定义的AutoFill
注解
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cwh.mpdemo.annotation.AutoFill;
import com.cwh.mpdemo.domain.SessionDomain;
public interface SessionLoginMapper extends BaseMapper<SessionDomain> {
@AutoFill
void insertData(SessionDomain sessionDomain);
}
- 使用mybatis-plus自带的填充注解
首先在实体对象上加自动填充属性注解fill = FieldFill.INSERT
@Data
@TableName("session_login")
public class SessionDomain {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
@TableField
private String userName;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT)
private String createUser;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
@TableField(fill = FieldFill.UPDATE)
private String updateUser;
}
实现元数据对象处理器接口MetaObjectHandler
,实现insertFill
,updateFill
逻辑
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
@Component
public class AutoFillHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 设置属性值
this.setFieldValByName("createTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
this.setFieldValByName("updateTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
//实际中从ThreadLocal获取用户id
this.setFieldValByName("createUser", "1", metaObject);
this.setFieldValByName("updateUser", "1", metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
//实际中从ThreadLocal获取用户id
this.setFieldValByName("updateTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);
this.setFieldValByName("updateUser", "1", metaObject);
}
}
剩下就是在service层使用mapper接口insert、update数据即可。