【工作记录】springboot集成aop实现日志@20230918

2023-09-18 18:07:12

springboot集成aop实现日志

1. 添加依赖

<!-- aop 依赖 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActionLog {

    String action() default "";

    String topic() default "";

}

3. 定义切面类

import com.cnhqd.authcenter.framework.common.utils.IpUtils;
import com.cnhqd.authcenter.framework.common.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Aspect
@Component
public class ActionLogAspect {

  @Pointcut("@annotation(com.cnhqd.authcenter.framework.common.log.ActionLog)")
  public void actionLog() {

  }

  /*** 在切点之前织入* @param joinPoint* @throws Throwable*/
  @Before("actionLog()")
  public void doBefore(JoinPoint joinPoint) throws Exception {
    // 开始打印请求日志
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();// 打印请求相关参数
    log.info("=================== Start ====================");
    // 打印请求url
    log.info("URL            : {}", request.getRequestURL().toString());
    // 打印Httpmethod
    log.info("HTTP Method    : {}", request.getMethod());
    // 打印调用 controller 的全路径以及执行方法
    log.info("Class Method   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
    // 打印请求的IP
    log.info("IP             : {}", IpUtils.getIpAddr(request));
    // 打印请求入参
    log.info("Request Args   : {}", JsonUtils.toJsonString(joinPoint.getArgs()));
    ActionLog annotation = ((MethodSignature) joinPoint.getSignature()).getMethod().getAnnotation(ActionLog.class);
    log.info("topic          :{}", annotation.topic());
    log.info("action         :{}", annotation.action());
  }

  @AfterReturning("actionLog()")
  public void afterReturning(){
    log.info("result        :{}", 200);
    log.info("=================== End ====================");
  }

  @AfterThrowing(pointcut = "actionLog()", throwing = "ex")
  public void afterThrowing(Throwable ex) {
    log.info("result        :{}", ex.getMessage());
    log.info("=================== End ====================");
  }

}

各注解说明:

@Aspect:声明该类为一个注解类;  

@Pointcut:定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等;  

@Before: 在切点之前,织入相关代码;  

@After: 在切点之后,织入相关代码;  

@AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;  

@AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;  

@Around: 在切入点前后织入代码,并且可以自由的控制何时执行切点;

4. 简单测试

编写测试controller

import com.cnhqd.authcenter.framework.common.log.ActionLog;
import com.cnhqd.authcenter.system.vo.SysAccountLoginVO;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("testAops")
public class TestAopsController {

    @GetMapping("get")
    @ActionLog(action = "get", topic = "测试AOP")
    public String get(String id) {
        return id;
    }

    @PostMapping("post")
    @ActionLog(action = "post", topic = "测试AOP")
    public String post(@RequestBody SysAccountLoginVO vo) {
        System.out.println(JsonUtils.toJsonString(vo));
        return "success";
    }

    @GetMapping("getEx")
    @ActionLog(action = "getEx", topic = "测试AOP")
    public String getEx() {
        throw new RuntimeException("getEx-这里是异常输出测试");
    }

