springboot整合aop,实现日志操作

前言:

整合之前,我们要明白aop是什么,为什么要用aop,aop能帮我们做什么。

答:AOP是面向切面编程(Aspect-Oriented Programming)的简称,它是一种编程思想,旨在在面向对象编程(OOP)的基础上进行功能模块的解耦和隔离。在传统的业务处理代码中,通常需要进行事务处理日志记录等操作,这些操作会分散到各个方法中,增加了开发和维护的难度。AOP通过预编译方式和运行期动态代理实现,在不修改源代码的情况下,将分散在各个方法中的重复代码提取出来,然后在程序编译或运行时,再将这些提取出来的代码应用到需要执行的地方。

因此,AOP能够帮我们做以下事情:

  1. 降低业务逻辑的耦合性,提高程序的可重用型和开发效率。
  2. 对业务逻辑的各个部分进行隔离,便于模块化管理。
  3. 提取公共功能,减少重复代码,提高代码的可维护性和可读性。
  4. 提供一种新的编程视角和工具,使开发人员可以专注于业务逻辑的实现,而不用过多关注其他功能的实现。

AOP能够提高开发效率和代码质量,降低维护成本。

=========================================================================

一、AOP介绍

1、名词介绍

(1)切面(Aspect):切入点和通知的集合
(2)连接点(Joinpoint):目标对象中可以被增强的所有方法
(3)通知(Advice):增强的代码(逻辑),分为前置,后置,最终,异常,环绕
(4)切入点(Pointcut):目标对象中经过匹配最终增强的方法
(5)引入(Introduction):动态的为某个类增加和减少方法
(6)目标对象(Target Object):被代理的对象
(7)AOP代理对象(AOP Proxy):AOP框架创建的代理对象,用于实现切面,调用方法
(8)织入(Weaving):将通知应用到切入点的过程

2、注解介绍

(1)@EnableAspectJautoProxy 用于springboot启动类,代表开启注解aop功能支持
                proxyTargetClass 是否强制使用CGlib的动态代理,默认false
                exposeProxy 是否通过aop框架暴露该代理对象,aopContext能够访问
(2)@Aspect 用于标注切面类
(3)@Pointcut 用于标识切入点
                value 切入点表达式
(4) @Before 前置通知
(5)@AfterReturning 后置通知
(6)@AfterThrowing 异常通知
(7)@After 最终通知
(8)@Around 环绕通知,环绕通知代表了一个完整的流程,因此环绕通知和上面的四个通知任选其一使用

3、切入点表达式

(1)execution - 根据表达式匹配,使用最多

        execution([修饰符] 返回类型 [包名.类名].方法名(参数列表) [异常])

        支持的通配符有 *:匹配所有。..:匹配多级包或者多个参数。+表示类以及子类

(2)within - 匹配方法所在的包或者类

(3)this - 用于向通知方法中传入代理对象的引用

(4)target - 用于向通知方法中传入目标对象的引用

(5)args - 用于向通知方法中传入参数,并且匹配参数个数

(6)@args - 和args都是匹配参数,但是@args要求传入切入点的参数必须标注指定注解,且不能是SOURCE源码注解,比如Lombok的

(7)@within - 匹配加了某个注解的类中的所有方法

(8)@target - 与@within类似,但是要求标注到类上的注解,必须为RUNTIME的

(9)@annotation - 匹配加了某个注解的方法

(10)bean 通过spring容器中的beName匹配

        可以使用通配符*来标识以什么开头,以什么结尾

二、整合AOP实现,实现日志操作

1、引入依赖

<!-- springboot aop -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.32</version>
</dependency>

2、类

