当前位置: 首页 > news >正文

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、测试

相关文章:

springboot整合aop,实现日志操作

前言&#xff1a; 整合之前&#xff0c;我们要明白aop是什么&#xff0c;为什么要用aop&#xff0c;aop能帮我们做什么。 答&#xff1a;AOP是面向切面编程&#xff08;Aspect-Oriented Programming&#xff09;的简称&#xff0c;它是一种编程思想&#xff0c;旨在在面向对象…...

openjdk和oracle jdk的区别

OpenJDK 和 Oracle JDK 都是 Java Development Kit (JDK) 的不同实现&#xff0c;用于开发和运行 Java 应用程序。它们有一些区别&#xff0c;但也有很多相似之处。以下是它们之间的主要区别&#xff1a; 开源性质&#xff1a; OpenJDK 是开源的&#xff0c;由一个社区维护和开…...

深度学习-Python调用ONNX模型

目录 ONNX模型使用流程 获取ONNX模型方法 使用ONNX模型 手动编写ONNX模型 Python调用ONNX模型 常见错误 错误raise ValueError...&#xff1a; 错误&#xff1a;Load model model.onnx failed 错误&#xff1a;CUDAExecutionProvider is not in available provider 错…...

[2023.09.24]: 今天差点又交白卷

今天周日&#xff0c;搞定了家里装修的一件事情&#xff0c;周末的事特别多&#xff0c;总算在10点的时候&#xff0c;解决了昨天那个输入焦点设置失败的问题。 在探索Rust编写基于web_sys的WebAssembly编辑器&#xff1a;挑战输入光标定位的实践中&#xff0c;我们总结了设置光…...

css,环形

思路&#xff1a; 1.先利用conic-gradient属性画一个圆&#xff0c;然后再叠加 效果图 <template><div class"ring"><div class"content"><slot></slot></div></div> </template> <script> import …...

php食堂点餐系统hsg5815ABA2程序-计算机毕业设计源码+数据库+lw文档+系统+部署

php食堂点餐系统hsg5815ABA2程序-(毕业设计毕设项目源代码课程设计程序设计指导xz2023) php食堂点餐系统hsg5815ABA2程序-计算机毕业设计源码数据库lw文档系统部署...

Vite打包时使用plugin解决浏览器兼容问题

一、安装Vite插件 在终端输入如下命令&#xff1a; npm add -D vitejs/plugin-legacy 二、配置config文件 在项目目录下创建vite.config.js文件夹&#xff0c;配置如下代码&#xff1a; import { defineConfig } from "vite"; import legacy from "vitejs/pl…...

java Excel 自用开发模板

下载导出 import com.hpay.admin.api.vo.Message; import com.hpay.admin.dubbo.IConfigDubboService; import com.hpay.admin.dubbo.IFileExportLogDubboService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.apache.poi.hss…...

34.CSS魔线图标的悬停效果

效果 源码 index.html <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Icon Fill Hover Effects</title> <link rel="stylesheet" h…...

Django — 会话

目录 一、Cookie1、介绍2、作用3、工作原理4、结构5、用途6、设置7、获取 二、Session1、介绍2、作用3、工作原理3、类型4、用途5、设置6、获取7、清空信息 三、Cookie 和 Session 的区别1、存储位置2、安全性3、数据大小4、跨页面共享5、生命周期6、实现机制7、适用场景 四、P…...

SpringBoot集成easypoi实现execl导出

<!--easypoi依赖&#xff0c;excel导入导出--><dependency><groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.4.0</version></dependency>通过Exce注解设置标头名字和单…...

第9章 【MySQL】InnoDB的表空间

表空间 是一个抽象的概念&#xff0c;对于系统表空间来说&#xff0c;对应着文件系统中一个或多个实际文件&#xff1b;对于每个独立表空间来说&#xff0c;对应着文件系统中一个名为 表名.ibd 的实际文件。大家可以把表空间想象成被切分为许许多多个 页 的池子&#xff0c;当我…...

工作、生活常用免费api接口大全

手机号码归属地&#xff1a;提供三大运营商的手机号码归属地查询。全国快递物流查询&#xff1a;1.提供包括申通、顺丰、圆通、韵达、中通、汇通等600快递公司在内的快递物流单号查询。2.与官网实时同步更新。3.自动识别快递公司。IP归属地-IPv4区县级&#xff1a;根据IP地址查…...

寻找单身狗

在一个数组中仅出现一次&#xff0c;其他数均出现两次&#xff0c;这个出现一次的数就被称为“单身狗“。 一.一个单身狗 我们知道异或运算操作符 ^ &#xff0c;它的特点是对应二进制位相同为 0&#xff0c;相异为 1。 由此我们容易知道两个相同的数,进行异或运算得到的结果…...

【pytest】 allure 生成报告

1. 下载地址 官方文档; Allure Framework 参考文档&#xff1a; 最全的PytestAllure使用教程&#xff0c;建议收藏 - 知乎 https://github.com/allure-framework 1.2安装Python依赖 windows&#xff1a;pip install allure-pytest 2. 脚本 用例 import pytest class …...

动态链接库搜索顺序

动态链接库搜索顺序 同一动态链接库 (DLL) 的多个版本通常存在于操作系统 (OS) 内的不同文件系统位置。 可以通过指定完整路径来控制从中加载任何给定 DLL 的特定位置。 但是&#xff0c;如果不使用该方法&#xff0c;则系统会在加载时搜索 DLL&#xff0c;如本主题中所述。 DL…...

【CAN、LIN通信的区分】

CAN和LIN是两种不同的通信协议&#xff0c;用于不同的应用场景。CAN&#xff08;Controller Area Network&#xff09;是一种高速、可靠、多节点的串行通信协议&#xff0c;主要用于汽车电子领域的高速数据传输和控制&#xff1b;而LIN&#xff08;Local Interconnect Network&…...

Redis环境配置

【Redis解压即可】链接&#xff1a;https://pan.baidu.com/s/1y4xVLF8-8PI8qrczbxde9w?pwd0122 提取码&#xff1a;0122 【Redis桌面工具】 链接&#xff1a;https://pan.baidu.com/s/1IlsUy9sMfh95dQPeeM_1Qg?pwd0122 提取码&#xff1a;0122 Redis安装步骤 1.先打开Redis…...

UG NX二次开发(C++)-采用std::vector对体对象的质心进行排序

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、体对象质心结构体的构造3、采用NXOpen获取part中的所有体对象4、通过遍历体对象集合来实现std::vector<MyBody>的赋值5、对结构体排序6、调用的完整源代码7、生成dll并测试一、pan…...

一点思考|关于「引领性研究」的一点感悟

前言&#xff1a;调研过这么多方向之后&#xff0c;对研究方向的产生与发展具备了一些自己的感悟&#xff0c;尤其是在AI安全领域。私认为&#xff0c;所谓有价值、有意义的研究&#xff0c;就是指在现实社会中能够产生波澜、为国家和社会产生一定效益的研究。 举例来说&#x…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄

文&#xff5c;魏琳华 编&#xff5c;王一粟 一场大会&#xff0c;聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中&#xff0c;汇集了学界、创业公司和大厂等三方的热门选手&#xff0c;关于多模态的集中讨论达到了前所未有的热度。其中&#xff0c;…...

EtherNet/IP转DeviceNet协议网关详解

一&#xff0c;设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络&#xff0c;本网关连接到EtherNet/IP总线中做为从站使用&#xff0c;连接到DeviceNet总线中做为从站使用。 在自动…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...

(一)单例模式

一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...