Spring MVC AOP通过注解方式拦截Controller等实现日志管理
2016-08-18 20:53
471 查看
之前一直写.net,没玩过spring,一直没用过aop(面向切面编程)这类功能,当然不是说.net里面没有这类框架,企业库就可以微软企业库官网
开始上代码:
@interface是用来自定义注释类型的。
注释的声明用@符号后面跟上这个注释类型的名字,再后面跟上括号,括号中列出这个注释中元 素/方法的key-value对。值必须是常量。
Aspect通常用于将必要的但和业务无关的逻辑和业务逻辑分离。
Spring使用的AOP注解分为三个层次:
前提条件是在xml中放开了
@Aspect放在类头上,把这个类作为一个切面。
@Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。
5种通知。
@Before,前置通知,放在方法头上。
@After,后置【finally】通知,放在方法头上。
@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。
注解也写好了,spring也配置好了,在controller里面怎么用呢?
如何测试呢?
从前端发起ajax请求controller,即可:
效果如下:
由于这里是通过Spring的@Aspect注解实现的AOP,所以同一个类中的某个方法A(该方法没有注解标识)调用另一个有注解标识的方法B时,方法B上的注解是不会起作用的。
演示demo:
http://download.csdn.net/detail/xunzaosiyecao/9609918
xml方式实现aop拦截及aop基础知识参考:
xml实现aop拦截
开始上代码:
注解定义
package com.jiankunking.common; import java.lang.annotation.*; /** * @author jiankunking * @Date: 2016/8/15 * @Time: 11:09 * @annotation OperationLogger */ @Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取 @Target(ElementType.METHOD)//目标是方法 @Documented//文档生成时,该注解将被包含在javadoc中,可去掉 public @interface OperationLogger { /** * 模块名字 */ String modelName() default ""; /** * 操作类型 */ String option(); }
@interface是用来自定义注释类型的。
注释的声明用@符号后面跟上这个注释类型的名字,再后面跟上括号,括号中列出这个注释中元 素/方法的key-value对。值必须是常量。
AOP拦截部分
package com.jiankunking.common; import org.apache.log4j.Logger; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import java.lang.reflect.Method; /** * @author jiankunking * @Date: 2016/8/15 * @Time: 11:11 * @annotation SysLogAspect */ @Aspect @Component public class SysLogAspect { private static final Logger logger = Logger.getLogger(SysLogAspect.class); /** * 定义Pointcut,Pointcut的名称,此方法不能有返回值,该方法只是一个标示 */ @Pointcut("@annotation(com.jiankunking.common.OperationLogger)") public void controllerAspect() { System.out.println("我是一个切入点"); } /** * 前置通知(Before advice) :在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。 * @param joinPoint */ @Before("controllerAspect()") public void doBefore(JoinPoint joinPoint) { System.out.println("=====SysLogAspect前置通知开始====="); //handleLog(joinPoint, null); } /** * 后通知(After advice) :当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。 * @param joinPoint */ @AfterReturning(pointcut = "controllerAspect()") public void doAfter(JoinPoint joinPoint) { System.out.println("=====SysLogAspect后置通知开始====="); //handleLog(joinPoint, null); } /** * 抛出异常后通知(After throwing advice) : 在方法抛出异常退出时执行的通知。 * @param joinPoint * @param e */ @AfterThrowing(value = "controllerAspect()", throwing = "e") public void doAfter(JoinPoint joinPoint, Exception e) { System.out.println("=====SysLogAspect异常通知开始====="); //handleLog(joinPoint, e); } /** * 环绕通知(Around advice) :包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。 * @param joinPoint */ @Around("controllerAspect()") public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("=====SysLogAspect 环绕通知开始====="); //handleLog(joinPoint, null); Object obj= joinPoint.proceed(); System.out.println("=====SysLogAspect 环绕通知结束====="); return obj; } /** * 日志处理 * * @param joinPoint * @param e */ private void handleLog(JoinPoint joinPoint, Exception e) { try { //获得注解 OperationLogger logger = giveController(joinPoint); if (logger == null) { return; } String signature = joinPoint.getSignature().toString(); // 获取目标方法签名 String methodName = signature.substring(signature.lastIndexOf(".") + 1, signature.indexOf("(")); String longTemp = joinPoint.getStaticPart().toLongString(); String classType = joinPoint.getTarget().getClass().getName(); Class<?> clazz = Class.forName(classType); Method[] methods = clazz.getDeclaredMethods(); System.out.println("methodName: " + methodName); for (Method method : methods) { if (method.isAnnotationPresent(OperationLogger.class) && method.getName().equals(methodName)) { //OpLogger logger = method.getAnnotation(OpLogger.class); String clazzName = clazz.getName(); System.out.println("clazzName: " + clazzName + ", methodName: " + methodName); } } } catch (Exception exp) { logger.error("异常信息:{}", exp); exp.printStackTrace(); } } /** * 获得注解 * @param joinPoint * @return * @throws Exception */ private static OperationLogger giveController(JoinPoint joinPoint) throws Exception { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); if (method != null) { return method.getAnnotation(OperationLogger.class); } return null; } }
Aspect通常用于将必要的但和业务无关的逻辑和业务逻辑分离。
Spring使用的AOP注解分为三个层次:
前提条件是在xml中放开了
<!-- 开启切面编程功能 --> <aop:aspectj-autoproxy proxy-target-class="true"/>
@Aspect放在类头上,把这个类作为一个切面。
@Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。
5种通知。
@Before,前置通知,放在方法头上。
@After,后置【finally】通知,放在方法头上。
@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。
@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。
@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。
在Maven中加入以下以依赖
<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"> <modelVersion>4.0.0</modelVersion> <groupId>com.mkyong.common</groupId> <artifactId>spring-mvc-log4j</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>SpringMVC + Log4j</name> <properties> <jdk.version>1.7</jdk.version> <spring.version>4.3.2.RELEASE</spring.version> <log4j.version>2.6.2</log4j.version> <jstl.version>1.2</jstl.version> <servletapi.version>3.1.0</servletapi.version> <org.aspectj-version>1.7.4</org.aspectj-version> <cglib.version>3.1</cglib.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency> <!-- Log4j start--> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> <!-- Log4j end--> <!-- jstl --> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servletapi.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- AspectJ --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${org.aspectj-version}</version> </dependency> <!-- @Inject --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>${cglib.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>${jdk.version}</source> <target>${jdk.version}</target> </configuration> </plugin> </plugins> </build> </project>
在spring-*.xml中加入spring支持,打开aop功能
<?xml version="1.0" encoding="UTF-8"?> <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 "> <!-- aop --> <bean id="logService" class="com.jiankunking.common.SysLogAspect"></bean> <!--Spring MVC使用ViewResolver来根据controller中返回的view名关联到具体的View对象。使用View对象来渲染返回值以生成最终的视图,如html,json或pdf等--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix"> <value>/WEB-INF/pages/</value> </property> <property name="suffix"> <value>.jsp</value> </property> </bean> <!-- 启动对@AspectJ注解的支持 --> <aop:aspectj-autoproxy proxy-target-class="true"/> <!-- 启用MVC注解 --> <mvc:annotation-driven/> <!-- 指定Sping组件扫描的基本包路径 --> <context:component-scan base-package="com.jiankunking.controller"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--静态文件处理--> <mvc:resources location="/resources/" mapping="/resources/**"/> </beans>
注解也写好了,spring也配置好了,在controller里面怎么用呢?
Controller应用
package com.jiankunking.controller; import com.jiankunking.common.OperationLogger; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping(value = "/Welcome", produces = "text/html;charset=UTF-8") public class WelcomeController { @OperationLogger(modelName = "WelcomeController", option = "getWelcome") @RequestMapping(value = "/getWelcome", method = RequestMethod.POST) public void getWelcome() { //异常拦截测试 //int i = 9 / 0; System.out.println("controller方法执行!"); } }
如何测试呢?
从前端发起ajax请求controller,即可:
$.ajax({ type: "POST", url: "/Welcome/getWelcome", contentType: "application/json", data: null, success: function () { // alert("22"); }, error: function () { // alert("失败!"); } });
效果如下:
由于这里是通过Spring的@Aspect注解实现的AOP,所以同一个类中的某个方法A(该方法没有注解标识)调用另一个有注解标识的方法B时,方法B上的注解是不会起作用的。
演示demo:
http://download.csdn.net/detail/xunzaosiyecao/9609918
xml方式实现aop拦截及aop基础知识参考:
xml实现aop拦截
相关文章推荐
- Spring MVC AOP通过注解方式拦截Controller等实现日志管理
- Spring MVC AOP通过自定义注解方式拦截Controller等实现日志管理
- java SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- java SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- java SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- java SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)
- SpringAOP拦截Controller,Service实现日志管理(自定义注解的方式)