AOP应用之系统操作日志
本文演示下如何使用AOP,去实现系统操作日志功能。
实现步骤
- 引入AOP包
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.6.6</version></dependency>
- 定义数据模型
package com.angel.ocean.domain.entity;import lombok.Data;
import java.util.Date;@Data
public class Syslog {/*** 主键**/private Long id;/*** ip 地址**/private String ip;/*** 类名**/private String className;/*** 方法名称**/private String methodName;/*** 传参**/private String params;/*** 执行结果, true-成功,false-失败**/private boolean status;/*** 响应信息**/private String response;/*** 业务类型**/private String remark;/*** 触发时间**/private Date createTime;/*** 操作用户**/private String createBy;
}
- 定义系统日志注解SyslogAnno
package com.angel.ocean.annotation;import java.lang.annotation.*;/*** 定义系统日志注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SyslogAnno {String value() default "";}
- 定义切面SyslogAspect
package com.angel.ocean.aspect;import com.alibaba.fastjson2.JSON;
import com.angel.ocean.annotation.SyslogAnno;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.runner.SyslogHandlerTask;
import com.angel.ocean.util.LogDataUtil;
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 java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;/**1. 日志切面*/
@Slf4j
@Aspect
@Component
public class SyslogAspect {@Pointcut("@annotation(com.angel.ocean.annotation.SyslogAnno)")public void logPointCut() {}@AfterReturning(value = "logPointCut()", returning = "result")public void normalLog(JoinPoint point, Object result) {try {Syslog syslog = getSysLog(point);syslog.setStatus(true);syslog.setResponse(JSON.toJSONString(result));SyslogHandlerTask.LOG_QUEUE.offer(syslog);} catch (Exception e) {log.error("SyslogAspect.normalLog() error. ", e);}}@AfterThrowing(value = "logPointCut()", throwing = "throwable")public void exceptionLog(JoinPoint point, Throwable throwable) {try {Syslog syslog = getSysLog(point);syslog.setStatus(false);syslog.setResponse(throwable.getMessage());SyslogHandlerTask.LOG_QUEUE.offer(syslog);} catch (Exception e) {log.error("SyslogAspect.exceptionLog() error. ", e);}}private Syslog getSysLog(JoinPoint joinPoint) {Syslog sysLog = new Syslog();MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();SyslogAnno sysLogAnno = method.getAnnotation(SyslogAnno.class);if (sysLogAnno != null) {sysLog.setRemark(sysLogAnno.value());}// 请求的 类名、方法名String className = joinPoint.getTarget().getClass().getName();String methodName = signature.getName();sysLog.setClassName(className);sysLog.setMethodName(methodName);// 请求的参数Object[] args = joinPoint.getArgs();try {List<String> list = new ArrayList<>();for (Object o : args) {list.add(JSON.toJSONString(o));}sysLog.setParams(list.toString());} catch (Exception e) {log.error("SyslogAspect.saveLog() error.", e);}sysLog.setIp(LogDataUtil.getIP());sysLog.setCreateBy(LogDataUtil.getUserId());sysLog.setCreateTime(new Date());return sysLog;}
}
工具类
package com.angel.ocean.util;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;@Slf4j
public class LogDataUtil {private LogDataUtil() {}/*** 获取用户IP地址*/public static String getIP() {String ip = "";try {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();ip = request.getRemoteAddr();} catch (Exception e) {log.error("GetIPException", e);}return ip;}/*** 获取用户ID*/public static String getUserId() {String userId = "";try {HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();userId = request.getHeader("userId");} catch (Exception e) {log.error("GetUserIdException", e);}return userId;}
}
- 定义日志数据处理SyslogHandlerTask
package com.angel.ocean.runner;import cn.hutool.core.collection.CollUtil;
import com.angel.ocean.domain.entity.Syslog;
import com.angel.ocean.service.SyslogService;
import com.google.common.collect.Queues;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;@Slf4j
@Component
public class SyslogHandlerTask implements CommandLineRunner {@Resourceprivate SyslogService syslogService;/*** 操作日志队列*/public static final BlockingQueue<Syslog> LOG_QUEUE = new LinkedBlockingQueue<>();@Overridepublic void run(String... strings) throws Exception {new Thread(() -> {List<Syslog> SyslogList = new ArrayList<>();while (true) {try {Queues.drain(LOG_QUEUE, SyslogList, 100, 500, TimeUnit.MILLISECONDS);if (CollUtil.isNotEmpty(SyslogList)) {syslogService.batchInsert(SyslogList);SyslogList.clear();} else {Thread.sleep(500);}} catch (Exception e) {log.error("SyslogHandlerTask error={}", e.getMessage(), e);}}}, "Syslog_Props_Mysql").start();}
}
- 打包成系统操作日志SDK (ocean-log)
如何使用
继承系统操作日志SDK
<dependency><groupId>com.angel.ocean</groupId><artifactId>ocean-log</artifactId><version>1.0.0</version>
</dependency>
在Api的添加/修改/删除等方法上,添加SyslogAnno注解
@ApiModelProperty(value = "保存角色信息表")
@PostMapping("save")
@SyslogAnno("添加角色")
public ApiResult<?> save(@RequestBody SysRoleDTO dto) {service.save(dto);return ApiResult.success();
}
实例验证
接口调用
系统操作日志数据
相关文章:

AOP应用之系统操作日志
本文演示下如何使用AOP,去实现系统操作日志功能。 实现步骤 引入AOP包 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>2.6.6</version></de…...

海外云手机自动化管理,高效省力解决方案
不论是企业还是个人,对于海外社媒的营销都是需要自动化管理的,因为自动化管理不仅省时省力,而且还节约成本; 海外云手机的自动化管理意味着什么?那就是企业无需再投入大量的人力和时间去逐一操作和监控每一台设备。 通…...
后仿真中的 《specify/endspecify block》之(5)使用specify进行时序仿真
前面我们学习了specify...endspecify 具体是什么东西。今天,我们使用specify block 中定义的延时,来进行一次仿真。看看到底是背后如何运转的呢。 一 基本例子 一个用 specify 指定延迟的与门逻辑描述如下: module and_gate(output Z,input A, B);assign Z = A & …...

win10/11磁盘管理
win10/11磁盘管理 合并磁盘分区的前提是你的两个磁盘区域是相邻的,比如如下: 如果需要吧这个磁盘进行分解,你可以选择压缩一部分磁盘或者是直接删除卷 我这里的话,因为压缩出来的卷和C盘好像是不相邻的(我之前做过&…...
【昇思初学入门】第四天打卡
数据变换Transforms 心得体会 MindSpore提供了丰富的数据变换工具,针对图像数据可以使用如Rescale、Normalize和HWC2CHW等,且使用Compose类允许我们定义一个变换序列,并将它们作为一个整体应用到数据上。 composed transforms.Compose([v…...

禁用/屏蔽 Chrome 默认快捷键
Chrome 有一些内置的快捷键,但是它并没有像其他软件一样提供管理快捷键的界面。在某些时候,当我们因为个人需求希望禁用 Chrome 某些快捷键时,又无从下手。 好在有开发者开发了 Chrome 插件,可以禁用 Chrome 快捷键的插件&#x…...

移动端+PC端应用模式的智慧城管综合执法办案平台源码,案件在线办理、当事人信用管理、文书电子送达、沿街店铺分析
城市管理综合执法管理平台实现执法办案、业务全流程在线办理,依托移动端PC端的“两端”应用模式,保障能够通过信息化手段进行日常的执法办案工作,强化执法监督功能。提供了案件在线办理、当事人信用管理、文书电子送达、沿街店铺分析等功能&a…...
AI音乐大模型时代:版权归属与创意产业的新生长点
AI在创造还是毁掉音乐? 简介:最近一个月,轮番上线的音乐大模型,一举将素人生产音乐的门槛降到了最低,并掀起了音乐圈会不会被AI彻底颠覆的讨论。短暂的兴奋后,AI产品的版权归属于谁,创意产业要…...
C++函数作为参数
C++函数作为参数 在C++中,函数作为另一个函数的参数是非常常见的做法,特别是在处理回调函数和泛型编程时。我们展示了如何在C++中将函数作为参数传递给另一个函数,包括普通函数、std::function 和 std::bind、lambda表达式以及类成员函数。每种方法都有其独特的优势,可以根…...

考前刷题练手感(北航期末往年数据结构编程题)
本次因为是考前一天极速刷题,所以没有讲解,若有问题可私信。 目录 一、 查找同时空人员二、 老鼠回家-无回路三、函数调⽤关系四、东二食堂模拟五、栈帧 一、 查找同时空人员 【问题描述】 假设一共有6个手机基站,都具有记录手机连接基站状…...

Android记录9--实现转盘效果
自定义View /2013.10.16_TurnPlate_Demo/src/com/wwj/turnplate/TurnPlateView.java package com.wwj.turnplate; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; im…...

【Oracle APEX开发小技巧1】转换类型实现显示小数点前的 0 以 及常见类型转换
在 apex 交互式式网格中,有一数值类型为 NUMBER,保留小数点后两位的项,在 展示时小数点前的 0 不显示。 效果如下: 转换前: m.WEIGHT_COEFFICIENT 解决方案: 将 NUMBER(20,2…...

GRIT论文阅读笔记
一篇试图统一生成任务和编码任务的工作,就是把只能完成生成任务的GPT改成既能生成又能encode。思路其实很简单,就是在输入的时候添加instruction tokens来指引模型做representation还是generation,然后各自算损失。representation任务用的是d…...

1980python个性化电影推荐管理系统mysql数据库Django结构layUI布局elasticsearch存储计算机软件工程网页
一、源码特点 python Django个性化电影推荐管理系统是一套完善的web设计系统mysql数据库 利用elasticsearch存储浏览数据 ,对理解python编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 开发环境pycharm…...

基于IDEA的Maven(依赖介绍和引用)
如何通过一个坐标信息(依赖)去引用 ,某个"jar 包" 会在这篇博客进行学习。 目录 一、学习开始 (0)项目的结构组成和 "pom.xml" 文件内容。 (1)首先需要一个标签…...

pytest测试框架pytest-sugar插件生成进度条
Pytest提供了丰富的插件来扩展其功能,介绍下插件pytest-sugar,可以帮助我们在控制台中显示彩色的测试结果和进度条,提供失败的堆栈回溯信息。 为了使用 pytest-sugar,需要满足以下条件: Python 3.8 或更高版本pytest…...

若依框架集成微信支付
1. 添加微信支付相关依赖 <!-- 微信支付 --> <dependency><groupId>com.github.wxpay</groupId><artifactId>wxpay-sdk</artifactId><version>0.0.3</version> </dependency> <dependency><groupId>com.gi…...

IOS开发学习日记(十七)
简单的第三方登录和分享功能 第三方登录系统 URL Scheme:App间的跳转及通信 App间跳转场景 登陆系统: 跨平台,跨App 标记用户,个性化的推送 使用第三方登录(减少注册成本 / 无须维护敏感信息) 微信 / Q…...
【ARMv8/ARMv9 硬件加速系列 2 -- ARM NEON 加速运算介绍】
文章目录 ARM NEONNEON 向量寄存器NEON 寄存器使用方式NEON 寄存器的视图NEON 寄存器别名NEON 寄存器的用途ARM NEON 在ARMv8架构中,引入了一组新的寄存器,称为向量寄存器(Vector Registers),用于支持高效的向量和浮点计算。这些寄存器是SIMD(Single Instruction, Multi…...

LayoutSystem布局系统
简介: LayoutSystem,是UGUI中由CanvasUpdateSystem发起(m_LayoutRebuildQueue中大部分都是LayoutRebuilder)的关于布局排列的处理系统。 类图: 布局过程 核心代码讲解: LayoutRebuilder...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...