    @PostMapping("postEx")
    @ActionLog(action = "postEx", topic = "测试AOP")
    public String postEx() {
        throw new RuntimeException("postEx-这里是异常输出测试");
    }
}

使用postman发送对应请求,观察控制台输出
postman-get
console-get
postman-getEx
console-getEx
postman-post
console-post
postman-postEx
console-postEx
可以看到日志可以正常输出,如有必要保存相关数据到数据库即可。

更多推荐

Spring学习 (一): IoC容器

前言参考廖雪峰Spring教程一、什么是IoC容器容器的意思可以理解为一个提供供程序正常运行,提供各种依赖的组件的包的环境。IoC,控制反转,实际上就是将原本由代码编写者控制的各个对象(组件)的生命周期托管给底层的容器,应用层不需要一个个定义好什么时候初始化,什么时候析构释放,所有组件不再由应用程序自己创建和配置,而是

蓝牙核心规范(V5.4)10.10-BLE 入门笔记之SMP和安全性

蓝牙篇之蓝牙核心规范(V5.4)深入详解汇总1.概述SMP是安全管理器协议,用于蓝牙低功耗系统的安全管理。SMP协议定义了配对和Key的分发过程的实现,以及用于实现这些方法的协议和工具。SMP的内容主要是配对和Key的分发,然后用Key对链路或数据进行加密。安全管理器协议(SMP)是协议栈的安全管理器组件的一部分。它支

【Android】SVGAPlayer的使用介绍

背景客户需要通过SVG来做直播场景的炫酷动画。故调用得到如下的工具库:GIthub-SVAGPlayer组装通过xml组装到项目中,然后调用提供的api实现自己的需求即可。<?xmlversion="1.0"encoding="utf-8"?><RelativeLayoutxmlns:android="http://s

9月13日扒面经

文章目录2)char可以存放汉字吗3)list,map,set区别是什么4)讲一下反射5)实现反射的类6)重载和重写区别7)类加载过程8)什么时候会内存泄漏9)子父类加载顺序10)String,StringBuilderStringBuffer区别,哪些是线程安全的,哪一个快一些11)线程创建方式,你常用的是哪个,为什

从0搭建夜莺v6基础监控告警系统(一):基础服务安装

文章目录1.写在前面1.1.官方文档传送门1.2.部署环境2.服务安装2.1.基础设置2.2.安装中间件2.3.安装nightingale-v62.4.安装VictoriaMetrics2.5.安装Categraf3.部署总结3.1.安装总结1.写在前面1.1.官方文档传送门项目介绍架构介绍仪表盘黄埔营培训计划相关信息

【OpenSSL】HMAC消息认证码

HMAC消息认证码哈希运算消息码(Hash-basedMessageAuthenticationCode)与密钥相关的单向散列函数应用在SSL协议中消息是否被正确传输消息完整性消息认证算法流程密钥填充0(填充到与散列函数分组长度一致)填充后的密钥与0X36做异或ipad与消息内容组合第一次与单向散列函数进行散列计算填充

HTTP 状态码

状态码状态码英文名称中文描述100Continue继续。客户端应继续其请求101SwitchingProtocols切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议200OK请求成功。一般用于GET与POST请求201Created已创建。成功请求并创建了新的资源202

【Spring Boot】拦截器学习笔记

一、普通拦截器1,新建类MyWebConfig实现WebMvcConfigurer,实现addInterceptors方法@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry//不拦截哪些请求.excludePathPatter

电磁逆设计中伴随变量法的详细指南:Python在Jupyter环境下的完整演示

第一部分:电磁逆设计与伴随变量法的基础介绍1.电磁逆设计简介电磁逆设计是一种寻找最优电磁结构的方法,以实现特定的电磁响应。与传统的电磁设计方法不同,逆设计方法不是从已知的结构出发,而是从期望的响应出发,反向求解最佳的结构参数。2.伴随变量法的概念伴随变量法是一种优化技术,广泛应用于多种工程领域,包括电磁逆设计。它的核心

jsoup框架技术文档--java爬虫--基本概念

阿丹:之前使用python写的爬虫,但是现在项目的技术选型是需要使用jsoup来爬取网页的数据。那就需要重新学习一个框架。首先了解一下整体框架的基本概念。jsoup的概念JSoup是一个开源的Java库,它用于处理HTML文档,类似于一个用于解析和操作HTML的瑞士军刀。其强大的功能使得对HTML的处理变得非常容易和简

2023/09/21 day5 qt

将注册的账号密码存储到数据库中登录的账号密码与数据库中的账号密码进行匹配头文件#ifndefDENGLU_H#defineDENGLU_H#include<QMainWindow>#include<QDebug>#include<QIcon>#include<QLabel>#include<QLineEdit>#inc

热文推荐