利用AOP+自定义注解实现日志记录
需求: 日志记录
操作日志记录,类似如下
思路:AOP+自定义注解
AOP面向切面编程,利用 一种称为"横切"
的技术,剖开封装的对象内部,并将那些影响了 多个类的公共行为
抽取出封装到一个可重用模块,并将其命名 为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
在每个目标方法上,加上自定义注解@MyLog(“查询全部订单”) 或者 @MyLog(“模块描述”)
利用AOP读取注解内的数据
步骤:
1.数据日志表
CREATE TABLE `log` (
`id` int(11) NOT NULL AUTO_INCREMENT comment '日志编号',
`log_time` datetime DEFAULT NULL comment '时间',
`log` varchar(255) DEFAULT NULL comment '日志信息',
`ip` varchar(255) DEFAULT NULL comment '操作ip',
`name` varchar(255) DEFAULT NULL comment '操作人员',
`method` varchar(255) DEFAULT NULL comment '请求方式',
`type` varchar(255) DEFAULT NULL comment '操作类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
项目中要设计实体类…
2.自定义日志注解
package com.taotie.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @date 2024/12/3
* @desc 自定义日志注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
public @interface MyLog {
/**
* 日志内容
*/
String log() default "";
/**
* 日志类型
*/
String type() default "";
}
3.创建AOP读取注解值,记录日志
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
package com.taotie.aspect;
import com.taotie.annotation.MyLog;
import com.taotie.entity.SysLog;
import com.taotie.entity.SysUser;
import com.taotie.service.SysLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
/**
* --- 天道酬勤 ---
*
* @author QiuShiju
* @date 2024/12/3
* @desc 日志切面类
*/
@Aspect
@Component
public class LogAspect {
@Autowired
private SysLogService sysLogService;
/**
* 定义后置增强方法,在目标方法调用后执行
* 特殊的!!!!! 此处的目标对象是注解!!!
* 即MyLog注解加在哪个方法,哪个方法就会被增强
*/
@After("@annotation(com.qf.annotation.MyLog)")
public void after(JoinPoint joinPoint) {
// 获取ip
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes( )).getRequest( );
String ip = request.getRemoteAddr( );
// 获取操作人名
String userName = "未登录";
HttpSession session = request.getSession( );
SysUser user = (SysUser) session.getAttribute( "sysUser" );
if (user!= null){
userName = user.getUserName( );
}
// 获取请求方式
String method = request.getMethod( );
// 获取注解参数: 1) 日志内容 2) 日志类型
HashMap<String, String> map = getAnnoLog(joinPoint);
String log = map.get("log");
String type = map.get("type");
// 封装日志对象
// 开始记录日志
SysLog sysLog = new SysLog( );
sysLog.setLogTime(new Date( ));
sysLog.setIp(ip);
sysLog.setName(userName);
sysLog.setMethod(method);
sysLog.setLog(log);
sysLog.setType(type);
// 调用service层方法,保存日志
sysLogService.insert(sysLog);
}
/**
* 封装的方法,通过反射技术获得目标方法上的注解的值
*/
public static HashMap<String, String> getAnnoLog(JoinPoint joinPoint) {
HashMap<String, String> map = new HashMap<>( );
try {
MethodSignature signature = (MethodSignature) joinPoint.getSignature( );
// 获得目标方法对象
Method method = signature.getMethod( );
// 获得目标方法对象上的日志注解
MyLog myLog = method.getDeclaredAnnotation(MyLog.class);
// 获得日志注解上的值
String log = myLog.log( );
String type = myLog.type( );
map.put("log", log);
map.put("type", type);
} catch (Exception e) {
throw new RuntimeException(e);
}
return map;
}
}
5.插入日志到数据库
ps: 这里需要自己实现LogService和LogMapper,即插入到数据库的动作,此处代码没有粘贴出来
6.在需要记录日志的方法上加注解即可
7.启动测试
发请求,测试,查看数据库记录的日志
后续
需要在项目设置 【日志模块】,将日志从数据库查询展现在前端即可,类似下面这样