1、添加相关依赖
<!-- aop依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.5.2</version>
</dependency>
<!-- mybatis-plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- mysql驱动依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
<scope>runtime</scope>
</dependency>
2、编写配置文件
server:
port: 8088
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/ihrm?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
aop:
auto: true
proxy-target-class: true
mybatis-plus:
type-aliases-package: com.zsn.docker.pojo
mapper-locations: classpath:mapper/*.xml
configuration:
map-underscore-to-camel-case: false
3、编写相关类
注解类:
/**
*只给方法使用
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RequiredLog {
String value() default "";
}
实体类:
@Data
@TableName("sysLog")
public class SysLog {
@TableId
private String id;
private String ip;
private String username;
//注解中信息
private String operation;
//含有注解的方法信息
private String method;
//方法参数信息
private String params;
//
private long time;
private String createdTime;
}
dao层代码:
@Repository
public interface SysLogDao extends BaseMapper<SysLog> {
}
service层代码:
@Service
public class SysLogService {
@Autowired
private SysLogDao sysLogDao;
public int saveObject(SysLog sysLog){
return sysLogDao.insert(sysLog);
}
}
编写切面:
/**
* @author: zhouzhou
* @date:2021/8/16 9:34
* @Aspect 描述的类为切面类,此类中实现:
* 1)切入点(Pointcut)的定义
* 2)通知(advice)的定义(扩展功能)
*/
@Slf4j
@Aspect
@Component
public class SysLogAspect {
@Autowired
private SysLogService sysLogService;
/**
* @Pointcut 注解用于描述或定义一个切入点
* 切入点的定义需要遵循spring中指定的表达式规范
*/
@Pointcut("@annotation(com.zsn.docker.annotation.RequiredLog)")
public void logPointCut() {}
/**
* @Around 注解描述的方法为一个环绕通知方法,
* 在此方法中可以添加扩展业务逻辑,可以调用下一个
切面对象或目标方法
* @param point 连接点(此连接点只应用@Around描述的方法)
* @return
* @throws Throwable
*/
@Around("logPointCut()")
public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable{
long start=System.currentTimeMillis();
log.info("start:"+start);
Object result=point.proceed();//调用下一个切面或目标方法
long end=System.currentTimeMillis();
log.info("end:"+end);
//记录日志(用户行为信息)
saveLog(point,(end-start));
return result;
}
//日志记录
private void saveLog(ProceedingJoinPoint jp,long time)throws Throwable {
//1.获取用户行为日志(ip,username,operation,method,params,time,createdTime)
//获取类的字节码对象,通过字节码对象获取方法信息
Class<?> targetCls=jp.getTarget().getClass();
//获取方法签名(通过此签名获取目标方法信息)
MethodSignature ms=(MethodSignature)jp.getSignature();
//获取目标方法上的注解指定的操作名称
Method targetMethod= targetCls.getDeclaredMethod(ms.getName(), ms.getParameterTypes());
RequiredLog requiredLog = targetMethod.getAnnotation(RequiredLog.class);
String operation=requiredLog.value();
//获取目标方法名(目标类型+方法名)
String targetClsName=targetCls.getName();
String targetObjectMethodName=targetClsName+"."+ms.getName();
//获取请求参数
String targetMethodParams= Arrays.toString(jp.getArgs());
//2.封装用户行为日志(SysLog)
SysLog entity=new SysLog();
entity.setId(UUID.randomUUID().toString());
entity.setIp(InetAddress.getLocalHost().getHostAddress());
entity.setUsername("admin");
entity.setOperation(operation);
entity.setMethod(targetObjectMethodName);
entity.setParams(targetMethodParams);
entity.setTime(time);
entity.setCreatedTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
//3.调用业务层对象方法(saveObject)将日志写入到数据库
log.info(entity.toString());
sysLogService.saveObject(entity);
}
}
对于aop的基本知识忘了的可以看下这个博客:
spring-aop
编写controller层代码:
@RestController
public class TestController {
@RequestMapping("test")
@RequiredLog("测试日志")
public String test(String str){
return "200";
}
最后运行项目:输入网址测试
控制台输出:
数据库数据: