一、首先创建个接口类Log
import java.lang.annotation.*;
/**
* @description: 自定义操作日志记录注解
* @author xizc
*
*/
@Target({ ElementType.PARAMETER, ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Log {
/**
* 日志类别
*/
public LogType logType();
/**
* 操作类别
*/
public BusinessType businessType();
/**
* 关联Id
*/
public String businessId();
/**
* 内容
*/
public String content();
}
二、编写切面类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
*
* @description: 操作日志记录处理
* @author xizc
*/
@Aspect
@Component
public class LogAspect {
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
/**
* 获取被拦截方法参数名列表(使用Spring支持类库)
*/
LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
ExpressionParser parser = new SpelExpressionParser();
/**
* 处理请求前执行
* @param joinPoint 切点
*/
@Before(value = "@annotation(methodLog)")
public void boBefore(JoinPoint joinPoint, Log methodLog) {
handleLog(joinPoint, methodLog, null, null);
}
/**
* 处理完请求后执行
*
* @param joinPoint 切点
*/
@AfterReturning(pointcut = "@annotation(methodLog)", returning = "jsonResult")
public void doAfterReturning(JoinPoint joinPoint, Log methodLog, Object jsonResult) {
handleLog(joinPoint, methodLog, null, jsonResult);
}
/**
* 拦截异常操作
*
* @param joinPoint 切点
* @param e 异常
*/
@AfterThrowing(value = "@annotation(methodLog)", throwing = "e")
public void doAfterThrowing(JoinPoint joinPoint, Log methodLog, Exception e) {
handleLog(joinPoint, methodLog, e, null);
}
protected void handleLog(final JoinPoint joinPoint, Log methodLog, final Exception e, Object jsonResult) {
try {
Object[] args = joinPoint.getArgs();
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String[] params = discoverer.getParameterNames(method);
EvaluationContext context = new StandardEvaluationContext();
for (int len = 0; len < params.length; len++) {
context.setVariable(params[len], args[len]);
}
//解析businessId注解值中的SpEL表达式
String businessIdSpel = methodLog.businessId();
Expression businessIdExpression = parser.parseExpression(businessIdSpel);
String businessId = businessIdExpression.getValue(context, String.class);
System.out.println("businessId:"+ businessId);
//解析content注解值中的SpEL表达式
String contentSpel = methodLog.content();
Expression contentExpression = parser.parseExpression(contentSpel);
String content = contentExpression.getValue(context, String.class);
System.out.println("content:"+ content);
//到此已经解析并获取到注解里面的信息,下面可以根据自己的业务相应的逻辑
} catch (Exception exp) {
// 记录本地异常日志
log.error("异常信息:{}", exp.getMessage());
exp.printStackTrace();
}
}
}
根据自己情况来删减切入点。
SpEL表达式可以获取入参对象里面的属性,例如传入User对象user里面的username,那么SpEL表达式就是 #user.username 。
三、测试
在controller里面写个方法
/**
* 测试log注解
*
* @param ids
* @param msg
*/
@GetMapping("/test5")
@Log(logType = LogType.EQUIP, businessType = BusinessType.EXPORT, businessId = "#ids", content = "'测试拼接参数'+#msg")
public void test5(Long[] ids, String msg) {
}
然后请求接口:
打印结果如下: