Thread是线程池,ThreadLocal是线程变量,每个线程变量是封闭的,与其它线程变量分隔开来,在sky-common下的com.sky.context包下有一个Basecontext类
public class BaseContext {//每一个上下文创建了一个线程变量,用来存储long类型的id//创建三个方法,用来设置,取用,删除idpublic static ThreadLocal<Long> threadLocal = new ThreadLocal<>();public static void setCurrentId(Long id) {threadLocal.set(id);}public static Long getCurrentId() {return threadLocal.get();}public static void removeCurrentId() {threadLocal.remove();}}
在jwt拦截器中我们会将前端传过来的id设置到当前线程中
public class JwtTokenAdminInterceptor implements HandlerInterceptor {@Autowiredprivate JwtProperties jwtProperties;/*** 校验jwt** @param request* @param response* @param handler* @return* @throws Exception*/public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("当线程的id"+Thread.currentThread().getId());//判断当前拦截到的是Controller的方法还是其他资源if (!(handler instanceof HandlerMethod)) {//当前拦截到的不是动态方法,直接放行return true;}//1、从请求头中获取令牌String token = request.getHeader(jwtProperties.getAdminTokenName());//2、校验令牌try {log.info("jwt校验:{}", token);//这个Claims claims = JwtUtil.parseJWT(jwtProperties.getAdminSecretKey(), token);Long empId = Long.valueOf(claims.get(JwtClaimsConstant.EMP_ID).toString());log.info("当前员工id:", empId);//这里BaseContext.setCurrentId(empId);//3、通过,放行return true;} catch (Exception ex) {//4、不通过,响应401状态码response.setStatus(401);return false;}}
}
紧接着想要使用AOP我们需要定义一个AutoFill注解
//表示注解到方法上
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//表示注解运行时仍保留
public @interface AutoFill {//在common包下,包含insert和update两种操作OperationType value();
}
然后我们就可以在AutoFillAspect对指定包下满足条件的方法进行拦截和处理
@Aspect
@Component
@Slf4j
public class AutoFillAspect {//为首的*表示返回类型为任意,com.sky.mapper.*.*这个表示//mapper包下所有的类(..)所有方法,&&后面表示加了AutoFill注解的方法//指定被拦截的方法@Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")public void autoFillPointCut(){}//在执行前做的操作@Before("autoFillPointCut()")public void autoFill(JoinPoint joinPoint){log.info("开始进行公共字段自动填充...");//获取到当前被拦截的方法上的数据库操作类型MethodSignature signature = (MethodSignature) joinPoint.getSignature();AutoFill autoFill=signature.getMethod().getAnnotation(AutoFill.class);OperationType operationType=autoFill.value();
// MemberSignature signature = (MemberSignature) joinPoint.getSignature();
// AutoFill autoFill=signature.getMothod().getAnnotation(AutoFill.class)//获取到当前被拦截的方法的参数-实体对象Object[] args=joinPoint.getArgs();if(args==null||args.length==0)return;Object entity=args[0];//准备赋值的类型LocalDateTime now=LocalDateTime.now();Long currentId= BaseContext.getCurrentId();//根据当前不同的操作类型,为对应的属性通过反射来赋值if(operationType==OperationType.INSERT){try {Method setCreateTime=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);Method setCreateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER,Long.class);Method setUpdateTime=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);Method setUpdateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);setCreateTime.invoke(entity,now);setCreateUser.invoke(entity,currentId);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} catch (Exception e) {throw new RuntimeException(e);}}else if(operationType==OperationType.UPDATE){try {Method setUpdateTime=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);Method setUpdateUser=entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);setUpdateTime.invoke(entity,now);setUpdateUser.invoke(entity,currentId);} catch (Exception e) {throw new RuntimeException(e);}}}
}
首先着重讲一下MethodSignature,由于我是跟着视频操作的,所以我一开始没有注意到一个很重要的点,MethodSignature到底是否加了extend,但看到这个类都是只读,我便认为它一开始就加了extend,然后再MethodSignature到Signature之间有这样一层关系Signature->MemberSignature->CodeSignature->MethodSignature.为什么需要这样继承呢,因为Signature没有getMethod方法,而我们需要获取方法上的注解类型,故进行这样一步操作.用于后面操作的条件判断.
接着在需要公共字段填充的类方法上加上@AutoFill(value="")注解,""里面填写对应的方法,这里只定义了update和insert.
举个例子
@Insert("insert into category(type, name, sort, status, create_time, update_time, create_user, update_user)" +" VALUES" +" (#{type}, #{name}, #{sort}, #{status}, #{createTime}, #{updateTime}, #{createUser}, #{updateUser})")@AutoFill(value = OperationType.INSERT)void insert(Category category);
内容完