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