配色: 字号:
Spring MVC AOP通过注解方式拦截Controller等实现日志管理
2016-09-30 | 阅:  转:  |  分享 
  
SpringMVCAOP通过注解方式拦截Controller等实现日志管理

开始上代码:



注解定义



packagecom.jiankunking.common;



importjava.lang.annotation.;



/

@authorjiankunking

@Date:2016/8/15

@Time:11:09

@annotationOperationLogger

/

@Retention(RetentionPolicy.RUNTIME)//注解会在class中存在,运行时可通过反射获取

@Target(ElementType.METHOD)//目标是方法

@Documented//文档生成时,该注解将被包含在javadoc中,可去掉

public@interfaceOperationLogger

{

/

模块名字

/

StringmodelName()default"";



/

操作类型

/

Stringoption();



}



@interface是用来自定义注释类型的。

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

AOP拦截部分



packagecom.jiankunking.common;



importorg.apache.log4j.Logger;

importorg.aspectj.lang.JoinPoint;

importorg.aspectj.lang.ProceedingJoinPoint;

importorg.aspectj.lang.Signature;

importorg.aspectj.lang.annotation.;

importorg.aspectj.lang.reflect.MethodSignature;

importorg.springframework.stereotype.Component;



importjava.lang.reflect.Method;



/

@authorjiankunking

@Date:2016/8/15

@Time:11:11

@annotationSysLogAspect

/

@Aspect

@Component

publicclassSysLogAspect

{

privatestaticfinalLoggerlogger=Logger.getLogger(SysLogAspect.class);



/

定义Pointcut,Pointcut的名称,此方法不能有返回值,该方法只是一个标示

/

@Pointcut("@annotation(com.jiankunking.common.OperationLogger)")

publicvoidcontrollerAspect()

{

System.out.println("我是一个切入点");

}



/

前置通知(Beforeadvice):在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。

@paramjoinPoint

/

@Before("controllerAspect()")

publicvoiddoBefore(JoinPointjoinPoint)

{

System.out.println("=====SysLogAspect前置通知开始=====");

//handleLog(joinPoint,null);

}



/

后通知(Afteradvice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

@paramjoinPoint

/

@AfterReturning(pointcut="controllerAspect()")

publicvoiddoAfter(JoinPointjoinPoint)

{

System.out.println("=====SysLogAspect后置通知开始=====");

//handleLog(joinPoint,null);

}



/

抛出异常后通知(Afterthrowingadvice):在方法抛出异常退出时执行的通知。

@paramjoinPoint

@parame

/

@AfterThrowing(value="controllerAspect()",throwing="e")

publicvoiddoAfter(JoinPointjoinPoint,Exceptione)

{

System.out.println("=====SysLogAspect异常通知开始=====");

//handleLog(joinPoint,e);

}



/

环绕通知(Aroundadvice):包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。

@paramjoinPoint

/

@Around("controllerAspect()")

publicObjectdoAround(ProceedingJoinPointjoinPoint)throwsThrowable

{

System.out.println("=====SysLogAspect环绕通知开始=====");

//handleLog(joinPoint,null);

Objectobj=joinPoint.proceed();

System.out.println("=====SysLogAspect环绕通知结束=====");

returnobj;

}



/

日志处理



@paramjoinPoint

@parame

/

privatevoidhandleLog(JoinPointjoinPoint,Exceptione)

{

try

{

//获得注解

OperationLoggerlogger=giveController(joinPoint);

if(logger==null)

{

return;

}



Stringsignature=joinPoint.getSignature().toString();//获取目标方法签名

StringmethodName=signature.substring(signature.lastIndexOf(".")+1,

signature.indexOf("("));



StringlongTemp=joinPoint.getStaticPart().toLongString();

StringclassType=joinPoint.getTarget().getClass().getName();



Classclazz=Class.forName(classType);



Method[]methods=clazz.getDeclaredMethods();

System.out.println("methodName:"+methodName);



for(Methodmethod:methods)

{

if(method.isAnnotationPresent(OperationLogger.class)

&&method.getName().equals(methodName))

{

//OpLoggerlogger=method.getAnnotation(OpLogger.class);

StringclazzName=clazz.getName();

System.out.println("clazzName:"+clazzName+",methodName:"

+methodName);

}

}



}catch(Exceptionexp)

{

logger.error("异常信息:{}",exp);

exp.printStackTrace();

}

}



/

获得注解

@paramjoinPoint

@return

@throwsException

/

privatestaticOperationLoggergiveController(JoinPointjoinPoint)throwsException

{

Signaturesignature=joinPoint.getSignature();

MethodSignaturemethodSignature=(MethodSignature)signature;

Methodmethod=methodSignature.getMethod();



if(method!=null)

{

returnmethod.getAnnotation(OperationLogger.class);

}

returnnull;

}



}



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

Spring使用的AOP注解分为三个层次:

前提条件是在xml中放开了









@Aspect放在类头上,把这个类作为一个切面。

@Pointcut放在方法头上,定义一个可被别的方法引用的切入点表达式。

5种通知。

@Before,前置通知,放在方法头上。

@After,后置【finally】通知,放在方法头上。

@AfterReturning,后置【try】通知,放在方法头上,使用returning来引用方法返回值。

@AfterThrowing,后置【catch】通知,放在方法头上,使用throwing来引用抛出的异常。

@Around,环绕通知,放在方法头上,这个方法要决定真实的方法是否执行,而且必须有返回值。

在Maven中加入以下以依赖




xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/maven-v4_0_0.xsd">

4.0.0

com.mkyong.common

spring-mvc-log4j

war

1.0-SNAPSHOT

SpringMVC+Log4j





1.7

4.3.2.RELEASE

2.6.2

1.2

3.1.0

1.7.4

3.1











org.springframework

spring-webmvc

${spring.version}





org.springframework

spring-aop

${spring.version}





org.springframework

spring-aspects

${spring.version}









org.apache.logging.log4j

log4j-api

${log4j.version}





org.apache.logging.log4j

log4j-core

${log4j.version}











jstl

jstl

${jstl.version}







javax.servlet

javax.servlet-api

${servletapi.version}

provided





log4j

log4j

1.2.17









org.aspectj

aspectjrt

${org.aspectj-version}









javax.inject

javax.inject

1







cglib

cglib

${cglib.version}















org.apache.maven.plugins

maven-compiler-plugin

3.3



${jdk.version}

${jdk.version}













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






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/aophttp://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd



">















/WEB-INF/pages/





.jsp

































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



Controller应用



packagecom.jiankunking.controller;



importcom.jiankunking.common.OperationLogger;

importorg.springframework.stereotype.Controller;

importorg.springframework.web.bind.annotation.RequestMapping;

importorg.springframework.web.bind.annotation.RequestMethod;



@Controller

@RequestMapping(value="/Welcome",produces="text/html;charset=UTF-8")

publicclassWelcomeController

{

@OperationLogger(modelName="WelcomeController",option="getWelcome")

@RequestMapping(value="/getWelcome",method=RequestMethod.POST)

publicvoidgetWelcome()

{

//异常拦截测试

//inti=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("失败!");

}

});



效果如下:



献花(0)
+1
(本文系网络学习天...首藏)