Spring MVC AOP通过自定义注解方式拦截Controller等实现日志管理

客官°小女子只卖身不卖艺 2022-06-06 10:08 228阅读 0赞

之前一直写.net,没玩过spring,一直没用过aop(面向切面编程)这类功能,当然不是说.net里面没有这类框架,企业库就可以微软企业库官网

开始上代码:

注解定义

  1. package com.jiankunking.common;
  2. import java.lang.annotation.*;
  3. /** * @author jiankunking * @Date: 2016/8/15 * @Time: 11:09 * @annotation OperationLogger */
  4. @Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取
  5. @Target(ElementType.METHOD)//目标是方法
  6. @Documented//文档生成时,该注解将被包含在javadoc中,可去掉
  7. public @interface OperationLogger {
  8. /** * 模块名字 */
  9. String modelName() default "";
  10. /** * 操作类型 */
  11. String option();
  12. }
  13. 1
  14. 2
  15. 3
  16. 4
  17. 5
  18. 6
  19. 7
  20. 8
  21. 9
  22. 10
  23. 11
  24. 12
  25. 13
  26. 14
  27. 15
  28. 16
  29. 17
  30. 18
  31. 19
  32. 20
  33. 21
  34. 22
  35. 23
  36. 24
  37. 25
  38. 26

@interface是用来自定义注释类型的。
注释的声明用@符号后面跟上这个注释类型的名字,再后面跟上括号,括号中列出这个注释中元 素/方法的key-value对。值必须是常量。

