jpa 修改信息拦截

实现目标springboot+JPA

哪个人,修改了哪个表的哪个字段,从什么值修改成什么值

import jakarta.persistence.*;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;@Component // 必须加
@Slf4j
@Configurable(autowire = Autowire.BY_TYPE)
public class AuditingEntityListener  {// 线程变量,保存修改前的 objectprivate ThreadLocal<Object> updateBeforeObject = new ThreadLocal<>();// 线程池static ThreadPoolExecutor executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors()+1, 30, 10,TimeUnit.SECONDS, new LinkedBlockingQueue(20),new ThreadPoolExecutor.CallerRunsPolicy());// EntityManager 操作数据库private static EntityManager entityManager;// requestprivate static HttpServletRequest request;@Autowiredpublic synchronized void setInfo(EntityManager entityManager,HttpServletRequest request) {AuditingEntityListener.entityManager = entityManager;AuditingEntityListener.request = request;}@PrePersistpublic void onCreateBefore(Object object) {// 在新实体持久化之前(即在数据库插入之前)调用System.out.println("在新实体持久化之前"+object);}@PostPersistpublic void onCreateAfter(Object object) {try {// object// 异步线程保存信息 入库executor.execute(()->{  });}catch (Exception e){}}@PreUpdatepublic void onUpdateBefore(Object object){System.out.println("在实体更新之前调用");// 用户名String userName = StringUtils.isBlank(request.getHeader("userName"))? "未知用户":request.getHeader("userName");System.out.println("修改人: " + userName);try {// 根据object对象获取主键名称,并根据主键获取对应的值Long id = SwaggerUtils.getIdFieldName(object);if(ObjectUtils.isEmpty(id)){return;}// 在新实体持久化之前(即在新数据插入之前)调用。// 根据ID获取该实体类库中的数据Future<Object> submit =  executor.submit(() -> entityManager.find(object.getClass(), id));// 阻塞主线程 [1s 超时],等待异步线程返回数据,将内容加入到线程变量if(!ObjectUtils.isEmpty(submit.get(1,TimeUnit.SECONDS))){updateBeforeObject.set(submit.get());}}catch (Exception e){log.error("异步信息获取失败={},",e.toString());}}@PostUpdatepublic void onUpdateAfter(Object object) {try {// 在实体更新之后调用。System.out.println("在实体更新之后调用");// 获取字段名,字段值,字段类型// getFields(object);// 获取修改后的字段区别//   有 swagger依赖,且 对应的实体有 @ApiModelProperty,则取 注释名,否则取真实字段名, 例//   @ApiModelProperty(value = "姓名")//    private String name;////    @Column(length = 200)//    private String addr;////    改动字段 [姓名]: [ 阿达 ] -> [ 77 ]//    改动字段 [addr]: [ 阿达 ] -> [ 77 ]if(!ObjectUtils.isEmpty(updateBeforeObject.get())){List<String> objectDifferetList = objectDifferet(updateBeforeObject.get(),object);objectDifferetList.forEach(e->{System.err.println(e);});// 移除此次操作updateBeforeObject.remove();// 异步线程保存 改动信息 入库executor.execute(()->{  });}}catch (Exception e){log.error("异步信息保存失败");}}@PreRemovepublic void onRemoveBefore(Object object) {// 在删除实体之前调用。System.out.println("在删除实体之前调用"+object);}@PostRemovepublic void onRemoveAfter(Object object) {// 在删除实体之后调用System.out.println("在删除实体之后调用"+object);}// 获取实体 字段 和 值public static void getFields(Object object){Class<?> clazz = object.getClass();Field[] fields = clazz.getDeclaredFields();StringBuilder stringBuilder = new StringBuilder();// 遍历所有字段for (Field field : fields) {// 确保私有字段也可以被访问field.setAccessible(true);try {// 获取字段的名称String fieldName = field.getName();// 获取字段的值Object fieldValue = field.get(object);// 获取字段的类型Class<?> fieldType = field.getType();// 打印字段的名称和类型System.out.println("字段名: " + fieldName + ", 字段值:"+ fieldValue + ", 字段类型: " + fieldType.getName());}catch (Exception e){System.out.println("field:获取失败={}"+field);}}}// 获取两个实体类字段之间的区别public static List<String> objectDifferet(Object obj1, Object obj2) {System.err.println("原始object:" + obj1);System.err.println("==================");System.err.println("新的object:" + obj2);List<String> differences = new ArrayList<>();if (obj1 == null || obj2 == null) {throw new IllegalArgumentException("Both objects must be non-null");}if (!obj1.getClass().equals(obj2.getClass())) {throw new IllegalArgumentException("Objects must be of the same type");}Class<?> clazz = obj1.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true); // Ensure private fields are accessibletry {Object value1 = field.get(obj1);Object value2 = field.get(obj2);if ((value1 != null && !value1.equals(value2)) || (value1 == null && value2 != null)) {String key = ObjectUtils.isEmpty( SwaggerUtils.getApiModelProperty(clazz,field.getName()) ) ? field.getName() : SwaggerUtils.getApiModelProperty(clazz,field.getName()).value() ;String table = ObjectUtils.isEmpty( SwaggerUtils.getTable(clazz) ) ? clazz.getName()+"实体" : SwaggerUtils.getTable(clazz).name() ;differences.add(String.format("表名 %s 字段  %s("+field.getName()+")  :  由 [ %s ] 改为 [ %s ]",table, key , value1, value2));}} catch (IllegalAccessException e) {e.printStackTrace(); // Handle exception as appropriate for your use case}}return differences;}}
import io.swagger.annotations.ApiModelProperty;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.lang.reflect.Field;public class SwaggerUtils {// 获取 标注了ApiModelProperty 对应的注释public static ApiModelProperty getApiModelProperty(Class<?> clazz, String fieldName) {try {Field field = clazz.getDeclaredField(fieldName);return field.getAnnotation(ApiModelProperty.class);} catch (NoSuchFieldException e) {e.printStackTrace();}return null;}// 获取标注了@Table 的表名public static Table getTable(Class<?> clazz) {try {return clazz.getAnnotation(Table.class);} catch (Exception e) {e.printStackTrace();}return null;}/*** 根据 传来的实体 获取主键id 对应的值!*/public static Long getIdFieldName(Object obj)  {try {Class<?> clazz = obj.getClass();Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(Id.class)) {field.setAccessible(true);Object idValue = field.get(obj);Long id = (Long) idValue;return id;}}} catch (Exception e) {e.printStackTrace();}return null;}}
实体@Entity//实体
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "user_abc")
@EntityListeners({AuditingEntityListener.class})
public class User  implements Serializable {@Id //主键@GeneratedValue(strategy = GenerationType.IDENTITY) //主键id生成策略,IDENTITY:自增private Long id;@Column(nullable = false,length = 200)// 非空 唯一 200长度@ApiModelProperty(value = "姓名")private String name;@Column(length = 200)private String addr;@Column(length = 200)private String phone;@Column(length = 200)
//    @Transientprivate String haha;}

修改接口
在这里插入图片描述

在这里插入图片描述

user_abc表

在这里插入图片描述

最终效果

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

死锁(JAVA)

死锁在多线程代码中是非常严重的BUG&#xff0c;一旦代码中出现死锁就会导致线程卡死。 当单个线程连续两次对同一个对象进行加锁操作时&#xff0c;如果该锁是不可重入锁就会发生死锁&#xff08;线程卡死&#xff09; 两个线程两把锁&#xff0c;如果出现这种情况也是会发生…

逻辑回归代价函数

逻辑回归的代价函数通常使用交叉熵损失来定义。这种损失函数非常适合于二元分类问题。 本篇来推导一下逻辑回归的代价函数。 首先&#xff0c;我们在之前了解了逻辑回归的定义&#xff1a;逻辑回归模型是一种用于二元分类的模型&#xff0c;其预测值是一个介于0和1之间的概率…

【产品设计】零代码核心模块之一:表单

在数字化越来越高级、越来越智能的场景下&#xff0c;信息收集依旧是适用场景最为丰富的方式之一。 应用开发工作台开三大核心模块&#xff1a;表单、流程、报表。 表单&#xff1a;一般适合数据录入&#xff0c;专人管理&#xff0c;如&#xff1a;用户调研、产品入库&#x…

项目篇 | 图书管理系统 | 图像加载与绘制

项目篇 | 图书管理系统 | 图像加载与绘制 基本介绍 首先解释清楚什么叫图像加载与绘制,意思就是说项目中需要用到一些图片资源(各种图标),我们要在图书管理系统中展示这些图片,就需要先导入图片到项目中,再加载图片资源(通过资源路径)、绘制图片(即展示)。 注:如果…

商业印刷市场分析:预计2029年将达到53004亿元

商业印刷技术显示了强大的生命力。电子商务的扩张性发展&#xff0c;传统的商务印刷行业也在逐渐的转型。中国印刷业已深度融入全球印刷加工产业链&#xff0c;为国际社会超过50个国家提供印刷包装服务。数据显示&#xff0c;中国印刷业对外加工贸易额已达842亿元。 商业印刷是…

【无标题】C++ STL -->模拟实现vector

这篇文章将模拟实现vector类的常用函数 vector类的函数接口 namespace ding {template<class T>class vectot{public:typedef T* iterator;typedef const T* const_iterator;//Member functionsvector(); vector(size_t n, const…

JVM的内存分区以及垃圾收集

1.JVM的内存分区 1.1方法区 方法区(永久代&#xff09;主要用来存储已在虚拟机加载的类的信息、常量、静态变量以及即时编译器编译后的代码信息。该区域是被线程共享的。 1.2虚拟机栈 虚拟机栈也就是我们平时说的栈内存&#xff0c;它是为java方法服务的。每个方法在执行的…

最大公因数,最小公倍数详解

前言 对于初学编程的小伙伴们肯定经常遇见此类问题&#xff0c;而且为之头疼&#xff0c;今天我来给大家分享一下&#xff0c;最大公因数和最小公倍数的求法。让我们开始吧&#xff01; 文章目录 1&#xff0c;最大公因数法1法2法3 2&#xff0c;最小公倍数3&#xff0c;尾声 …

[C++] 虚函数、纯虚函数和虚析构(virtual)

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/weixin_43197380&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 Loewen丶原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&…

cmake 最基础示例

C 代码 文件名&#xff1a;first_cmake.cpp #include <iostream> using namespace std;int main() {cout<< "A" << endl;return 0; }CMakeLists.txt 文件 #CMakeLists.txt # 设置:版本 cmake_minimum_required(VERSION 3.20)# 定义 :项目名称 …

宏基因组学及宏转录组学分析工具MOCAT2(Meta‘omic Analysis Toolkit 2)安装配置及常用使用方法

详细介绍 尽管这个工具已经暂停后续开发&#xff0c;但其工具功能还是挺好的&#xff0c;大家可以参考一下&#xff0c;尤其对于喜欢自定义开发流程的可以参考是流程。 MOCAT 2&#xff08;Metaomic Analysis Toolkit 2&#xff09;是一个用于宏基因组和宏转录组数据分析的工具…

Java实现快速排序算法

快速排序算法 &#xff08;1&#xff09;概念&#xff1a;快速排序是指通过一趟排序将要排序的数据分割成独立的两部分&#xff0c;其中一部分的所有数据都比另外一部分的所有数据都要小&#xff0c;然后再按此方法对这两部分数据分别进行快速排序。整个排序过程可以递归进行&…

TSINGSEE青犀城市道路积水AI检测算法视频智能监管解决方案

近年来&#xff0c;由于城市区域内涝频发&#xff0c;遇到强降水天气出现路面严重积水的情况时有发生&#xff0c;影响交通通行甚至引发事故。所以&#xff0c;对下穿隧道、下沉式道路等路面积水情况的监测显得尤为重要。传统的监管方式很难及时发现道路积水情况&#xff0c;那…

物易管预测性维护平台3.6.0版本上线,工况数据处理、设备故障模型、数据可视化等方面带来全新功能体验

物易管设备预测性维护平台V3.6.0版本近日正式发布上线&#xff0c;相较V3.5.0版本次主要新增优化设备工况数据接入、工况数据模型训练、数据可视化以及设备监测详情优化四个板块。新版本在处理工况数据、设备故障模型、数据分析展示以及设备监测方面带来全新的体验。 01设备工况…

Jtti:ssl协议未开启怎么解决?

如果你的服务器上的SSL协议未开启&#xff0c;可以按照以下步骤检查和解决问题。SSL协议通常由Web服务器配置和启用。以下是基于常见的Web服务器的步骤&#xff1a; Apache Web 服务器&#xff1a; 1.检查 Apache 是否加载了 SSL 模块&#xff1a; 在终端中运行以下命令&#x…

基于SSM的高校疫情管理系统设计与实现论文

摘 要 当下疫情不容松懈&#xff0c;此次新冠肺炎疫情是传播速度最快、感染范围最广、防控难度最大的一次重大突发公共卫生事件&#xff0c;疫情防控尤为重要&#xff0c;传统的基于纸质文本的疫情信息管理模式&#xff0c;效率低&#xff0c;无法满足管理需求&#xff0c;所以…

若依源码分析

一.登录 1.1 生成验证码 基本思路 后端生成一个表达式,74?11 74?转成图片,传到前端进行展示 将结果11存入redis 前端代码实现: 请求后端地址:http://localhost/dev-api/captchaImage,通过反向代理解决前后端跨域问题,将请求路径变为:http://localhost:8080/captchaImag…

ESXI 6.7升级update3

一、适用场景 1、企业已有专业服务器&#xff0c;通过虚拟化环境搭建了vm server&#xff1b; 2、备份整个vm server时&#xff0c;需要使用ovftool工具完成&#xff0c;直接导出ovf模板时报错&#xff1b; 3、升级EXSI6.7的build 8169922版本为update 3版本后&#xff0c;已保…

The method show() from the type Window is deprecated

java.awt.Window.show() java.awt.Component.setVisible(true); Window.show() java.awt.JFrame java.awt.Frame java.awt.Windows java.awt.Component.setVisible(true);

论文查重过多怎么降重 神码ai

大家好&#xff0c;今天来聊聊论文查重过多怎么降重&#xff0c;希望能给大家提供一点参考。 以下是针对论文重复率高的情况&#xff0c;提供一些修改建议和技巧&#xff0c;可以借助此类工具&#xff1a; 论文查重过多怎么降重 当论文查重率过高时&#xff0c;需要进行降重处…