AOP日志管理

来源:互联网 发布:淘宝客户分类管理 编辑:程序博客网 时间:2024/06/06 03:26

 

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是因为Controllerjdk代理了。我们只要把它交给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

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

 

 

原创粉丝点击