美文网首页
Spring Aop实战应用

Spring Aop实战应用

作者: 进击的三文鱼 | 来源:发表于2021-04-30 13:53 被阅读0次

    一 场景

    记录操作日志

    二 代码实现

    1 切面类

    /**
     * 操作日志记录处理
     * 
     * @author ruoyi
     */
    @Aspect
    @Component
    public class LogAspect
    {
        private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
    
        // 配置织入点
        @Pointcut("@annotation(com.sunisco.external.portal.common.annotation.Log)")
        public void logPointCut()
        {
        }
    
        /**
         * 处理完请求后执行
         *
         * @param joinPoint 切点
         */
        @AfterReturning(pointcut = "logPointCut()")
        public void doAfterReturning(JoinPoint joinPoint)
        {
            handleLog(joinPoint, null);
        }
    
        /**
         * 拦截异常操作
         * 
         * @param joinPoint 切点
         * @param e 异常
         */
        @AfterThrowing(value = "logPointCut()", throwing = "e")
        public void doAfterThrowing(JoinPoint joinPoint, Exception e)
        {
            handleLog(joinPoint, e);
        }
    
        protected void handleLog(final JoinPoint joinPoint, final Exception e)
        {
            try
            {
                // 获得注解
                Log controllerLog = getAnnotationLog(joinPoint);
                if (controllerLog == null)
                {
                    return;
                }
    
                // 获取当前的用户
                SysUser currentUser =new SysUser();
    
                // *========数据库日志=========*//
                SysOperLog operLog = new SysOperLog();
                operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
                // 请求的地址
                String ip = "";
                operLog.setOperIp(ip);
    
                operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
                if (currentUser != null)
                {
                    operLog.setOperName(currentUser.getLoginName());
                    if (StringUtils.isNotNull(currentUser.getDept())
                            && StringUtils.isNotEmpty(currentUser.getDept().getDeptName()))
                    {
                        operLog.setDeptName(currentUser.getDept().getDeptName());
                    }
                }
    
                if (e != null)
                {
                    operLog.setStatus(BusinessStatus.FAIL.ordinal());
                    operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
                }
                // 设置方法名称
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = joinPoint.getSignature().getName();
                operLog.setMethod(className + "." + methodName + "()");
                // 处理设置注解上的参数
                getControllerMethodDescription(controllerLog, operLog);
                // 保存数据库
                AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
            }
            catch (Exception exp)
            {
                // 记录本地异常日志
                log.error("==前置通知异常==");
                log.error("异常信息:{}", exp.getMessage(),exp);
            }
        }
    
        /**
         * 获取注解中对方法的描述信息 用于Controller层注解
         * 
         * @param log 日志
         * @param operLog 操作日志
         * @throws Exception
         */
        public void getControllerMethodDescription(Log log, SysOperLog operLog) throws Exception
        {
            // 设置action动作
            operLog.setBusinessType(log.businessType().ordinal());
            // 设置标题
            operLog.setTitle(log.title());
            // 设置操作人类别
            operLog.setOperatorType(log.operatorType().ordinal());
            // 是否需要保存request,参数和值
            if (log.isSaveRequestData())
            {
                // 获取参数的信息,传入到数据库中。
                setRequestValue(operLog);
            }
        }
    
        /**
         * 获取请求的参数,放到log中
         * 
         * @param operLog 操作日志
         * @throws Exception 异常
         */
        private void setRequestValue(SysOperLog operLog) throws Exception
        {
            Map<String, String[]> map = ServletUtils.getRequest().getParameterMap();
            String params = JSON.marshal(map);
            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
        }
    
        /**
         * 是否存在注解,如果存在就获取
         */
        private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
        {
            Signature signature = joinPoint.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            Method method = methodSignature.getMethod();
    
            if (method != null)
            {
                return method.getAnnotation(Log.class);
            }
            return null;
        }
    }
    

    2 配置监控的自定义注解

    /**
     * 自定义操作日志记录注解
     * 
     * @author ruoyi
     */
    @Target({ ElementType.PARAMETER, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Log
    {
        /**
         * 模块 
         */
        public String title() default "";
    
        /**
         * 功能
         */
        public BusinessType businessType() default BusinessType.OTHER;
    
        /**
         * 操作人类别
         */
        public OperatorType operatorType() default OperatorType.MANAGE;
    
        /**
         * 是否保存请求的参数
         */
        public boolean isSaveRequestData() default true;
    }
    

    3 为要增加日志的方法添加自定义注解

      /**
         * 删除菜单
         */
        @Log(title = "菜单管理", businessType = BusinessType.DELETE)
        @GetMapping("/remove/{menuId}")
        @ResponseBody
        public AjaxResult remove(@PathVariable("menuId") String menuId) {
            if (menuService.selectCountMenuByParentId(menuId) > 0) {
                return AjaxResult.warn("存在子菜单,不允许删除");
            }
            if (menuService.selectCountRoleMenuByMenuId(menuId) > 0) {
                return AjaxResult.warn("菜单已分配,不允许删除");
            }
            return toAjax(menuService.deleteMenuById(menuId));
        }
    

    4 开启AOP

    /**
     * 程序注解配置
     *
     */
    @Configuration
    // 表示通过aop框架暴露该代理对象,AopContext能够访问
    @EnableAspectJAutoProxy(exposeProxy = true)
    public class ApplicationConfig
    {
    
    }
    

    三 参数讲解

    1 @Aspect 指定切面类

    2 @Pointcut 公共切入点表达式,可以是一个类中的一个方法,现在写成了注解更加灵活

    3 JoinPoint: 作为函数的参数传入切面方法,可以得到目标方法的相关信息

    4 @EnableAspectJAutoProxy : 开启基于注解的AOP模式

    5 通知方法

    前置通知(@Before)
    后置通知(@After)
    返回通知 (@AfterReturning)
    异常通知 (@AfterThrowing)
    环绕通知 (@Around)

    相关文章

      网友评论

          本文标题:Spring Aop实战应用

          本文链接:https://www.haomeiwen.com/subject/hhpnrltx.html