@Component
@Aspect
public class LogProcess {
/**
* 线程池多少个:
* 1. 如果是IO密集型应用, 是CPU核心的两倍.
* 2. 如果是CPU密集型应用, 是cup核心数 + 1
*/
//创建线程池
private ExecutorService executorService = Executors.newFixedThreadPool(16);
private ProcessLogMapper processLogMapper;
public LogProcess(ProcessLogMapper processLogMapper) {
this.processLogMapper = processLogMapper;
}
//环绕通知
@Around("execution(* com.hubu.controller.*.*(..))")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
//获取方法的签名,主要目的就是为了获取反射的Method
MethodSignature methodSignature = (MethodSignature)pjp.getSignature();
//通过签名拿方法
Method method = methodSignature.getMethod();
//存储用户操作记录
ProcessLog pl = new ProcessLog();
//获取类名
String className = method.getDeclaringClass().getName();
//获取方法的名称
String methodName = method.getName();
//拿到参数值
Object[] paramValues = pjp.getArgs();
//获取所有的请求的参数,但是只能获取到参数的名字
Parameter[] parameters = method.getParameters();
Map<String,Object> paramMap = new HashMap<>();
for (int i = 0; i<parameters.length;i++){
//parameters[i].getName() 获取参数的名称
Parameter parameter = parameters[i];
//获取参数上@ExcludeParam 这个注解
ExcludeParam excludeParam = parameter.getDeclaredAnnotation(ExcludeParam.class);
/**
* 1. 文件上传时候, 参数类型是 MultipartFile, 无法转换为JSON, 所以需要将其排除
* 2. 当参数上加上 @ExcludeParam, 表示该参数不需要记录日志.
*/
if(excludeParam != null || parameter.getType() == MultipartFile.class) {
continue;
}
paramMap.put(parameters[i].getName(),paramValues[i]);
}
//记录用户行为数据
pl.setClassName(className);
pl.setMethodName(methodName);
pl.setCreateTime(new Date());
pl.setParamsInfo(JSONObject.toJSONString(paramMap));
//获取方法头顶的注解
ProcessInfo processInfo = method.getAnnotation(ProcessInfo.class);
if (null!=processInfo){
String info = processInfo.value(); //拿注解的属性
pl.setProcessInfo(info);
}
Object obj = pjp.proceed(); // 表示执行具体的Controller, 与过滤器 chain.doFilter(req, resp);一样
/**
* 在SpringMVC环境中, 如果需要获取 Request, 需要使用 RequestContextHolder; 对于登录来讲, 因为用户的目的是想拿token, 所以对于
* 登录来说, 头顶是没有token
*/
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
// 如果是登录,就直接到session中获取, 但是用户可能登录失败, session中没有任何的内容
if(method.getDeclaringClass() == LoginController.class) {
//拿的是刚刚登陆的session(loginController)
SysUser user = (SysUser)request.getSession().getAttribute("user-info");
if(null != user) { // 登录成功
pl.setUserId(user.getId());
}else { // 登录失败
pl.setProcessInfo("登录失败");
}
}else { // 非登录场景, 就需要通过请求头中的 Authorization 获取到 sessionId, 间接的获取到 session, 然后获取用户的id
String token = request.getHeader("Authorization"); // jsessionId
HttpSession session = SessionManager.getSession(token);
SysUser user = (SysUser) session.getAttribute("user-info");
pl.setUserId(user.getId());
}
// 采取多线程的方式, 其他线程的错误不会抛到主线程来
executorService.submit(() -> {
try {
processLogMapper.insert(pl);
}catch (Exception ex) {
ex.printStackTrace();
}
});
return obj;
}
}
使用自定义注解和aop对用户的行为记录进行存储
最新推荐文章于 2022-02-05 16:24:10 发布
![](https://img-home.csdnimg.cn/images/20240711042549.png)