在項目進行過程中,需要使用aop對api傳入或者傳出數據進行日誌記錄。考慮實際應用,放棄了使用攔截器,轉而使用aop的前置通知和返回通知中加入日誌記錄操作。
在spring中,controller會被JDK自動代理。當使用自定義標籤時controller已經實例化不會在通過aop,因此需要走cglib代理。
xml配置:
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns="http://www.springframework.org/schema/beans"
xmlns:task="http://www.springframework.org/schema/task"
<span style="color:#FF6666;"> <!-- 啓動對@AspectJ註解的支持 -->
<aop:aspectj-autoproxy/>
<!--通知spring使用cglib而不是jdk的來生成代理方法 AOP可以攔截到Controller-->
<aop:aspectj-autoproxy proxy-target-class="true" /> </span><span style="color:#FF6666;"> xmlns:aop="http://www.springframework.org/schema/aop"</span>
xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
<span style="color:#FF6666;"> http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 啓動對@AspectJ註解的支持 -->
<aop:aspectj-autoproxy/>
<!--通知spring使用cglib而不是jdk的來生成代理方法 AOP可以攔截到Controller-->
<aop:aspectj-autoproxy proxy-target-class="true" />
</span>
自定義標籤:
package com.xiaoma.universe.video.aspect;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ControllerLog {
String description() default "";//自定義標籤屬性
}
實現aspect:
package com.xiaoma.universe.video.aspect;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class LogAspect {
//本地異常日誌記錄對象
private static final Logger logger = LoggerFactory.getLogger(LogAspect.class);
//Controller層切點
@Pointcut("@annotation(com.xiaoma.universe.video.aspect.ControllerLog)")
public void controllerAspect() {
}
/**
* 前置通知 用於攔截Controller層記錄用戶的操作
*
* @param joinPoint 切點
*/
@Before("controllerAspect()")
public void doBefore(JoinPoint joinPoint) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
System.out.println("請求"+request.getCharacterEncoding());
}
/**
* 獲取註解中對方法的描述信息 用於Controller層註解
*
* @param joinPoint 切點
* @return 方法描述
* @throws Exception
*/
public static String getControllerMethodDescription(JoinPoint joinPoint) throws Exception {
Class<?> clazz = joinPoint.getTarget().getClass();
String name = joinPoint.getSignature().getName();
Object[] parameterTypes = joinPoint.getArgs();
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(name) && method.getParameterTypes().length == parameterTypes.length) {
ControllerLog methodLog = method.getAnnotation(ControllerLog. class);
if (methodLog != null) {
return methodLog.description();
}
break;
}
}
return "";
}
}
在controller中使用:
@RequestMapping( method=RequestMethod.GET)
@ResponseBody
@ControllerLog(description="123")
public JSONObject list(HttpServletRequest request, HttpServletResponse response ,VideoCourses videoCourses, BaseModel model ,@TokenUser UserInfo user,String channel,String queryType)
{
return null;
}