package com.mgx.demo.common.enums;import lombok.AllArgsConstructor;
import lombok.Getter;/*** @author mgx*/
@AllArgsConstructor
@Getter
public enum CharacterEnum {/*** 特殊字符*///空白BLANK("")//空格, SPACE(" ")//换行, NEWLINE("\n")//enter换行, ENTER("\r")//左斜杠, SLASH("/")//双左斜杠, DOUBLE_SLASH("//")//反斜杠, BACKSLASH("\\")//单引号, QUOTES("'")//双引号, DOUBLE_QUOTES("\"")//撇号, APOSTROPHE("`")//艾特符, AT("@")//井号, HASHTAG("#")//dollar符, DOLLAR("$")//百分号, PERCENT("%")//异或运算符 数字相同返回0,否则为1, XOR("^")//and符, AND("&")//星号, ASTERISK("*")//等于号, EQUAL("=")//下划线, UNDERSCORE("_")//点, DOT(".")//句号, C_DOT("。")//逗号, COMMA(",")//中文逗号, C_COMMA(",")//管道符, PIPE("|")//双管道符, DOUBLE_PIPE("||")//问号, Q_MARK("?")//叹号, E_MARK("!")//加号, PLUS("+")//连字号、短横杠、减号, HYPHEN("-")//小于符, LT("<")//大于符, GT(">")//冒号, COLON(":")//分号, SEMICOLON(";")//中文分号, C_SEMICOLON(";")//左圆括号 round, L_R_BRACKETS("(")//右圆括号, R_R_BRACKETS(")")//左右圆括号, R_BRACKETS("()")//左方括号 square, L_S_BRACKETS("[")//右方括号, R_S_BRACKETS("]")//左右方括号, S_BRACKETS("[]")//左大括号 curly, L_C_BRACKETS("{")//右大括号, R_C_BRACKETS("{")//左右大括号, C_BRACKETS("{}");private final String character;public String value() {return character;}}
package com.mgx.demo.utils;import com.alibaba.fastjson.JSON;
import com.mgx.demo.common.enums.CharacterEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;/*** @author mgx*/
@Slf4j
public class LogUtil {/*** 接口请求日志** @param param 接口获取参数*/public static void param(Object... param) {RequestAttributes ra = RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes) ra;if (Objects.nonNull(sra)) {HttpServletRequest request = sra.getRequest();String url = request.getRequestURL().toString();log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : Arrays.toString(param));}}/*** 接口请求日志** @param param 封装后的参数,若数据结构较复杂,请考虑json转化string耗时及性能*/public static void paramObject(Object param) {RequestAttributes ra = RequestContextHolder.getRequestAttributes();ServletRequestAttributes sra = (ServletRequestAttributes) ra;if (Objects.nonNull(sra)) {HttpServletRequest request = sra.getRequest();String url = request.getRequestURL().toString();log.info("===============++++请求++++================\n地址:{}\n参数:{}", url, Objects.isNull(param) ? CharacterEnum.BLANK.value() : JSON.toJSONString(param));}}public static void logRequest(HttpServletRequest request) {log.info("===============++++请求++++================\n地址:{}\n方法:{}\nIP:{}", request.getRequestURL().toString(), request.getMethod(), request.getRemoteAddr());}}
package com.mgx.demo.config.aop;import com.alibaba.fastjson.JSON;import com.mgx.demo.annotation.LogRequestParam;
import com.mgx.demo.utils.LogUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;/***  自动打印日志*/
@Aspect
@Component
public class WebLogAspect {private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);@Pointcut("execution(public * com.mgx.demo.controller.*.*(..))")public void webLog() {}@AfterReturning(returning = "ret", pointcut = "webLog()")public void doAfterReturning(Object ret) {// 处理完请求,返回内容logger.info("RESPONSE : {}", JSON.toJSONString(ret));}@Before("@annotation(logRequestParam) || @within(logRequestParam)")public void doRequestParamLog(JoinPoint joinPoint, LogRequestParam logRequestParam) {// 获取方法参数Object[] args = joinPoint.getArgs();if (args != null) {if (args.length == 1) {LogUtil.paramObject(args[0]);} else {LogUtil.param(args);}}}}
package com.mgx.demo.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author mgx*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogRequestParam {
}
<?xml version="1.0" encoding="UTF-8"?>
<configuration><springProperty scope="context" name="logPath" source="project.log.config" defaultValue="${user.home}/springboot-mgx/logs"/><property name="LOG_HOME" value="${logPath}"/><!-- %m输出的信息, %p日志级别, %t线程名, %d日期, %c类的全名, %i索引 --><!-- appender是configuration的子节点,是负责写日志的组件 --><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><encoder><!--<pattern>${CONSOLE_LOG_PATTERN}</pattern> --><pattern>%date{yyyy-MM-dd HH:mm:ss} %highlight(%-5level) (%file:%line\)- %m%n</pattern><!-- 控制台也要使用utf-8,不要使用gbk --><charset>UTF-8</charset></encoder></appender><!-- RollingFileAppender:滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 --><!-- 1.先按日期存日志,日期变了,将前一天的日志文件名重命名为xxx%日期%索引,新的日志仍然是sys.log --><!-- 2.如果日期没有变化,但是当前日志文件的大小超过1kb时,对当前日志进行分割 重名名 --><appender name="ALL" class="ch.qos.logback.core.rolling.RollingFileAppender"><File>${LOG_HOME}/sys.log</File><!-- rollingPolicy:当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名。 --><!-- TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动 --><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><!-- 活动文件的名字会根据fileNamePattern的值,每隔一段时间改变一次 --><!-- 文件名:pileLog/2020/10/10/sys.2020-10-10_13.log --><fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.%i.log</fileNamePattern><timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"><!-- maxFileSize:这是活动文件的大小,默认值是10MB --><maxFileSize>30MB</maxFileSize></timeBasedFileNamingAndTriggeringPolicy></rollingPolicy><encoder><!-- pattern节点,用来设置日志的输入格式 --><pattern>%d %p (%file:%line\)- %m%n</pattern><!-- 记录日志的编码 --><charset>UTF-8</charset> <!-- 此处设置字符集 --></encoder></appender><!--ERROR--><appender name="ERROR" class="ch.qos.logback.core.rolling.RollingFileAppender"><filter class="ch.qos.logback.classic.filter.LevelFilter"><level>ERROR</level><onMatch>ACCEPT</onMatch><onMismatch>DENY</onMismatch></filter><file>${LOG_HOME}/sys.error.log</file><append>true</append><rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><fileNamePattern>${LOG_HOME}/%d{yyyy-MM/dd/HH}/sys.error.%i.log</fileNamePattern><maxFileSize>30MB</maxFileSize></rollingPolicy><encoder><Pattern>%d %p (%file:%line\)- %m%n</Pattern><charset>UTF-8</charset></encoder></appender><contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"><resetJUL>true</resetJUL></contextListener><!-- 控制台日志输出级别 --><root level="info"><appender-ref ref="CONSOLE"/><appender-ref ref="ALL"/><appender-ref ref="ERROR"/></root><!-- 指定项目中某个包,当有日志操作行为时的日志记录级别 --><!-- com.dmyc为根包,也就是只要是发生在这个根包下面的所有日志操作行为的权限都是DEBUG --><!-- 级别依次为【从高到低】:FATAL > ERROR > WARN > INFO > DEBUG > TRACE  --><logger name="com.mgx.demo.controller" level="DEBUG"/><logger name="com.mgx.demo.mapper" level="DEBUG"/><logger name="springfox" level="ERROR"/></configuration>

application

 需要打印日志的地方,在类上加上自定义注解

3、测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/137088.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虹科方案 | LIN/CAN总线汽车零部件测试方案

文章目录 摘要一、汽车零部件测试的重要性&#xff1f;二、虹科的测试仿真工具如何在汽车零部件测试展露头角&#xff1f;三、应用场景**应用场景1&#xff1a;方向盘开关的功能测试****应用场景2&#xff1a;各类型电机的控制测试****应用场景3&#xff1a;RGB氛围灯的功能测试…

win系统环境搭建(六)——Windows安装nginx

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;六&#xff09;——Windows安装nginx 本系列windows环境搭建开始讲解如何给win系统搭建环境&#xff0c;本人所用系统是腾讯云服务器的Windows Server 2022&#xff0c;你可以理解成就是你用的windows10…

建立表使用约束

1.建立表 二、使用约束 1.NOT NULL 非空约束&#xff0c;规定某个字段不能为空&#xff0c;NOT NULL 约束强制列不接受 NULL 值。 NOT NULL 约束强制字段始终包含值。这意味着&#xff0c;如果不向字段添加值&#xff0c;就无法插入新记录或者更新记录。下面的 SQL 强制表&qu…

最小二乘法的实现与线性回归的应用

1. 简介 简单线性回归中&#xff0c;您有一个因变量y和一个自变量X。该模型可以表示为&#xff1a; y m x b ymxb ymxb 其中 x x x: 自变量 y y y: 因变量 m m m: 斜率 b b b: 截距 最小二乘法是回归分析中用于估计线性回归模型参数的标准方法。它可以最小化误差的平方和&…

LVS+Haproxy

LVSHaproxy 一、Haproxy简介1.1、Haproxy应用分析1.2、Haproxy的特性1.3、常见负载均衡策略1.4、LVS、Haproxy、Nginx区别1.5、 Haproxy的优点1.6、常见的Web集群调度器 二、Haproxy部署实例四、日志定义优化 一、Haproxy简介 Haproxy 是一个使用C语言编写的自由及开放源代码软…

mysql odbc驱动安装

到官网下载对应版本的驱动包 可以选择对应版本&#xff0c;建议使用最新版本即可 查看powerDesigner对应的位数&#xff0c;位数对应不上的话&#xff0c;会找不到 powerDesigner 可以参考&#xff1a;powerDesigner安装 我这里装的是32位的 下载对应版本的即可 下载完成&a…

深入理解Kubernetes Pod调试

调试运行中的容器和Pod不像直接调试进程那么容易&#xff0c;本文介绍了通过临时容器共享命名空间的方式调试业务容器进程的方法。原文: Debugging Kubernetes Pods: Deep Dive ZanUnsplash 调试pod最简单的方法是在有问题的pod中执行命令&#xff0c;并尝试排除故障。这种方法…

软件定制开发的优势与步骤|APP搭建|小程序

软件定制开发的优势与步骤|APP搭建|小程序 定制开发的优势&#xff1a; 1. 满足特定需求&#xff1a;定制开发可以根据客户的实际需求进行设计和开发&#xff0c;使得软件系统能够更好地满足客户的业务目标。 2. 优化用户体验&#xff1a;通过深入了解客户的需求&#xff0c;定…

视频监控管理平台/视频汇聚/视频云存储EasyCVR安全检查的相关问题及解决方法3.0

智能视频监控系统/视频云存储/集中存储/视频汇聚平台EasyCVR具备视频融合汇聚能力&#xff0c;作为安防视频监控综合管理平台&#xff0c;它支持多协议接入、多格式视频流分发&#xff0c;视频监控综合管理平台EasyCVR支持海量视频汇聚管理&#xff0c;可应用在多样化的场景上&…

若依前端使用

初始化页面时&#xff0c;路由上加参数 1. 多个菜单对应一个页面&#xff0c;默认查询的数据状态不一样 vue 页面上 通过 debugger; 查看所有的参数&#xff0c; 最后取到了 2. Vue warn]: Error in callback for immediate watcher “fileList”: “TypeError: Cannot read p…

双系统ubuntu20.04(neotic版本)从0实现Gazebo仿真slam建图

双系统ubuntu20.04(neotic版本)从0实现Gazebo仿真slam建图 昨晚完成了ROS的多机通讯&#xff0c;还没来得及整理相关操作步骤&#xff0c;在进行实际小车的实验之前&#xff0c;还是先打算在仿真环境中进行测试&#xff0c;熟悉相关的操作步骤&#xff0c;计划通过虚拟机&…

【深度学习】 Python 和 NumPy 系列教程(九):NumPy详解:1、创建数组的n种方式

目录 一、前言 二、实验环境 三、NumPy 0. 多维数组对象&#xff08;ndarray&#xff09; a. 多维数组的属性 1. 创建数组 a. 使用numpy.array函数&#xff1a; b. 使用numpy.zeros函数 c. 使用numpy.ones函数 d. 使用numpy.arange函数 e. 使用numpy.linspace函数 …

2023Q2全球可穿戴腕带出货量达 4400 万台

全球可穿戴设备市场在2023年第二季度继续保持增长态势&#xff0c;总出货量达到了4400万台&#xff0c;同比增长了6%。这一增长得益于消费者对于可穿戴设备的需求不断增加&#xff0c;以及不同细分市场的需求反弹。 根据市场研究机构 Canalys 的最新报告&#xff0c;全球可穿戴…

Android EditText筛选+选择功能开发

在日常开发中经常会遇到这种需求&#xff0c;EditText既需要可以筛选&#xff0c;又可以点击选择。这里筛选功能用的是AutoCompleteTextView&#xff0c;选择功能使用的是第三方库https://github.com/kongzue/DialogX。 Android AutoCompleteTextView(自动完成文本框)的基本使用…

【物联网】简要解释RTK(Real-Time Kinematic)>>实时动态差分定位

引言&#xff1a; RTK&#xff08;Real-Time Kinematic&#xff09;技术是一种基于差分GPS的高精度定位技术&#xff0c;它通过实时通信和数据处理&#xff0c;能够提供厘米级甚至亚米级的定位精度。RTK技术在许多领域都得到了广泛应用&#xff0c;如测绘、航空航天、农业等。本…

详解Nacos和Eureka的区别

文章目录 Eureka是什么Nacos是什么Nacos的实现原理 Nacos和Eureka的区别CAP理论连接方式服务异常剔除操作实例方式自我保护机制 Eureka是什么 Eureka 是Spring Cloud 微服务框架默认的也是推荐的服务注册中心, 由Netflix公司与2012将其开源出来,Eureka基于REST服务开发,主要用…

【C++STL基础入门】list改、查操作

文章目录 前言一、list查操作1.1 迭代器循环1.2 for_each函数 二、list改操作2.1 迭代器修改2.2 assign函数2.3 运算符 总结 前言 C标准模板库&#xff08;STL&#xff09;是C语言中非常重要的部分&#xff0c;它提供了一组通用的模板类和函数&#xff0c;用于处理常见的数据结…

七、运算符

运算符 1.运算符1.1.赋值运算符1.2.算数运算符1.3.自增和自减运算符1.4.比较运算符1.5.逻辑运算符1.6.位运算符1.6.1.按位与运算1.6.2.按位或运算1.6.3.按位取反运算1.6.4.按位异或运算1.6.5.移位操作1.6.6.复合赋值运算符1.6.7.三元运算符1.6.8.运算符优先级 1.7.训练11.8.训练…

win系统环境搭建(九)——Windows安装chatGPT

windows环境搭建专栏&#x1f517;点击跳转 win系统环境搭建&#xff08;九&#xff09;——Windows安装chatGPT 本系列windows环境搭建开始讲解如何给win系统搭建环境&#xff0c;本人所用系统是腾讯云服务器的Windows Server 2022&#xff0c;你可以理解成就是你用的windows…

上位机在自动化控制中的作用和优势是什么?

上位机在自动化控制中的作用和优势是什么&#xff1f; 自动化控制编程领域包括单片机、PLC、机器视觉和运动控制等方向。输入“777”&#xff0c;即刻获取关于上位机开发和数据可视化的专业学习资料&#xff0c;近年来&#xff0c;上位机编程逐渐兴起&#xff0c;正在逐步替代…