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.    }    

    效果图

    用户操作:



     异常


  • 相关阅读:
    HDU 跑跑卡丁车
    螺旋模型
    原型模型
    CSS匹配规则参考
    索引调优
    动态加载外部css或js文件
    des算法的C#实现
    @@RowCount和“SET NOCOUNT ON”在触发器中使用的先后顺序引起的问题
    WebService生成XML文档时出错。不应是类型XXXX。使用XmlInclude或SoapInclude属性静态指定非已知的类型。
    Sql获取星期几的方法
  • 原文地址:https://www.cnblogs.com/ljdblog/p/5998199.html
Copyright © 2011-2022 走看看