Thread是线程池,ThreadLocal是线程变量,每个线程变量是封闭的,与其它线程变量分隔开来,在sky-common下的com.sky.context包下有一个Basecontext类
public class BaseContext {
//每一个上下文创建了一个线程变量,用来存储long类型的id
//创建三个方法,用来设置,取用,删除id
public 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 {
@Autowired
private 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);
内容完