1、spring-mvc.xml配置
<bean id="operationLogAspect" class="com.xxx.aop.OperationLogAspect" />
2、注解类
package com.xxx.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 操作日志
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
/**
* 要操作的资源
*
* @return 资源
*/
OperationType value();
/**
* 日志类型
*/
enum OperationType {
ADD, // 发布
UPDATE_STATUS_ON, // 上架
UPDATE_STATUS_OFF, // 下架
EDIT, // 编辑
UPGRADE, // 更新
}
}
3、aop类
package com.xxx.aop;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.*;
@Aspect // 标注为一个切面
@Component
@EnableAspectJAutoProxy(proxyTargetClass = true) // 开启注解版的aop功能,也可以直接在xml中配置<aop:aspectj-autoproxy />,在xml中配置需要添加相应的xmlns
public class OperationLogAspect {
protected static Logger logger = LoggerFactory.getLogger(OperationLogAspect.class);
@Pointcut("@annotation(com.xxx.OperationLog)")
private void operationLog() {
}
/**
* 被代理方法处理完后执行
*
* @param joinPoint 连接点。可以从中取到注解的的参数以及被代理方法的参数
* @param result 被代理方法的返回值,可以定义成自己想要的类型
*/
@AfterReturning(pointcut = "operationLog()", returning = "result")
public void after(JoinPoint joinPoint, boolean result) {
if (!result) return; // 这里因为定义的返回值类型是boolean,所以被代理方法返回false的情况就没有记录
// 获取注解
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
final OperationLog annotation = method.getAnnotation(OperationLog.class);
if (annotation != null) {
System.out.println(annotation.value()); // 注解中的value值
}
// 获取被代理方法参数
// 原先是想要获取接口请求参数,但是被代理方法已经从request中取出了请求参数,而request流只能单次读取。所以after方法中是取不到请求参数的
// args数组的内容就是被代理方法的参数
final Object[] args = joinPoint.getArgs();
// params就是被代理方法add的第一个参数
Map params = (Map) args[0];
// response就是被代理方法add的第二个参数
HttpServletResponse response = (HttpServletResponse) args[1];
// 还可以取到例如保存再session中的用户信息
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
String userID = (String) request.getSession().getAttribute("userid");
}
/**
* 如果after方法出错,在这里可以捕获
*
* @param jp JoinPoint
* @param e RuntimeException
*/
@AfterThrowing(pointcut = "operationLog()", throwing = "e")
public void afterThrowing(JoinPoint jp, RuntimeException e) {
logger.error(jp.getSignature().getName() + "方法发生异常," + e);
}
}
4,被代理方法
@OperationLog(OperationLog.OperationType.ADD)
public boolean add(@Valid @RequestBody Map<String, Object> params, HttpServletResponse response) {
}