使用自定义注解和aop对用户的行为记录进行存储

这篇博客详细介绍了如何使用Spring的AOP(面向切面编程)来实现方法执行的环绕通知,主要用于记录用户操作日志。内容包括创建线程池、处理参数、获取方法信息、插入日志数据库等步骤,并特别关注了文件上传和登录场景的日志处理。通过注解获取方法头顶的元信息,以及在多线程环境下确保日志记录的正确性。
摘要由CSDN通过智能技术生成
@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;
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值