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);
內容完