这次要实现的功能是,要记录所有到controller中方法的运行日志保存到日志表中
日志信息包含:操作人、操作时间、执行方法的全类名、执行方法名、方法作用、方法运行时参数、返回值、方法执行时长。
准备工作
添加aop的启动器
<!--aop-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
创建数据表
-- 操作日志表
create table operate_log(
id int unsigned primary key auto_increment comment 'ID',
class_name varchar(100) comment '操作的类名',
method_name varchar(100) comment '操作的方法名',
method_desc varchar(100) comment '方法用途',
method_params varchar(1000) comment '方法参数',
return_value varchar(2000) comment '返回值',
operate_user int unsigned comment '操作人ID',
operate_time datetime comment '操作时间',
cost_time bigint comment '方法执行耗时, 单位:ms'
) comment '操作日志表';
创建日志类
package com.itheima.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class OperateLog {
private Integer id; //ID
private String className; //操作类名
private String methodName; //操作方法名
private String methodDesc; //方法用途
private String methodParams; //操作方法参数
private String returnValue; //操作方法返回值
private Integer operateUser; //操作人ID
private LocalDateTime operateTime; //操作时间
private Long costTime; //操作耗时
}
创建日志的Mapper
package com.itheima.mapper;
import com.itheima.pojo.OperateLog;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface OperateLogMapper {
//插入日志数据
@Insert("insert into operate_log (operate_user, operate_time, class_name, method_name,method_desc, method_params, return_value, cost_time) " +
"values (#{operateUser}, #{operateTime}, #{className}, #{methodName},#{methodDesc}, #{methodParams}, #{returnValue}, #{costTime});")
public void insert(OperateLog log);
}
制作切面
package com.itheima.aspect;
import com.itheima.anno.LogAnno;
import com.itheima.mapper.OperateLogMapper;
import com.itheima.pojo.OperateLog;
import com.itheima.util.JwtUtils;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;
@Component
@Aspect//切面
public class LogAspect {
@Autowired
private HttpServletRequest request;
@Autowired
private OperateLogMapper operateLogMapper;
//自定义注解
@Pointcut("@annotation(com.itheima.anno.LogAnno)")
public void pt() {
}
//环绕通知
@Around("pt()")
public Object logAround(ProceedingJoinPoint pjp) {
OperateLog operateLog = new OperateLog();
//日志信息包含:方法作用、、返回值、方法执行时长
try {
String token = request.getHeader("token");
Integer id = JwtUtils.parseJWT(token).get("id", Integer.class);
operateLog.setOperateUser(id);//操作人id
}catch (Exception e){
e.printStackTrace();
}
MethodSignature ms = (MethodSignature) pjp.getSignature();
operateLog.setMethodName(ms.getMethod().getName());//方法名
operateLog.setMethodDesc(ms.getMethod().getAnnotation(LogAnno.class).methodDesc());//方法作用
operateLog.setOperateTime(LocalDateTime.now());//操作时间
operateLog.setClassName(pjp.getTarget().getClass().getName());//全类名
operateLog.setMethodParams(Arrays.toString(pjp.getArgs()));//参数
Object obj = null;
long start = new Date().getTime();
try {
obj = pjp.proceed();
operateLog.setReturnValue(obj.toString());
return obj;
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
long end = new Date().getTime();
operateLog.setCostTime(end-start);//方法执行时长
operateLogMapper.insert(operateLog);//保存日志
}
}
}