做日志管理最好的是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代码 

1. package com.annotation;  
2. import java.lang.annotation.*;  
3. /** 
4.  *自定义注解 拦截Controller 
5.  */  
6. @Target({ElementType.PARAMETER, ElementType.METHOD})  
7. @Retention(RetentionPolicy.RUNTIME)  
8. @Documented  
9. public  @interface SystemControllerLog {  
10.     String description()  default ”";  
11. }
1. package com.annotation;  
2. import java.lang.annotation.*;  
3. /** 
4.  *自定义注解 拦截service 
5.  */  
6. @Target({ElementType.PARAMETER, ElementType.METHOD})  
7. @Retention(RetentionPolicy.RUNTIME)  
8. @Documented  
9. public  @interface SystemServiceLog {  
10.     String description()  default ”";  
11. }

 第二步创建一个切点类:

Java代码 

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

第三步把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代码 

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层的使用

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