AOP拦截部分

  1. package com.jiankunking.common;
  2. import org.apache.log4j.Logger;
  3. import org.aspectj.lang.JoinPoint;
  4. import org.aspectj.lang.ProceedingJoinPoint;
  5. import org.aspectj.lang.Signature;
  6. import org.aspectj.lang.annotation.*;
  7. import org.aspectj.lang.reflect.MethodSignature;
  8. import org.springframework.stereotype.Component;
  9. import java.lang.reflect.Method;
  10. /** * @author jiankunking * @Date: 2016/8/15 * @Time: 11:11 * @annotation SysLogAspect */
  11. @Aspect
  12. @Component
  13. public class SysLogAspect {
  14. private static final Logger logger = Logger.getLogger(SysLogAspect.class);
  15. /** * 定义Pointcut,Pointcut的名称,此方法不能有返回值,该方法只是一个标示 */
  16. @Pointcut("@annotation(com.jiankunking.common.OperationLogger)")
  17. public void controllerAspect()
  18. {
  19. System.out.println("我是一个切入点");
  20. }
  21. /** * 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。 * @param joinPoint */
  22. @Before("controllerAspect()")
  23. public void doBefore(JoinPoint joinPoint)
  24. {
  25. System.out.println("=====SysLogAspect前置通知开始=====");
  26. //handleLog(joinPoint, null);
  27. }
  28. /** * 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 * @param joinPoint */
  29. @AfterReturning(pointcut = "controllerAspect()")
  30. public void doAfter(JoinPoint joinPoint)
  31. {
  32. System.out.println("=====SysLogAspect后置通知开始=====");
  33. //handleLog(joinPoint, null);
  34. }
  35. /** * 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 * @param joinPoint * @param e */
  36. @AfterThrowing(value = "controllerAspect()", throwing = "e")
  37. public void doAfter(JoinPoint joinPoint, Exception e)
  38. {
  39. System.out.println("=====SysLogAspect异常通知开始=====");
  40. //handleLog(joinPoint, e);
  41. }
  42. /** * 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。 * @param joinPoint */
  43. @Around("controllerAspect()")
  44. public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable
  45. {
  46. System.out.println("=====SysLogAspect 环绕通知开始=====");
  47. //handleLog(joinPoint, null);
  48. Object obj= joinPoint.proceed();
  49. System.out.println("=====SysLogAspect 环绕通知结束=====");
  50. return obj;
  51. }
  52. /** * 日志处理 * * @param joinPoint * @param e */
  53. private void handleLog(JoinPoint joinPoint, Exception e)
  54. {
  55. try
  56. {
  57. //获得注解
  58. OperationLogger logger = giveController(joinPoint);
  59. if (logger == null)
  60. {
  61. return;
  62. }
  63. String signature = joinPoint.getSignature().toString(); // 获取目标方法签名
  64. String methodName = signature.substring(signature.lastIndexOf(".") + 1,
  65. signature.indexOf("("));
  66. String longTemp = joinPoint.getStaticPart().toLongString();
  67. String classType = joinPoint.getTarget().getClass().getName();
  68. Class<?> clazz = Class.forName(classType);
  69. Method[] methods = clazz.getDeclaredMethods();
  70. System.out.println("methodName: " + methodName);
  71. for (Method method : methods)
  72. {
  73. if (method.isAnnotationPresent(OperationLogger.class)
  74. && method.getName().equals(methodName))
  75. {
  76. //OpLogger logger = method.getAnnotation(OpLogger.class);
  77. String clazzName = clazz.getName();
  78. System.out.println("clazzName: " + clazzName + ", methodName: "
  79. + methodName);
  80. }
  81. }
  82. } catch (Exception exp)
  83. {
  84. logger.error("异常信息:{}", exp);
  85. exp.printStackTrace();
  86. }
  87. }
  88. /** * 获得注解 * @param joinPoint * @return * @throws Exception */
  89. private static OperationLogger giveController(JoinPoint joinPoint) throws Exception
  90. {
  91. Signature signature = joinPoint.getSignature();
  92. MethodSignature methodSignature = (MethodSignature) signature;
  93. Method method = methodSignature.getMethod();
  94. if (method != null)
  95. {
  96. return method.getAnnotation(OperationLogger.class);
  97. }
  98. return null;
  99. }
  100. }
  101. 1
  102. 2
  103. 3
  104. 4
  105. 5
  106. 6
  107. 7
  108. 8
  109. 9
  110. 10
  111. 11
  112. 12
  113. 13
  114. 14
  115. 15
  116. 16
  117. 17
  118. 18
  119. 19
  120. 20
  121. 21
  122. 22
  123. 23
  124. 24
  125. 25
  126. 26
  127. 27
  128. 28
  129. 29
  130. 30
  131. 31
  132. 32
  133. 33
  134. 34
  135. 35
  136. 36
  137. 37
  138. 38
  139. 39
  140. 40
  141. 41
  142. 42
  143. 43
  144. 44
  145. 45
  146. 46
  147. 47
  148. 48
  149. 49
  150. 50
  151. 51
  152. 52
  153. 53
  154. 54
  155. 55
  156. 56
  157. 57
  158. 58
  159. 59
  160. 60
  161. 61
  162. 62
  163. 63
  164. 64
  165. 65
  166. 66
  167. 67
  168. 68
  169. 69
  170. 70
  171. 71
  172. 72
  173. 73
  174. 74
  175. 75
  176. 76
  177. 77
  178. 78
  179. 79
  180. 80
  181. 81
  182. 82
  183. 83
  184. 84
  185. 85
  186. 86
  187. 87
  188. 88
  189. 89
  190. 90
  191. 91
  192. 92
  193. 93
  194. 94
  195. 95
  196. 96
  197. 97
  198. 98
  199. 99
  200. 100
  201. 101
  202. 102
  203. 103
  204. 104
  205. 105
  206. 106
  207. 107
  208. 108
  209. 109
  210. 110
  211. 111
  212. 112
  213. 113
  214. 114
  215. 115
  216. 116
  217. 117
  218. 118
  219. 119
  220. 120
  221. 121
  222. 122
  223. 123
  224. 124
  225. 125
  226. 126
  227. 127
  228. 128
  229. 129
  230. 130
  231. 131
  232. 132
  233. 133
  234. 134
  235. 135
  236. 136
  237. 137
  238. 138
  239. 139
  240. 140
  241. 141
  242. 142
  243. 143
  244. 144
  245. 145
  246. 146
  247. 147
  248. 148
  249. 149
  250. 150

Aspect通常用于将必要的但和业务无关的逻辑和业务逻辑分离。

Spring使用的AOP注解分为三个层次:
前提条件是在xml中放开了

  1. <!-- 开启切面编程功能 -->
  2. <aop:aspectj-autoproxy proxy-target-class="true"/>
  3. 1
  4. 2
  1. @Aspect放在类头上,把这个类作为一个切面。
  2. @Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。
  3. 5种通知。
  1. 1. @Before,前置通知,放在方法头上。
  2. 2. @After,后置【finally】通知,放在方法头上。
  3. 3. @AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
  4. 4. @AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
  5. 5. @Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。

