在项目进行过程中,需要使用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;
}