`
stevenzuo
  • 浏览: 12526 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)

阅读更多

http://blog.csdn.net/czmchen/article/details/42392985

首先我们为什么需要做日志管理,在现实的上线中我们经常会遇到系统出现异常或者问题。这个时候就马上打开CRT或者SSH连上服务器拿日子来分析。受网络的各种限制。于是我们就想为什么不能直接在管理后台查看报错的信息呢。于是日志管理就出现了。

         其次个人觉得做日志管理最好的是Aop,有的人也喜欢用拦截器。都可以,在此我重点介绍我的实现方式。

         Aop有的人说拦截不到Controller。有的人说想拦AnnotationMethodHandlerAdapter截到Controller必须得拦截org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter。

首先Aop可以拦截到Controller的,这个是毋容置疑的其次须拦截AnnotationMethodHandlerAdapter也不是必须的。最起码我没有验证成功过这个。我的spring版本是4.0.3。

         Aop之所以有的人说拦截不到Controller是因为Controller被jdk代理了。我们只要把它交给cglib代理就可以了。

第一步定义两个注解:


[java] view plain copy
package com.annotation;   
   
import java.lang.annotation.*;   
   
/** 
*自定义注解 拦截Controller 
*/   
   
@Target({ElementType.PARAMETER, ElementType.METHOD})   
@Retention(RetentionPolicy.RUNTIME)   
@Documented   
public  @interface SystemControllerLog {   
   
    String description()  default "";   
   
   
}   
   
package com.annotation;   
   
import java.lang.annotation.*;   
   
/** 
*自定义注解 拦截service 
*/   
   
@Target({ElementType.PARAMETER, ElementType.METHOD})   
@Retention(RetentionPolicy.RUNTIME)   
@Documented   
public  @interface SystemServiceLog {   
   
    String description()  default "";   
   
   
}   



第二步创建一个切点类:

[java] view plain copy
package com.annotation;   
   
import com.model.Log;   
import com.model.User;   
import com.service.LogService;   
import com.util.DateUtil;   
import com.util.JSONUtil;   
import com.util.SpringContextHolder;   
import com.util.WebConstants;   
import org.aspectj.lang.JoinPoint;   
import org.aspectj.lang.annotation.*;   
import org.slf4j.Logger;   
import org.slf4j.LoggerFactory;   
import org.springframework.stereotype.Component;   
import org.springframework.web.context.request.RequestContextHolder;   
import org.springframework.web.context.request.ServletRequestAttributes;   
import javax.annotation.Resource;   
import javax.servlet.http.HttpServletRequest;   
import javax.servlet.http.HttpSession;   
import java.lang.reflect.Method;   
   
/** 
* 切点类 
* @author tiangai 
* @since 2014-08-05 Pm 20:35 
* @version 1.0 
*/   
@Aspect   
@Component   
public  class SystemLogAspect {   
    //注入Service用于把日志保存数据库   
    @Resource   
     private LogService logService;   
    //本地异常日志记录对象   
     private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);   
   
    //Service层切点   
    @Pointcut("@annotation(com.annotation.SystemServiceLog)")   
     public  void serviceAspect() {   
    }   
   
    //Controller层切点   
    @Pointcut("@annotation(com.annotation.SystemControllerLog)")   
     public  void controllerAspect() {   
    }   
   
    /** 
     * 前置通知 用于拦截Controller层记录用户的操作 
     * 
     * @param joinPoint 切点 
     */   
    @Before("controllerAspect()")   
     public  void doBefore(JoinPoint joinPoint) {   
   
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();   
        HttpSession session = request.getSession();   
        //读取session中的用户   
        User user = (User) session.getAttribute(WebConstants.CURRENT_USER);   
        //请求的IP   
        String ip = request.getRemoteAddr();   
         try {   
            //*========控制台输出=========*//   
            System.out.println("=====前置通知开始=====");   
            System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));   
            System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));   
            System.out.println("请求人:" + user.getName());   
            System.out.println("请求IP:" + ip);   
            //*========数据库日志=========*//   
            Log log = SpringContextHolder.getBean("logxx");   
            log.setDescription(getControllerMethodDescription(joinPoint));   
            log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));   
            log.setType("0");   
            log.setRequestIp(ip);   
            log.setExceptionCode( null);   
            log.setExceptionDetail( null);   
            log.setParams( null);   
            log.setCreateBy(user);   
            log.setCreateDate(DateUtil.getCurrentDate());   
            //保存数据库   
            logService.add(log);   
            System.out.println("=====前置通知结束=====");   
        }  catch (Exception e) {   
            //记录本地异常日志   
            logger.error("==前置通知异常==");   
            logger.error("异常信息:{}", e.getMessage());   
        }   
    }   
   
    /** 
     * 异常通知 用于拦截service层记录异常日志 
     * 
     * @param joinPoint 
     * @param e 
     */   
    @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")   
     public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {   
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();   
        HttpSession session = request.getSession();   
        //读取session中的用户   
        User user = (User) session.getAttribute(WebConstants.CURRENT_USER);   
        //获取请求ip   
        String ip = request.getRemoteAddr();   
        //获取用户请求方法的参数并序列化为JSON格式字符串   
        String params = "";   
         if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {   
             for ( int i = 0; i < joinPoint.getArgs().length; i++) {   
                params += JSONUtil.toJsonString(joinPoint.getArgs()[i]) + ";";   
            }   
        }   
         try {   
              /*========控制台输出=========*/   
            System.out.println("=====异常通知开始=====");   
            System.out.println("异常代码:" + e.getClass().getName());   
            System.out.println("异常信息:" + e.getMessage());   
            System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));   
            System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));   
            System.out.println("请求人:" + user.getName());   
            System.out.println("请求IP:" + ip);   
            System.out.println("请求参数:" + params);   
               /*==========数据库日志=========*/   
            Log log = SpringContextHolder.getBean("logxx");   
            log.setDescription(getServiceMthodDescription(joinPoint));   
            log.setExceptionCode(e.getClass().getName());   
            log.setType("1");   
            log.setExceptionDetail(e.getMessage());   
            log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));   
            log.setParams(params);   
            log.setCreateBy(user);   
            log.setCreateDate(DateUtil.getCurrentDate());   
            log.setRequestIp(ip);   
            //保存数据库   
            logService.add(log);   
            System.out.println("=====异常通知结束=====");   
        }  catch (Exception ex) {   
            //记录本地异常日志   
            logger.error("==异常通知异常==");   
            logger.error("异常信息:{}", ex.getMessage());   
        }   
         /*==========记录本地异常日志==========*/   
        logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);   
   
    }   
   
   
    /** 
     * 获取注解中对方法的描述信息 用于service层注解 
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */   
     public  static String getServiceMthodDescription(JoinPoint joinPoint)   
             throws Exception {   
        String targetName = joinPoint.getTarget().getClass().getName();   
        String methodName = joinPoint.getSignature().getName();   
        Object[] arguments = joinPoint.getArgs();   
        Class targetClass = Class.forName(targetName);   
        Method[] methods = targetClass.getMethods();   
        String description = "";   
         for (Method method : methods) {   
             if (method.getName().equals(methodName)) {   
                Class[] clazzs = method.getParameterTypes();   
                 if (clazzs.length == arguments.length) {   
                    description = method.getAnnotation(SystemServiceLog. class).description();   
                     break;   
                }   
            }   
        }   
         return description;   
    }   
   
    /** 
     * 获取注解中对方法的描述信息 用于Controller层注解 
     * 
     * @param joinPoint 切点 
     * @return 方法描述 
     * @throws Exception 
     */   
     public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {   
        String targetName = joinPoint.getTarget().getClass().getName();   
        String methodName = joinPoint.getSignature().getName();   
        Object[] arguments = joinPoint.getArgs();   
        Class targetClass = Class.forName(targetName);   
        Method[] methods = targetClass.getMethods();   
        String description = "";   
         for (Method method : methods) {   
             if (method.getName().equals(methodName)) {   
                Class[] clazzs = method.getParameterTypes();   
                 if (clazzs.length == arguments.length) {   
                    description = method.getAnnotation(SystemControllerLog. class).description();   
                     break;   
                }   
            }   
        }   
         return description;   
    }   
}   


第三步把Controller的代理权交给cglib


在实例化ApplicationContext的时候需要加上




Xml代码
<!-- 启动对@AspectJ注解的支持 --> 
<aop:aspectj-autoproxy/> 
在调用Controller的时候AOP发挥作用所以在SpringMVC的配置文件里加上


Xml代码
<!--通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller-> 
<aop:aspectj-autoproxy proxy-target-class="true" /> 
第四步使用



Controller层的使用

Java代码

[java] view plain copy
/** 
    * 删除用户 
    * 
    * @param criteria 条件 
    * @param id       id 
    * @param model    模型 
    * @return 数据列表 
    */   
   @RequestMapping(value = "/delete")   
   //此处为记录AOP拦截Controller记录用户操作   
   @SystemControllerLog(description = "删除用户")   
    public String del(Criteria criteria, String id, Model model, HttpSession session) {   
        try {   
           User user = (User) session.getAttribute(WebConstants.CURRENT_USER);   
            if ( null != user) {   
                if (user.getId().equals(id)) {   
                   msg = "您不可以删除自己!";   
                   criteria = userService.selectByCriteriaPagination(criteria);   
               }  else {   
                   //删除数据并查询出数据   
                   criteria = userService.delete(id, criteria);   
                   msg = "删除成功!";   
               }   
           }   
       }  catch (Exception e) {   
           msg = "删除失败!";   
       }  finally {   
           model.addAttribute("msg", msg);   
           model.addAttribute("criteria", criteria);   
       }   
       //跳转列表页   
        return "user/list";   
   }   

Service层的使用



[java] view plain copy 在CODE上查看代码片派生到我的代码片
/** 
    * 按照分页查询 
    * @param criteria 
    * @return 
    */   
   //此处为AOP拦截Service记录异常信息。方法不需要加try-catch   
   @SystemServiceLog(description = "查询用户")   
    public Criteria<User> selectByCriteriaPagination(Criteria<User> criteria)   
   {   
       criteria.getList().get(0).getAccount();   
       //查询总数   
        long total=userMapper.countByCriteria(criteria);   
       //设置总数   
       criteria.setRowCount(total);   
       criteria.setList(userMapper.selectByCriteriaPagination(criteria));   
        return  criteria;   
   }   




效果图



用户操作:



异常







文章来源http://itindex.net/detail/50710-springaop-controller-service
分享到:
评论

相关推荐

    springMVC AOP拦截拦截Controller等实现日志管理

    通过这种方式,我们可以在Spring MVC中利用AOP实现对Controller方法的透明日志管理,不仅记录正常流程,也能捕获和记录异常,提升系统的可维护性和问题排查效率。 在实际项目中,我们可以根据需求进一步定制日志...

    Spring Mvc AOP通过注解方式拦截controller等实现日志管理

    本教程将详细介绍如何利用注解来配置和使用AOP来拦截Controller层的方法,以便记录执行过程中的相关信息,实现日志管理。 一、Spring AOP基础 AOP是Spring框架的核心组件之一,它允许程序员定义“切面”,这些切面...

    springaop拦截controller日志

    "springaop拦截controller日志"这个主题旨在讲解如何使用Spring AOP来拦截Controller层的方法调用,并在方法执行前后记录相关日志。 首先,了解Spring AOP的基本概念。AOP是一种编程范式,它允许程序员定义“切面”...

    Spring MVC AOP通过注解方式拦截Controller等实现日志管理demo版本2

    本项目"Spring MVC AOP通过注解方式拦截Controller等实现日志管理demo版本2"是基于注解的AOP实践,旨在帮助开发者了解如何利用AOP来记录应用程序中的关键操作日志。以下是关于这个主题的详细解释: 1. **Spring AOP...

    springboot spring aop 拦截器注解方式实现脱敏

    总结一下,通过上述步骤,我们已经在Spring Boot应用中利用Spring AOP和注解方式实现了数据脱敏。这个拦截器可以在不修改原有业务代码的情况下,确保敏感信息在响应给客户端之前得到处理,提高了应用的安全性。同时...

    spring MVC AOP注解方式如何拦截controller 例子

    本文将详细介绍如何使用AspectJ注解在Spring MVC中实现AOP拦截Controller方法,并提供一个具体的例子。 首先,我们需要了解Spring AOP的基础概念。AOP允许我们定义“切面”,这些切面包含了业务逻辑中横切关注点的...

    spring aop切面拦截指定类和方法实现流程日志跟踪

    本节将详细介绍如何使用Spring AOP实现流程日志跟踪,主要关注于如何通过AOP拦截特定的类和方法来进行日志记录。 ##### 3.1 配置Spring AOP 在Spring配置文件中定义切面和切入点表达式是非常关键的一步。一般来说...

    spring aop 拦截日志示例

    通过以上步骤,我们就完成了使用Spring AOP拦截并记录系统操作日志和异常日志的过程。在实际项目中,可以根据需求调整切点表达式,优化日志格式,以及对日志进行分类和分级存储。这样的设计使得日志管理变得灵活且...

    spring aop日志拦截

    总结来说,Spring AOP为我们提供了一种优雅的方式来实现controller层的日志拦截。通过定义切面和通知,我们可以轻松地在方法执行前后插入日志记录,而不必在每个controller方法内部编写重复的代码。这种面向切面的...

    对spring aop 各个组件进行实现

    自定义注解是Spring AOP中实现切面逻辑的一种方式。例如,我们可以创建一个名为`@LogExecutionTime`的注解,用来记录方法的执行时间。首先,定义注解: ```java @Retention(RetentionPolicy.RUNTIME) @Target...

    springboot工程自定义response注解、自定义规范化返回数据结构

    本主题将深入探讨如何在Spring Boot工程中通过自定义response注解、利用Java反射机制、设置自定义拦截器以及实现WebMvcConfigurer接口来实现这一目标。 首先,我们来看自定义response注解。在Spring Boot中,可以...

    AOP拦截日志JAVA

    Java AOP(面向切面编程)是一种编程范式,它允许程序员定义“切面”,这些切面封装了特定关注点的代码,如日志...这就是"AOP拦截日志JAVA"的核心内容,它利用了Spring AOP的强大功能,让日志管理变得更加简单和高效。

    spring自定义注解实现拦截器的实现方法

    在Spring框架中,自定义注解结合AOP(面向切面编程)是实现业务逻辑与非业务逻辑分离的一种有效方式。通过自定义注解,可以针对不同的业务场景灵活地添加功能,比如权限控制、日志记录、事务管理等。本文将详细讨论...

    Spring AOP实例

    9. **自动代理(Auto-proxying)**:Spring可以在扫描bean定义时自动检测带有特定注解的类并创建对应的代理对象,如`@Component`、`@Service`、`@Repository`和`@Controller`。 在`Spring052`这个压缩包中,可能...

    Spring注解和扫包自定义注解和自动扫包.rar

    Spring还提供了AOP(面向切面编程)的支持,使得可以通过`@Aspect`、`@Pointcut`、`@Before`、`@After`等注解来关联自定义注解和切面处理逻辑,实现类似注解触发的方法拦截。 关于Mybatis,虽然它主要关注SQL映射和...

    详解SpringBoot AOP 拦截器(Aspect注解方式)

    在 SpringBoot 项目中,AspectJ 是一种常用的 AOP 实现方式,通过使用 AspectJ 注解,可以轻松地实现方法拦截和增强。下面将详细介绍 SpringBoot AOP 拦截器的实现方式。 一、 Filter、HandlerInterceptor 和 ...

    Spring Boot Aspect 切面 AOP 拦截器 Interceptor 监控control请求耗时

    在Spring Boot应用中,面向切面编程(AOP)是一种强大的设计模式,它允许我们以声明式的方式插入代码,比如日志记录、事务管理或权限检查。Aspect是AOP的核心概念,它封装了关注点,使得我们可以将这些关注点与业务...

    struts2+spring aop demo

    在"struts2+spring aop demo"这个项目中,我们将探讨如何结合这两个框架,利用Spring的AOP功能来记录操作日志,特别是涉及自定义参数的AOP例子。 首先,让我们了解AOP的概念。面向切面编程(Aspect Oriented ...

    spring中注解的实现原理

    总结来说,Spring中注解的实现原理涉及到元注解的定义、注解处理器的运行、BeanDefinition的生成以及AOP和事务管理的注解处理。这些机制使得Spring能够在不依赖XML的情况下,提供灵活、高效且易于维护的框架功能。...

    springmvc log4j2 logback 注解 jackson 日志脱敏实现源码

    本资源包含的是关于`SpringMVC`、`Log4j2`、`Logback`以及`Jackson`的日志脱敏实现源码,提供了多种实现方式,旨在帮助开发者在保障信息安全的同时,充分利用日志进行系统分析。 1. **基于正则表达式的日志脱敏实现...

Global site tag (gtag.js) - Google Analytics