在Maven中加入以下以依赖

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>com.mkyong.common</groupId>
  4. <artifactId>spring-mvc-log4j</artifactId>
  5. <packaging>war</packaging>
  6. <version>1.0-SNAPSHOT</version>
  7. <name>SpringMVC + Log4j</name>
  8. <properties>
  9. <jdk.version>1.7</jdk.version>
  10. <spring.version>4.3.2.RELEASE</spring.version>
  11. <log4j.version>2.6.2</log4j.version>
  12. <jstl.version>1.2</jstl.version>
  13. <servletapi.version>3.1.0</servletapi.version>
  14. <org.aspectj-version>1.7.4</org.aspectj-version>
  15. <cglib.version>3.1</cglib.version>
  16. </properties>
  17. <dependencies>
  18. <dependency>
  19. <groupId>org.springframework</groupId>
  20. <artifactId>spring-webmvc</artifactId>
  21. <version>${spring.version}</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework</groupId>
  25. <artifactId>spring-aop</artifactId>
  26. <version>${spring.version}</version>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework</groupId>
  30. <artifactId>spring-aspects</artifactId>
  31. <version>${spring.version}</version>
  32. </dependency>
  33. <!-- Log4j start-->
  34. <dependency>
  35. <groupId>org.apache.logging.log4j</groupId>
  36. <artifactId>log4j-api</artifactId>
  37. <version>${log4j.version}</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.apache.logging.log4j</groupId>
  41. <artifactId>log4j-core</artifactId>
  42. <version>${log4j.version}</version>
  43. </dependency>
  44. <!-- Log4j end-->
  45. <!-- jstl -->
  46. <dependency>
  47. <groupId>jstl</groupId>
  48. <artifactId>jstl</artifactId>
  49. <version>${jstl.version}</version>
  50. </dependency>
  51. <dependency>
  52. <groupId>javax.servlet</groupId>
  53. <artifactId>javax.servlet-api</artifactId>
  54. <version>${servletapi.version}</version>
  55. <scope>provided</scope>
  56. </dependency>
  57. <dependency>
  58. <groupId>log4j</groupId>
  59. <artifactId>log4j</artifactId>
  60. <version>1.2.17</version>
  61. </dependency>
  62. <!-- AspectJ -->
  63. <dependency>
  64. <groupId>org.aspectj</groupId>
  65. <artifactId>aspectjrt</artifactId>
  66. <version>${org.aspectj-version}</version>
  67. </dependency>
  68. <!-- @Inject -->
  69. <dependency>
  70. <groupId>javax.inject</groupId>
  71. <artifactId>javax.inject</artifactId>
  72. <version>1</version>
  73. </dependency>
  74. <dependency>
  75. <groupId>cglib</groupId>
  76. <artifactId>cglib</artifactId>
  77. <version>${cglib.version}</version>
  78. </dependency>
  79. </dependencies>
  80. <build>
  81. <plugins>
  82. <plugin>
  83. <groupId>org.apache.maven.plugins</groupId>
  84. <artifactId>maven-compiler-plugin</artifactId>
  85. <version>3.3</version>
  86. <configuration>
  87. <source>${jdk.version}</source>
  88. <target>${jdk.version}</target>
  89. </configuration>
  90. </plugin>
  91. </plugins>
  92. </build>
  93. </project>
  94. 1
  95. 2
  96. 3
  97. 4
  98. 5
  99. 6
  100. 7
  101. 8
  102. 9
  103. 10
  104. 11
  105. 12
  106. 13
  107. 14
  108. 15
  109. 16
  110. 17
  111. 18
  112. 19
  113. 20
  114. 21
  115. 22
  116. 23
  117. 24
  118. 25
  119. 26
  120. 27
  121. 28
  122. 29
  123. 30
  124. 31
  125. 32
  126. 33
  127. 34
  128. 35
  129. 36
  130. 37
  131. 38
  132. 39
  133. 40
  134. 41
  135. 42
  136. 43
  137. 44
  138. 45
  139. 46
  140. 47
  141. 48
  142. 49
  143. 50
  144. 51
  145. 52
  146. 53
  147. 54
  148. 55
  149. 56
  150. 57
  151. 58
  152. 59
  153. 60
  154. 61
  155. 62
  156. 63
  157. 64
  158. 65
  159. 66
  160. 67
  161. 68
  162. 69
  163. 70
  164. 71
  165. 72
  166. 73
  167. 74
  168. 75
  169. 76
  170. 77
  171. 78
  172. 79
  173. 80
  174. 81
  175. 82
  176. 83
  177. 84
  178. 85
  179. 86
  180. 87
  181. 88
  182. 89
  183. 90
  184. 91
  185. 92
  186. 93
  187. 94
  188. 95
  189. 96
  190. 97
  191. 98
  192. 99
  193. 100
  194. 101
  195. 102
  196. 103
  197. 104
  198. 105
  199. 106

