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

Spring AOP+注解方式实现系统日志记录

一、前言

在上篇文章中,我们使用了AOP思想实现日志记录的功能,代码中采用了指定连接点方式(@Pointcut(“execution(* com.nowcoder.community.controller..(…))”)),指定后不需要在进行任何操作就可以记录日志了,但是如果我们对某些controller不想记录日志,就需要更改指定的切点,灵活性较差。因此采用注解+AOP方式,实现更灵活的日志记录功能。

二、注解实现代码

package com.nowcoder.community.annotation;import java.lang.annotation.*;/*** @author Janson* @Description AOP日志记录注解* @Date 2023/5/12* @Target LogAspect 注解的作用目标* @Retention 指定注解的保留时间*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LogAspect {/*** title 自定义名称* description 自定义描述* @return*/String title() default "";String description() default "";
}

三、AOP日志记录类实现代码

定义切点(织入点)
execution(* com.nowcoder.community.controller..(…))
- 第一个 * 表示 支持任意类型返回值的方法
- com.nowcoder.community.controller 表示这个包下的类
- 第二个 * 表示 controller包下的任意类
- 第三个 * 表示 类中的任意方法
- (…) 表示方法可以拥有任意参数
可以根据自己的需求替换。

package com.nowcoder.community.aspect;import com.nowcoder.community.annotation.LogAspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;/*** @author Janson* @Description AOP日志记录,此方案不统一设置连接点 @Pointcut,而是采用注解方式,指定连接的方法* @Date 2023/5/12*/
@Aspect
@Component
public class LogAspectAnnotationTest {/*** 定义切点(织入点)*  execution(* com.nowcoder.community.controller.*.*(..))*      - 第一个 * 表示 支持任意类型返回值的方法*      - com.nowcoder.community.controller 表示这个包下的类*      - 第二个 * 表示 controller包下的任意类*      - 第三个 * 表示 类中的任意方法*      - (..) 表示方法可以拥有任意参数*   可以根据自己的需求替换。**/@Before(value = "@annotation(controllerLog)")public void before(JoinPoint joinPoint, LogAspect controllerLog){String className = joinPoint.getClass().getName();String methodName = joinPoint.getSignature().getName();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null){return;}String ip = attributes.getRequest().getRemoteHost();String requestURI = attributes.getRequest().getRequestURI();String requestMethod = attributes.getRequest().getMethod();String title = controllerLog.title();String description = controllerLog.description();System.out.println("title is " + title + ",description is " + description);System.out.println("before excute ······");System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,requestMethod,className,methodName));}@After(value = "@annotation(controllerLog)")public void after(JoinPoint joinPoint, LogAspect controllerLog){String className = joinPoint.getClass().getName();String methodName = joinPoint.getSignature().getName();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null){return;}String ip = attributes.getRequest().getRemoteHost();String requestURI = attributes.getRequest().getRequestURI();String requestMethod = attributes.getRequest().getMethod();String title = controllerLog.title();String description = controllerLog.description();System.out.println("title is " + title + ",description is " + description);System.out.println("after excute ······");System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,requestMethod,className,methodName));}@AfterReturning(value = "@annotation(controllerLog)")public void afterReturning(JoinPoint joinPoint, LogAspect controllerLog){String className = joinPoint.getClass().getName();String methodName = joinPoint.getSignature().getName();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null){return;}String ip = attributes.getRequest().getRemoteHost();String requestURI = attributes.getRequest().getRequestURI();String requestMethod = attributes.getRequest().getMethod();String title = controllerLog.title();String description = controllerLog.description();System.out.println("title is " + title + ",description is " + description);System.out.println("afterReturning excute ······");System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,requestMethod,className,methodName));}@AfterThrowing(value = "@annotation(controllerLog)",throwing = "e")public void afterThrowing(JoinPoint joinPoint, LogAspect controllerLog,Exception e){String className = joinPoint.getClass().getName();String methodName = joinPoint.getSignature().getName();ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null){return;}String ip = attributes.getRequest().getRemoteHost();String requestURI = attributes.getRequest().getRequestURI();String requestMethod = attributes.getRequest().getMethod();String title = controllerLog.title();String description = controllerLog.description();System.out.println("title is " + title + ",description is " + description);System.out.println("afterThrowing excute ······" + e.getMessage());System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s],请求失败原因: [%s]", ip,requestURI, requestMethod,className,methodName,e.getMessage()));}@Around(value = "@annotation(controllerLog)")public void around(ProceedingJoinPoint joinPoint, LogAspect controllerLog) throws Throwable {String className = joinPoint.getTarget().getClass().getName();String methodName = joinPoint.getSignature().getName();System.out.println("className is : " + className + ". methodName is : " + methodName);ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();if (attributes == null){return;}// 请求ipString ip = attributes.getRequest().getRemoteHost();// 请求路径String requestURI = attributes.getRequest().getRequestURI();// 请求方法String requestMethod = attributes.getRequest().getMethod();String title = controllerLog.title();String description = controllerLog.description();System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,requestMethod,className,methodName));Object obj = null;try {obj = joinPoint.proceed();} catch (Throwable e) {System.out.println("我捕获了异常");throw new RuntimeException("执行失败",e);}System.out.println(String.format("用户: [%s] 的请求路径为:[%s], 请求方式为: [%s],请求类名为: [%s], 请求方法名为: [%s]", ip,requestURI,requestMethod,className,methodName));System.out.println("around excute after ········");}
}

相关文章:

Spring AOP+注解方式实现系统日志记录

一、前言 在上篇文章中,我们使用了AOP思想实现日志记录的功能,代码中采用了指定连接点方式(Pointcut(“execution(* com.nowcoder.community.controller..(…))”)),指定后不需要在进行任何操作就可以记录日志了&…...

OpenGL 4.0的Tessellation Shader(细分曲面着色器)

细分曲面着色器(Tessellation Shader)处于顶点着色器阶段的下一个阶段,我们可以看以下链接的OpenGL渲染流水线的图:Rendering Pipeline Overview。它是由ATI在2001年率先设计出来的。 目录 细分曲面着色器细分曲面Patch细分曲面控…...

项目经理如何及时掌控项目进度?

延迟是指超出计划的时间,而无法掌控则意味着管理者对实际情况一无所知。 为了解决这些问题,我们需要建立好的制度和沟通机制。例如使用项目管理软件来跟踪进度、定期开会并避免沟通障碍等。 管理者可以建立相关制度: 1、建立进度记录制度。…...

HTML <applet> 标签

HTML5 中不支持 <applet> 标签在 HTML 4 中用于定义嵌入式小程序(插件)。 实例 一个嵌入的 Java applet: <applet code="Bubbles.class" width="350" height="350"> Java applet that draws animated bubbles. </applet&g…...

加密与解密

加密与解密 加密方式分类 加密方式主要分为两种 一种是对称加密一种是非对称加密 对称加密 对称和非对称两种方式主要说的是加密和解密两个过程。 如果对数据用一个钥匙进行了加密&#xff0c;那么&#xff0c; 你想成功读取到这个加密了的数据的话&#xff0c;就必须对这…...

京东金融Android瘦身探索与实践

作者&#xff1a;京东科技 冯建华 一、背景 随着业务不断迭代更新&#xff0c;App的大小也在快速增加&#xff0c;2019年~2022年期间一度超过了117M&#xff0c;期间我们也做了部分优化如图1红色部分所示&#xff0c;但在做优化的同时面临着新的增量代码&#xff0c;包体积一直…...

open3d-ml 读取SemanticKITTI Dataset

目录 1. 下载dataset 2. 读取并做可视化 3. 源码阅读 3.1 读取点云数据-bin格式 3.2 读取标注数据-.label文件 3.3 读取配置 3.4 test 3.5 train 1. 下载dataset 以SemanticKITTI为例。下载链接&#xff1a;http://semantic-kitti.org/dataset.html#download 把上面三…...

6.其他函数

1.时间日期类 -- current_date() 返回当前日期 -- date_add(date, n) 返回从date开始n天之后的日期 -- date_sub(date, n) 返回从date开始n天之前的日期 -- datediff(date1, date2) 返回date1-date2的日期差 -- year(date) 返回…...

2023年宜昌市中等职业学校技能大赛 “网络搭建与应用”竞赛题-1

2023年宜昌市中等职业学校技能大赛 “网络搭建与应用”竞赛题 一、竞赛内容分布 “网络搭建及应用”竞赛共分二个部分&#xff0c;其中&#xff1a; 第一部分&#xff1a;企业网络搭建部署项目&#xff0c;占总分的比例为50%&#xff1b; 第二部分&#xff1a;企业网络服…...

Linux权限划分的原则

考察的不仅是一个具体的指令&#xff0c;还考察对技术层面的认知。 如果对 Linux 权限有较深的认知和理解&#xff0c;那么完全可以通过查资料去完成具体指令的执行。更重要的是&#xff0c;认知清晰的程序员可以把 Linux 权限管理的知识迁移到其他的系统设计中。 权限抽象 一…...

