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获取用户idarg.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> {@AutoFillvoid insertData(SessionDomain sessionDomain);
}
- 使用mybatis-plus自带的填充注解
首先在实体对象上加自动填充属性注解fill = FieldFill.INSERT
@Data
@TableName("session_login")
public class SessionDomain {@TableId(value = "id", type = IdType.AUTO)private Long id;@TableFieldprivate 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 {@Overridepublic 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获取用户idthis.setFieldValByName("createUser", "1", metaObject);this.setFieldValByName("updateUser", "1", metaObject);}@Overridepublic void updateFill(MetaObject metaObject) {//实际中从ThreadLocal获取用户idthis.setFieldValByName("updateTime", Date.from(LocalDateTime.now().toInstant(ZoneOffset.UTC)), metaObject);this.setFieldValByName("updateUser", "1", metaObject);}
}
剩下就是在service层使用mapper接口insert、update数据即可。