Spring AOP注解方式实现日志管理
程序员文章站
2022-04-25 16:45:22
...
文章目录
前言:使用注解方式实现日志管理,可以使我们的程序变的清晰、简单,不和很多业务代码混在一起。
实现思路大致分为四点
- 设计日志表和日志类,编写日志Dao和Service以及实现
- 自定义注解,注解中加入几个属性,属性可以标识操作的类型(方法是做什么的)
- 编写切面,切点表达式使用上面的注解直接定位到使用注解的方法,
- 编写通知,通过定位到方法,获取上面的注解以及注解的属性,然后从session中直接获取或者从数据库获取当前登录用户的信息,最后根据业务处理一些日志信息之后调用日志Service存储日志
设计日志表和日志类此步骤将省略可以根据自己的实际情况设计
自定义注解
BussLog
package com.sl.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author shuliangzhao
* @Title: BussLog
* @ProjectName spring-boot-learn
* @Description: TODO
* @date 2019/10/14 20:06
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BussLog {
/**
* 业务的名称
*/
String value() default "";
/**
* 是否将当前日志记录到数据库中
*/
boolean save() default true;
}
BussLogAspect
package com.sl.aop;
import com.alibaba.fastjson.JSON;
import com.sl.annotation.BussLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author shuliangzhao
* @Title: BussLogAspect
* @ProjectName spring-boot-learn
* @Description: TODO
* @date 2019/10/14 20:08
*/
@Aspect
@Component
@EnableAspectJAutoProxy
public class BussLogAspect {
private static final Logger log = LoggerFactory.getLogger(BussLogAspect.class);
@Pointcut(value = "@annotation(com.sl.annotation.BussLog)")
public void pointcut() {
}
@Around("pointcut()")
public Object writeLog(ProceedingJoinPoint point) throws Throwable {
//先执行业务
Object result = point.proceed();
try {
handle(point);
} catch (Exception e) {
log.error("日志记录出错!", e);
}
return result;
}
private void handle(ProceedingJoinPoint point) throws Exception {
Method currentMethod = getMethod(point);
//获取操作名称
BussLog annotation = currentMethod.getAnnotation(BussLog.class);
boolean save = annotation.save();
String bussinessName = parseParams(point.getArgs(), annotation.value());
log.info("{} | {} - {} {} - {}", bussinessName);
if (!save) {
return;
}
}
private Method getMethod(JoinPoint point) throws NoSuchMethodException {
Signature sig = point.getSignature();
MethodSignature msig = (MethodSignature) sig;
Object target = point.getTarget();
return target.getClass().getMethod(msig.getName(), msig.getParameterTypes());
}
public String parseParams(Object[] params, String bussinessName) {
if (bussinessName.contains("{") && bussinessName.contains("}")) {
List<String> result = match(bussinessName, "(?<=\\{)(\\d+)");
for (String s : result) {
int index = Integer.parseInt(s);
bussinessName = bussinessName.replaceAll("\\{" + index + "}", JSON.toJSONString(params[index - 1]));
}
}
return bussinessName;
}
private static List<String> match(String str, String regex) {
if (null == str) {
return null;
}
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
List<String> list = new LinkedList<>();
while (matcher.find()) {
list.add(matcher.group());
}
return list;
}
}