一、前言
当我们的项目需要用到展示用户实际操作日志详细记录的时候,我们可以用注解加AOP方式简单实现操作日志的记录;
二、开发前准备
开发环境:JDK1.8、Mysql5.7
2.1、数据库
#系统日志表,这里没有添加索引只是简单实现了一下
CREATE TABLE `sys_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`operation` varchar(255) DEFAULT NULL,
`method` varchar(255) DEFAULT NULL,
`uri` varchar(255) DEFAULT NULL,
`ip` varchar(255) DEFAULT NULL,
`params` varchar(255) DEFAULT NULL,
`operator_name` varchar(255) DEFAULT NULL,
`use_time` decimal(10,3) DEFAULT NULL,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4;
2.2、 添加依赖
这里只写了主要的AOP依赖,完整pom文件和项目地址可以访问git上的
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.3、自定义注解
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysLog {
String value() default "";
}
2.4、AOP部分主要代码
@Around:在被通知的方法调用之前和调用之后执行自定义的方法
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
private static Logger logger = LoggerFactory.getLogger(SysLogAspect.class);
@Around("@annotation(sysLog)")
@Pointcut()
public Object around(ProceedingJoinPoint joinPoint, SysLog sysLog) throws Throwable {
long beginTime = System.currentTimeMillis();
//执行方法
Object result = joinPoint.proceed();
//执行时长(毫秒)
long time = System.currentTimeMillis() - beginTime;
SysLogEntity sysLogEntity = new SysLogEntity();
if(sysLog != null){
//注解上的描述
sysLogEntity.setOperation(sysLog.value());
}
//请求的方法名
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
sysLogEntity.setMethod(className + "." + methodName + "()");
//请求uri
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
sysLogEntity.setUri(request.getRequestURI());
Map<String, String> headers = WebUtils.getHeaders(request);
logger.info("headers: {}",headers);
//请求的参数
Object[] args = joinPoint.getArgs();
String params = JSON.toJSONString(args[0]);
sysLogEntity.setParams(params);
//设置IP地址
sysLogEntity.setIp(WebUtils.getIpAddr(request));
/*//用户名,这里测试阶段没做安全认证框架的
String username = SecurityUtils.getSysUser().getUsername();
sysLogEntity.setUsername(username);*/
//耗时保存秒
BigDecimal bigDecimal = new BigDecimal(String.valueOf(time));
BigDecimal useTime = bigDecimal.divide(new BigDecimal("1000"), 3, RoundingMode.HALF_UP);
sysLogEntity.setUseTime(useTime.doubleValue());
//保存系统日志
sysLogService.save(sysLogEntity);
return result;
}
}
2.5、测试
写一个测试接口
@RestController
@RequestMapping("/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
@Autowired
private IUserService iUserService;
@RequestMapping("/save")
@SysLog("insert user")
public HashMap<String, Object> insert(SysUser sysUser){
iUserService.insert(sysUser);
HashMap<String, Object> resMap = new HashMap<>();
resMap.put("success","OK");
resMap.put("code",200);
resMap.put("msg","insert success!");
logger.info("resp: {}",resMap);
return resMap;
}
}
请求接口
查看操作日志记录表结果