PhotoScan拼接无人机航拍RGB照片

目录 背景 拼接步骤 1.新建并保存项目 2.添加照片 3.对齐照片 4.添加标记&#xff08;Markers&#xff09; 5.添加地面控制点 6.建立批处理任务 7.使用批处理文件进行批处理 8.导出DEM 9.导出DOM 背景 本文介绍使用地面控制点&#xff08;GCPs&#xff09;拼接​​…...

【设计模式】责任链模式的介绍及其应用

责任链的介绍 责任链模式是一种对象的行为模式。在责任链模式里&#xff0c;很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递&#xff0c;直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求&a…...

一些思考关于行业,关于方向,关于人生路线

一些碎碎念 选择与视角工程与科研平台与信息敢问路在何方 选择与视角 两年前的秋招时几乎速通了出现在学校招聘会上的几乎出现的每一个offer&#xff0c;那也是我人生第一次收获到如此多的肯定与选择&#xff0c;为此我在b站上上传了一期就业解读&#xff0c;作为一个冷门到几…...

fbx sdk的使用介绍

我们平时需要围绕fbx写一些小工具&#xff0c;虽说使用ascii格式的fbx可以直接进行字符串解析&#xff0c;并且网上也有一些基于ascii解析的开源库&#xff0c;但在制作一些通用的工具时&#xff0c;使用fbx sdk进行编写肯定是最好的。 1.下载fbx sdk和cmake 要用cmake生成vi…...

mvvm模式

mvvm是Model-View-ViewModel的缩写&#xff0c;是前端的一种架构模式 M - Model&#xff0c;模型 对应data数据 V - View&#xff0c;视图 对应用户界面&#xff0c;DOM元素 VM - ViewModel&#xff0c;视图模型 对应vue实例对象&#xff0c;是连接model和view的桥梁 …...

Spring/SpringBoot常用注解总结

为什么要写这篇文章&#xff1f; 最近看到网上有一篇关于 SpringBoot 常用注解的文章被转载的比较多&#xff0c;我看了文章内容之后属实觉得质量有点低&#xff0c;并且有点会误导没有太多实际使用经验的人&#xff08;这些人又占据了大多数&#xff09;。所以&#xff0c;自…...

2023 年第八届数维杯大学生数学建模挑战赛 B 题 节能列车运行控制优化策略

在城市交通电气化进程快速推进的同时&#xff0c;与之相应的能耗增长和负面效应也 在迅速增加。城市轨道交通中的快速增长的能耗给城轨交通的可持续性发展带来 负担。2018 年&#xff0c;北京、上海、广州地铁负荷占全市总负荷的 1.5%-2.5%,成为了 城市电网的最大单体负荷[1]。…...

【Swift】 NSButton的用法和示例

NSButton是macOS开发中常用的控件&#xff0c;用于创建按钮。它有许多用法和需要注意的事项&#xff0c;下面介绍其中的一些。 1. 创建按钮&#xff1a;使用init(frame:)或init(title:action:)初始化按钮 let button NSButton(frame: NSRect(x: 0, y: 0, width: 100, height…...

2023什么蓝牙耳机好?经销商盘点新手必入蓝牙耳机品牌

蓝牙耳机是除手机外我们使用频率最高的数码产品&#xff0c;我做蓝牙耳机经销商五年来&#xff0c;对各个品牌都有深入了解。近期看到很多新手们咨询什么蓝牙耳机好&#xff0c;我给大家盘点一下新手必看的五大蓝牙耳机品牌。 1.JEET Air 2蓝牙耳机 推荐理由&#xff1a;专为舒…...

MySQL基础(二十)MySQL的数据目录

1. MySQL8的主要目录结构 find / -name mysql1.1 数据库文件的存放路径 show variables like datadir; # /var/lib/mysql/1.2 相关命令目录 相关命令目录&#xff1a;/usr/bin 和/usr/sbin。 1.3 配置文件目录 配置文件目录&#xff1a;/usr/share/mysql-8.0&#xff08;命…...

Spark 之 入门讲解详细版(1)

1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室&#xff08;Algorithms, Machines, and People Lab&#xff09;开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目&#xff0c;8个月后成为Apache顶级项目&#xff0c;速度之快足见过人之处&…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

API网关Kong的鉴权与限流:高并发场景下的核心实践

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言 在微服务架构中&#xff0c;API网关承担着流量调度、安全防护和协议转换的核心职责。作为云原生时代的代表性网关&#xff0c;Kong凭借其插件化架构…...

6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙

Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...