目标:
在方法上添加自定义注解,当有方法请求时记录日志信息到数据库
引入AOP依赖
<!--AOP依赖包-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
1.创建自定义注解OperLog
/**
* @author yt
* @create 2022/4/15 10:52
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface OperLog {
String title() default "";
}
2.创建日志实体类
/**
* @author yt
* @create 2022/4/14 17:33
*/
@Data
@NoArgsConstructor
public class Log implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.AUTO)
/**
* 主键id
*/
private Integer id;
/**
* 创建时间
*/
private Date createdAt;
/**
* 标题
*/
private String title;
/**
* 请求路径
*/
private String url;
/**
* 请求ip
*/
private String ip;
/**
* 方法名称
*/
private String method;
/**
* 请求方式
*/
private String requestMethod;
}
3.创建切面类
核心:主要是判断访问的方法上是否有注解,有就获取信息写入数据库,核心部分就是如何获取各种信息。获取到直接创建对象,通过mybatis-plus写入数据库
@Aspect和@Component
首先,这个@Aspect注释告诉Spring这是个切面类,然后@Compoment将转换成Spring容器中的bean或者是代理bean。 总之要写切面这两个注解一起用就是了。
@PointCut
这个注解包含两部分,PointCut表达式和PointCut签名。表达式是拿来确定切入点的位置的,说白了就是通过一些规则来确定,哪些方法是要增强的,也就是要拦截哪些方法。
/**
* 切面类
*
* @author yt
* @create 2022/4/15 10:16
*/
@Component
//aop注解,标注这个类是一个切面
@Aspect
public class AnnotationPointCut {
@Autowired
private LogMapper logMapper;
//定义一个织入点,就是注解的全类名
@Pointcut("@annotation(com.example.demo.annotation.OperLog)")
public void OperLogPointCut() {
}
//处理完请求后执行
@AfterReturning(pointcut = "OperLogPointCut()", returning = "jsonResult")
public void afterReturning(JoinPoint joinPoint, Object jsonResult) {
//获取注解,没有获取到就return,获取到就写入数据库
try {
//判断访问的方法是否有注解,有就创建对象获取信息写入数据库
OperLog controllerOperLog = getAnnotationOperLog(joinPoint);
if (controllerOperLog == null) {
return;
}
Log log = new Log();
log.setId(null);
//标题
log.setTitle(controllerOperLog.title());
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = servletRequestAttributes.getRequest();
//请求uri
log.setUrl(request.getRequestURI());
log.setIp("127.0.0.1");
//类名称与方法名称
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
log.setMethod(className + "." + methodName + "()");
//请求方式
log.setRequestMethod(request.getMethod());
logMapper.insert(log);
} catch (Exception e) {
e.printStackTrace();
}
}
//判断访问的方法上是否有注解
public OperLog getAnnotationOperLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(OperLog.class);
}
return null;
}
}
4.添加注解
在访问的方法上添加注解,并在注解里写上对应的方法名称
//添加自定义的注解
@OperLog(title = "添加老师")
@GetMapping("add")
public ResponseResult add(String name, String work, Integer age) {
Teacher t1 = new Teacher();
t1.setId(null);
t1.setName(name);
t1.setAge(age);
t1.setUpdatedAt(new Date());
t1.setWork(work);
teacherService.add(t1);
return new ResponseResult(200, "添加成功");
}
//添加自定义的注解
@OperLog(title = "查询老师")
@GetMapping("select")
public ResponseResult<List<Teacher>> select() {
List<Teacher> teacherList = teacherService.select();
return new ResponseResult(200, teacherList);
}
//添加自定义的注解
@OperLog(title = "按照姓名查找老师")
@GetMapping("select/one")
public ResponseResult<Teacher> selectOne(String name) {
Teacher teacher = teacherService.selectOne(name);
return new ResponseResult(200, teacher);
}
5.将结果写入数据库
当访问对应的方法结束时,会直接写入数据库