zoukankan      html  css  js  c++  java
  • SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)

    文章来源http://itindex.net/detail/50710-springaop-controller-service

      首先我们为什么需要做日志管理,在现实的上线中我们经常会遇到系统出现异常或者问题。这个时候就马上打开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
     
    1. package com.annotation;    
    2.     
    3. import java.lang.annotation.*;    
    4.     
    5. /**  
    6.  *自定义注解 拦截Controller  
    7.  */    
    8.     
    9. @Target({ElementType.PARAMETER, ElementType.METHOD})    
    10. @Retention(RetentionPolicy.RUNTIME)    
    11. @Documented    
    12. public  @interface SystemControllerLog {    
    13.     
    14.     String description()  default "";    
    15.     
    16.     
    17. }    
    18.     
    19. package com.annotation;    
    20.     
    21. import java.lang.annotation.*;    
    22.     
    23. /**  
    24.  *自定义注解 拦截service  
    25.  */    
    26.     
    27. @Target({ElementType.PARAMETER, ElementType.METHOD})    
    28. @Retention(RetentionPolicy.RUNTIME)    
    29. @Documented    
    30. public  @interface SystemServiceLog {    
    31.     
    32.     String description()  default "";    
    33.     
    34.     
    35. }    

    第二步创建一个切点类:

    [java] view plain copy
     
    1. package com.annotation;    
    2.     
    3. import com.model.Log;    
    4. import com.model.User;    
    5. import com.service.LogService;    
    6. import com.util.DateUtil;    
    7. import com.util.JSONUtil;    
    8. import com.util.SpringContextHolder;    
    9. import com.util.WebConstants;    
    10. import org.aspectj.lang.JoinPoint;    
    11. import org.aspectj.lang.annotation.*;    
    12. import org.slf4j.Logger;    
    13. import org.slf4j.LoggerFactory;    
    14. import org.springframework.stereotype.Component;    
    15. import org.springframework.web.context.request.RequestContextHolder;    
    16. import org.springframework.web.context.request.ServletRequestAttributes;    
    17. import javax.annotation.Resource;    
    18. import javax.servlet.http.HttpServletRequest;    
    19. import javax.servlet.http.HttpSession;    
    20. import java.lang.reflect.Method;    
    21.     
    22. /**  
    23.  * 切点类  
    24.  * @author tiangai  
    25.  * @since 2014-08-05 Pm 20:35  
    26.  * @version 1.0  
    27.  */    
    28. @Aspect    
    29. @Component    
    30. public  class SystemLogAspect {    
    31.     //注入Service用于把日志保存数据库    
    32.     @Resource    
    33.      private LogService logService;    
    34.     //本地异常日志记录对象    
    35.      private  static  final Logger logger = LoggerFactory.getLogger(SystemLogAspect. class);    
    36.     
    37.     //Service层切点    
    38.     @Pointcut("@annotation(com.annotation.SystemServiceLog)")    
    39.      public  void serviceAspect() {    
    40.     }    
    41.     
    42.     //Controller层切点    
    43.     @Pointcut("@annotation(com.annotation.SystemControllerLog)")    
    44.      public  void controllerAspect() {    
    45.     }    
    46.     
    47.     /**  
    48.      * 前置通知 用于拦截Controller层记录用户的操作  
    49.      *  
    50.      * @param joinPoint 切点  
    51.      */    
    52.     @Before("controllerAspect()")    
    53.      public  void doBefore(JoinPoint joinPoint) {    
    54.     
    55.         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
    56.         HttpSession session = request.getSession();    
    57.         //读取session中的用户    
    58.         User user = (User) session.getAttribute(WebConstants.CURRENT_USER);    
    59.         //请求的IP    
    60.         String ip = request.getRemoteAddr();    
    61.          try {    
    62.             //*========控制台输出=========*//    
    63.             System.out.println("=====前置通知开始=====");    
    64.             System.out.println("请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
    65.             System.out.println("方法描述:" + getControllerMethodDescription(joinPoint));    
    66.             System.out.println("请求人:" + user.getName());    
    67.             System.out.println("请求IP:" + ip);    
    68.             //*========数据库日志=========*//    
    69.             Log log = SpringContextHolder.getBean("logxx");    
    70.             log.setDescription(getControllerMethodDescription(joinPoint));    
    71.             log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
    72.             log.setType("0");    
    73.             log.setRequestIp(ip);    
    74.             log.setExceptionCode( null);    
    75.             log.setExceptionDetail( null);    
    76.             log.setParams( null);    
    77.             log.setCreateBy(user);    
    78.             log.setCreateDate(DateUtil.getCurrentDate());    
    79.             //保存数据库    
    80.             logService.add(log);    
    81.             System.out.println("=====前置通知结束=====");    
    82.         }  catch (Exception e) {    
    83.             //记录本地异常日志    
    84.             logger.error("==前置通知异常==");    
    85.             logger.error("异常信息:{}", e.getMessage());    
    86.         }    
    87.     }    
    88.     
    89.     /**  
    90.      * 异常通知 用于拦截service层记录异常日志  
    91.      *  
    92.      * @param joinPoint  
    93.      * @param e  
    94.      */    
    95.     @AfterThrowing(pointcut = "serviceAspect()", throwing = "e")    
    96.      public  void doAfterThrowing(JoinPoint joinPoint, Throwable e) {    
    97.         HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();    
    98.         HttpSession session = request.getSession();    
    99.         //读取session中的用户    
    100.         User user = (User) session.getAttribute(WebConstants.CURRENT_USER);    
    101.         //获取请求ip    
    102.         String ip = request.getRemoteAddr();    
    103.         //获取用户请求方法的参数并序列化为JSON格式字符串    
    104.         String params = "";    
    105.          if (joinPoint.getArgs() !=  null && joinPoint.getArgs().length > 0) {    
    106.              for ( int i = 0; i < joinPoint.getArgs().length; i++) {    
    107.                 params += JSONUtil.toJsonString(joinPoint.getArgs()[i]) + ";";    
    108.             }    
    109.         }    
    110.          try {    
    111.               /*========控制台输出=========*/    
    112.             System.out.println("=====异常通知开始=====");    
    113.             System.out.println("异常代码:" + e.getClass().getName());    
    114.             System.out.println("异常信息:" + e.getMessage());    
    115.             System.out.println("异常方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
    116.             System.out.println("方法描述:" + getServiceMthodDescription(joinPoint));    
    117.             System.out.println("请求人:" + user.getName());    
    118.             System.out.println("请求IP:" + ip);    
    119.             System.out.println("请求参数:" + params);    
    120.                /*==========数据库日志=========*/    
    121.             Log log = SpringContextHolder.getBean("logxx");    
    122.             log.setDescription(getServiceMthodDescription(joinPoint));    
    123.             log.setExceptionCode(e.getClass().getName());    
    124.             log.setType("1");    
    125.             log.setExceptionDetail(e.getMessage());    
    126.             log.setMethod((joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));    
    127.             log.setParams(params);    
    128.             log.setCreateBy(user);    
    129.             log.setCreateDate(DateUtil.getCurrentDate());    
    130.             log.setRequestIp(ip);    
    131.             //保存数据库    
    132.             logService.add(log);    
    133.             System.out.println("=====异常通知结束=====");    
    134.         }  catch (Exception ex) {    
    135.             //记录本地异常日志    
    136.             logger.error("==异常通知异常==");    
    137.             logger.error("异常信息:{}", ex.getMessage());    
    138.         }    
    139.          /*==========记录本地异常日志==========*/    
    140.         logger.error("异常方法:{}异常代码:{}异常信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), e.getClass().getName(), e.getMessage(), params);    
    141.     
    142.     }    
    143.     
    144.     
    145.     /**  
    146.      * 获取注解中对方法的描述信息 用于service层注解  
    147.      *  
    148.      * @param joinPoint 切点  
    149.      * @return 方法描述  
    150.      * @throws Exception  
    151.      */    
    152.      public  static String getServiceMthodDescription(JoinPoint joinPoint)    
    153.              throws Exception {    
    154.         String targetName = joinPoint.getTarget().getClass().getName();    
    155.         String methodName = joinPoint.getSignature().getName();    
    156.         Object[] arguments = joinPoint.getArgs();    
    157.         Class targetClass = Class.forName(targetName);    
    158.         Method[] methods = targetClass.getMethods();    
    159.         String description = "";    
    160.          for (Method method : methods) {    
    161.              if (method.getName().equals(methodName)) {    
    162.                 Class[] clazzs = method.getParameterTypes();    
    163.                  if (clazzs.length == arguments.length) {    
    164.                     description = method.getAnnotation(SystemServiceLog. class).description();    
    165.                      break;    
    166.                 }    
    167.             }    
    168.         }    
    169.          return description;    
    170.     }    
    171.     
    172.     /**  
    173.      * 获取注解中对方法的描述信息 用于Controller层注解  
    174.      *  
    175.      * @param joinPoint 切点  
    176.      * @return 方法描述  
    177.      * @throws Exception  
    178.      */    
    179.      public  static String getControllerMethodDescription(JoinPoint joinPoint)  throws Exception {    
    180.         String targetName = joinPoint.getTarget().getClass().getName();    
    181.         String methodName = joinPoint.getSignature().getName();    
    182.         Object[] arguments = joinPoint.getArgs();    
    183.         Class targetClass = Class.forName(targetName);    
    184.         Method[] methods = targetClass.getMethods();    
    185.         String description = "";    
    186.          for (Method method : methods) {    
    187.              if (method.getName().equals(methodName)) {    
    188.                 Class[] clazzs = method.getParameterTypes();    
    189.                  if (clazzs.length == arguments.length) {    
    190.                     description = method.getAnnotation(SystemControllerLog. class).description();    
    191.                      break;    
    192.                 }    
    193.             }    
    194.         }    
    195.          return description;    
    196.     }    
    197. }    



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

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

    Xml代码 
    1. <!-- 启动对@AspectJ注解的支持 -->  
    2. <aop:aspectj-autoproxy/>  

     在调用Controller的时候AOP发挥作用所以在SpringMVC的配置文件里加上

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

     第四步使用

    Controller层的使用

    Java代码

    [java] view plain copy
     
    1. /**  
    2.     * 删除用户  
    3.     *  
    4.     * @param criteria 条件  
    5.     * @param id       id  
    6.     * @param model    模型  
    7.     * @return 数据列表  
    8.     */    
    9.    @RequestMapping(value = "/delete")    
    10.    //此处为记录AOP拦截Controller记录用户操作    
    11.    @SystemControllerLog(description = "删除用户")    
    12.     public String del(Criteria criteria, String id, Model model, HttpSession session) {    
    13.         try {    
    14.            User user = (User) session.getAttribute(WebConstants.CURRENT_USER);    
    15.             if ( null != user) {    
    16.                 if (user.getId().equals(id)) {    
    17.                    msg = "您不可以删除自己!";    
    18.                    criteria = userService.selectByCriteriaPagination(criteria);    
    19.                }  else {    
    20.                    //删除数据并查询出数据    
    21.                    criteria = userService.delete(id, criteria);    
    22.                    msg = "删除成功!";    
    23.                }    
    24.            }    
    25.        }  catch (Exception e) {    
    26.            msg = "删除失败!";    
    27.        }  finally {    
    28.            model.addAttribute("msg", msg);    
    29.            model.addAttribute("criteria", criteria);    
    30.        }    
    31.        //跳转列表页    
    32.         return "user/list";    
    33.    }    


     Service层的使用

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

    效果图

    用户操作:



     异常


  • 相关阅读:
    智器SmartQ T7实体店试用体验
    BI笔记之SSAS库Process的几种方案
    PowerTip of the Day from powershell.com上周汇总(八)
    PowerTip of the Day2010071420100716 summary
    PowerTip of the Day from powershell.com上周汇总(十)
    PowerTip of the Day from powershell.com上周汇总(六)
    重新整理Cellset转Datatable
    自动加密web.config配置节批处理
    与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable
    在VS2003中以ClassLibrary工程的方式管理Web工程.
  • 原文地址:https://www.cnblogs.com/ljdblog/p/5998199.html
Copyright © 2011-2022 走看看