在spring-*.xml中加入spring支持,打开aop功能

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
  3. <!-- aop -->
  4. <bean id="logService" class="com.jiankunking.common.SysLogAspect"></bean>
  5. <!--Spring MVC使用ViewResolver来根据controller中返回的view名关联到具体的View对象。使用View对象来渲染返回值以生成最终的视图,如html,json或pdf等-->
  6. <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  7. <property name="prefix">
  8. <value>/WEB-INF/pages/</value>
  9. </property>
  10. <property name="suffix">
  11. <value>.jsp</value>
  12. </property>
  13. </bean>
  14. <!-- 启动对@AspectJ注解的支持 -->
  15. <aop:aspectj-autoproxy proxy-target-class="true"/>
  16. <!-- 启用MVC注解 -->
  17. <mvc:annotation-driven/>
  18. <!-- 指定Sping组件扫描的基本包路径 -->
  19. <context:component-scan base-package="com.jiankunking.controller">
  20. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  21. </context:component-scan>
  22. <!--静态文件处理-->
  23. <mvc:resources location="/resources/" mapping="/resources/**"/>
  24. </beans>
  25. 1
  26. 2
  27. 3
  28. 4
  29. 5
  30. 6
  31. 7
  32. 8
  33. 9
  34. 10
  35. 11
  36. 12
  37. 13
  38. 14
  39. 15
  40. 16
  41. 17
  42. 18
  43. 19
  44. 20
  45. 21
  46. 22
  47. 23
  48. 24
  49. 25
  50. 26
  51. 27
  52. 28
  53. 29
  54. 30
  55. 31
  56. 32
  57. 33
  58. 34
  59. 35
  60. 36
  61. 37
  62. 38
  63. 39
  64. 40

注解也写好了,spring也配置好了,在controller里面怎么用呢?

Controller应用

  1. package com.jiankunking.controller;
  2. import com.jiankunking.common.OperationLogger;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RequestMethod;
  6. @Controller
  7. @RequestMapping(value = "/Welcome", produces = "text/html;charset=UTF-8")
  8. public class WelcomeController
  9. {
  10. @OperationLogger(modelName = "WelcomeController", option = "getWelcome")
  11. @RequestMapping(value = "/getWelcome", method = RequestMethod.POST)
  12. public void getWelcome()
  13. {
  14. //异常拦截测试
  15. //int i = 9 / 0;
  16. System.out.println("controller方法执行!");
  17. }
  18. }
  19. 1
  20. 2
  21. 3
  22. 4
  23. 5
  24. 6
  25. 7
  26. 8
  27. 9
  28. 10
  29. 11
  30. 12
  31. 13
  32. 14
  33. 15
  34. 16
  35. 17
  36. 18
  37. 19
  38. 20
  39. 21

如何测试呢?
从前端发起ajax请求controller,即可:

  1. $.ajax({
  2. type: "POST",
  3. url: "/Welcome/getWelcome",
  4. contentType: "application/json",
  5. data: null,
  6. success: function () {
  7. // alert("22");
  8. },
  9. error: function () {
  10. // alert("失败!");
  11. }
  12. });
  13. 1
  14. 2
  15. 3
  16. 4
  17. 5
  18. 6
  19. 7
  20. 8
  21. 9
  22. 10
  23. 11
  24. 12
  25. 13
  26. 14

效果如下:
这里写图片描述

由于这里是通过Spring的@Aspect注解实现的AOP,所以同一个类中的某个方法A(该方法没有注解标识)调用另一个有注解标识的方法B时,方法B上的注解是不会起作用的。

这里写图片描述

演示demo:
http://download.csdn.net/detail/xunzaosiyecao/9609918

xml方式实现aop拦截及aop基础知识参考:
xml实现aop拦截

Spring Boot 自定义注解方式拦截Controller等实现日志管理:
Spring Boot 自定义注解

发表评论

表情:
评论列表 (有 0 条评论,228人围观)

还没有评论,来说两句吧...

相关阅读