使用自定义注解+SpringAop实现操作日志记录,记录内容包括请求参数、请求方法、请求响应时间等的记录。
一、在pom文件中,引入依赖包和插件。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
lombok还需安装插件。我这里只是主要的包引入,还有其他的需要自行引入。
二、自定义注解
import java.lang.annotation.Documented;
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)
@Documented
public @interface SysLog {
String value() default "";
}
三、编写AOP切面类
import com.google.gson.Gson;
import com.piao.annotation.SysLog;
import com.piao.sys.sysconfig.bo.SysLogBo;
import com.piao.sys.sysconfig.service.SysLogService;
import com.power.common.util.DateTimeUtil;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.aspectj.lang.ProceedingJoinPoint;
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.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 系统日志切面
*/
@Aspect
@Component
@AllArgsConstructor
public class SysLogAspect {
private final SysLogService sysLogService;
/**
* 这里我们使用注解的形式 当然,我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method 切点表达式:
* execution(...)
*/
@Pointcut("@annotation(com.piao.annotation.SysLog)")
public void logPointCut() {}
/**
* 环绕通知 @Around , 当然也可以使用 @Before (前置通知) @After (后置通知)
*
* @param point
* @return
* @throws Throwable
*/
@SneakyThrows
@Around("logPointCut()")
public Object around(ProceedingJoinPoint point) {
long beginTime = System.currentTimeMillis();
Object result = point.proceed();
long time = System.currentTimeMillis() - beginTime;
SysLogBo sysLog = getLog(point, time);
sysLogService.addSysLog(sysLog);
return result;
}
/**
* 获取日志信息
*
* @param joinPoint
* @param time
*/
private SysLogBo getLog(ProceedingJoinPoint joinPoint, long time) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SysLogBo sysLogBO = new SysLogBo();
sysLogBO.setExeuTime(time);
sysLogBO.setCreateDate(DateTimeUtil.nowStrTime());
SysLog sysLog = method.getAnnotation(SysLog.class);
if (sysLog != null) {
// 注解上的描述
sysLogBO.setRemark(sysLog.value());
}
// 请求的 类名、方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = signature.getName();
sysLogBO.setClassName(className);
sysLogBO.setMethodName(methodName);
// 请求的参数
Object[] args = joinPoint.getArgs();
List<String> list = new ArrayList(args.length);
for (Object o : args) {
list.add(new Gson().toJson(o));
}
sysLogBO.setParams(list.toString());
return sysLogBO;
}
}
四、编写日志业务实体
import lombok.Data;
import lombok.ToString;
@Data
@ToString
public class SysLogBo {
private long exeuTime;
private String createDate;
private String className;
private String methodName;
private String params;
private String remark;
}
五、编写日志业务服务和实现
import com.baomidou.mybatisplus.extension.api.R;
import com.piao.sys.sysconfig.bo.SysLogBo;
/**
* 系统日志服务
*/
public interface SysLogService {
R addSysLog(SysLogBo sysLog);
}
import com.baomidou.mybatisplus.extension.api.R;
import com.piao.sys.sysconfig.bo.SysLogBo;
import com.piao.sys.sysconfig.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
/**
* 系统日志服务实现
*/
@Slf4j
@Service
public class SysLogServiceImpl implements SysLogService {
@Async
@Override
public R addSysLog(SysLogBo sysLog) {
//这里可以编写存入数据库,es或者进行其他持久化
log.info(sysLog.toString());
return R.ok(sysLog);
}
}
我这里实现类只是记录到日志里面去了,大家可以根据自己的需求去持久化记录。
六、使用自定义注解验证效果。
import com.piao.annotation.SysLog;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "/user")
public class UserController {
@SysLog(value = "获取一个例子")
@GetMapping(value = "/getDemo")
public String getDemo(){
String str = "this is a zhirong user";
return str;
}
}
我们通过swagger文档来调用添加了自定义注解的接口,也可以通过浏览器调用。
下面我们看控制台输出的日志,已经成功调用了日志服务,并输出了日志信息。