Aop-利用自定义注解和Aop 反射 注入 createTime 和 updateTime
一、前言
createTime和updateTime 这种字段,在写业务代码时很容易漏掉。而且在业务代码里面 每次都要关注这个字段手动 set一下很繁琐。
二、代码
利用Aop切面 和 反射 和自定义注解可以单独在一个地方管理这种 与业务无关的字段。
1、OperateAnnotion自定义注解
package com.mangoubiubiu.annotation; import java.lang.annotation.*; /** * @author mangoubiubiu */ //作用在类,方法,字段上 @Target(value = {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME)//注解可以在运行期的加载阶段被加载到Class对象中。那么在程序运行阶段,我们可以通过反射得到这个注解,并通过判断是否有这个注解或这个注解中属性的值,从而执行不同的程序代码段 @Documented//是被用来指定自定义注解是否能随着被定义的java文件生成到JavaDoc文档当中。 public @interface OperateAnnotion { Class[] exclude() default {}; //需要注入实体类的class String [] operateFileds() default {"createTime","updateTime"};//字段名 String idKey() default "";//实体类的id 通过idKey 来取value }
2、OperateAspect切面类
package com.mangoubiubiu.aspect; import cn.hutool.core.util.ReflectUtil; import com.mangoubiubiu.annotation.OperateAnnotion; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Field; import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; /** * @author mangoubiubiu * 切面类 注入createTime updateTime */ @Aspect @Component @Slf4j public class OperateAspect { /** * 切入点 */ @Pointcut("@annotation(com.mangoubiubiu.annotation.OperateAnnotion)") public void pointCut(){} /** * 环绕通知 * @param joinPoint * @return */ @Around("@annotation(operateAnnotion)") public Object around(ProceedingJoinPoint joinPoint, OperateAnnotion operateAnnotion){ //获取class List<Class> classes = Arrays.asList(operateAnnotion.exclude()); //获取要修改的字段 List<String> fields = Arrays.asList(operateAnnotion.operateFileds()); //获取要判断的id名 String idKey= operateAnnotion.idKey(); Object[] args= joinPoint.getArgs(); try { for(int i = 0; i<args.length; i++){ //通过反射获取当前实体类的id,用来判断是修改操作还是新增操作 for(int j=0;j<classes.size();j++){ if(args[i].getClass() == classes.get(j)){ Object o =args[i]; //ReflectUtil为hutool反射的工具类 Field field = ReflectUtil.getField(args[i].getClass(), idKey); field.setAccessible(true);//关闭安全检查 String ids = (String)field.get(o);//通过反射拿到当前实体类的id field.setAccessible(false); //id为空则为新增 createTime UpdateTime都要加 if(StringUtils.isBlank(ids)){ fields.forEach((str->{ ReflectUtil.setFieldValue(o,str, LocalDateTime.now()); })); }else{ ReflectUtil.setFieldValue(o,fields.get(1), LocalDateTime.now());//默认第二个为updateTime } } } } //执行目标方法 Object result = joinPoint.proceed(); return result; }catch (Throwable e){ log.error(e.getMessage()); } return null; } }
3、业务Service operateFileds没有写 默认有个默认值
/** * 保存或者修改单条学生记录 * @param student */ @OperateAnnotion(exclude = {Student.class},idKey = "stuId") @Override public void saveOrUpdate(Student student) { //id为空为新增 if(StringUtils.isBlank(student.getStuId())){ student.setStuId(UUID.randomUUID().toString().replaceAll("-","")); studentMapper.insertStudent(student); }else { studentMapper.updateStudent(student); } }
三、测试
新增
成功注入
修改
注入成功
SUCCESS