jpa 修改信息拦截

实现目标springboot+JPA

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

@Component // 必须加
@Slf4j
@Configurable(autowire = Autowire.BY_TYPE)
public class AuditingEntityListener  {

    // 线程变量,保存修改前的 object
    private 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;

    // request
    private static HttpServletRequest request;


    @Autowired
    public synchronized void setInfo(EntityManager entityManager,HttpServletRequest request) {
        AuditingEntityListener.entityManager = entityManager;
        AuditingEntityListener.request = request;
    }

    @PrePersist
    public void onCreateBefore(Object object) {
        if(object instanceof User){
            // 在新实体持久化之前(即在数据库插入之前)调用
            System.out.println("在新实体持久化之前"+object);
        }

    }
    @PostPersist
    public void onCreateAfter(Object object) {
        try {
            // object
            // 异步线程保存信息 入库
            executor.execute(()->{  });
        }catch (Exception e){

        }

    }

    @PreUpdate
    public void onUpdateBefore(Object object){
        System.out.println("在实体更新之前调用");
        // 用户名
        String userName = StringUtils.isBlank(request.getHeader("userName"))? request.getHeader("userName") : "未知用户";
        System.out.println("修改人: " + userName);
        try {
             if(object instanceof User){
                User obj = ((User) object);
                // 在新实体持久化之前(即在新数据插入之前)调用。
                // 根据ID获取该实体类库中的数据
                Future<Object> submit =  executor.submit(() -> entityManager.find(obj.getClass(), obj.getId()));
                // 阻塞主线程,等待异步线程返回数据,将内容加入到线程变量
                 if(!ObjectUtils.isEmpty(submit.get())){
                     updateBeforeObject.set(submit.get());
                 }
             }
        }catch (Exception e){
            log.error("异步信息获取失败");
        }
    }

    @PostUpdate
    public 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("异步信息保存失败");
        }

    }

    @PreRemove
    public void onRemoveBefore(Object object) {
        // 在删除实体之前调用。
        System.out.println("在删除实体之前调用"+object);
    }

    @PostRemove
    public 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 accessible
            try {
                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;
    }

}
public class SwaggerUtils {
    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;
    }

    public static Table getTable(Class<?> clazz) {
        try {
            return clazz.getAnnotation(Table.class);
        } 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)
//    @Transient
    private String haha;

}

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

在这里插入图片描述

user_abc表

在这里插入图片描述

最终效果

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot运维中的高级配置

&#x1f648;作者简介&#xff1a;练习时长两年半的Java up主 &#x1f649;个人主页&#xff1a;程序员老茶 &#x1f64a; ps:点赞&#x1f44d;是免费的&#xff0c;却可以让写博客的作者开心好久好久&#x1f60e; &#x1f4da;系列专栏&#xff1a;Java全栈&#xff0c;…

Navicat16 无限试用 亲测有效

Navicat16 无限试用 亲测有效 亲测有效&#xff01;&#xff01;&#xff01; 吐槽下&#xff0c;有的用不了&#xff0c;有的是图片&#xff0c;更甚者还有收费的&#xff0c;6的一批 粘贴下面的代码&#xff0c;保存到桌面&#xff0c;命名为 trial-navicat16.bat echo off…

Web安全-SQL注入常用函数(二)

★★实战前置声明★★ 文章中涉及的程序(方法)可能带有攻击性&#xff0c;仅供安全研究与学习之用&#xff0c;读者将其信息做其他用途&#xff0c;由用户承担全部法律及连带责任&#xff0c;文章作者不承担任何法律及连带责任。 1、MySQL数据库构成 初始化安装MySQL数据库后(…

从零开始搭建企业管理系统(七):RBAC 之用户管理

RBAC 之用户管理 创建表&#xff08;Entity&#xff09;用户表角色表权限表用户角色表关系注解ManyToMany 角色权限表 接口开发UserControllerUserServiceUserServiceImplUserRepository 问题解决update 更新问题懒加载问题JSON 循环依赖问题 根据上一小结对表的设计&#xff0…

基于ssm高校食堂订餐系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本高校食堂订餐系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

服务器数据恢复-EqualLogic PS存储硬盘坏道导致存储不可用的数据恢复案例

服务器数据恢复环境&#xff1a; 一台DELL EqualLogic PS系列存储&#xff0c;存储中有一组由16块SAS硬盘组成的RAID5。上层是VMFS文件系统&#xff0c;存放虚拟机文件。存储上层分了4个卷。 服务器故障&检测&#xff1a; 存储上有2个硬盘指示灯显示黄色&#xff0c;磁盘出…

51单片机的外部中断的以及相关寄存器的讲解

中断系统 本文主要涉及8051单片机的中断系统的讲解与使用 其中包括中断相关寄存器的介绍与使用以及外部中断初始化的代码分析。 文章目录 中断系统一、 中断的介绍二、 中断结构及相关寄存器2.1 中断源 2.2 中断请求控制器2.2.1 TCON寄存器2.2.2 SCON寄存器2.2.3 中断允许寄存器…

Spark与PySpark(1.概述、框架、模块)

目录 1.Spark 概念 2. Hadoop和Spark的对比 3. Spark特点 3.1 运行速度快 3.2 简单易用 3.3 通用性强 3.4 可以允许运行在很多地方 4. Spark框架模块 4.1 Spark Core 4.2 SparkSQL 4.3 SparkStreaming 4.4 MLlib 4.5 GraphX 5. Spark的运行模式 5.1 本地模式(单机) Local运行模…

智能优化算法应用:基于模拟退火算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于模拟退火算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于模拟退火算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.模拟退火算法4.实验参数设定5.算法结果6.…

2036开关门,1109开关门

一&#xff1a;2036开关门 1.1题目 1.2思路 1.每次都是房间号是服务员的倍数的时候做处理&#xff0c;所以外层&#xff08;i&#xff09;枚举服务员1~n&#xff0c;内层&#xff08;j&#xff09;枚举房间号1~n&#xff0c;当j % i0时&#xff0c;做处理 2.这个处理指的是&…

module ‘tensorflow‘ has no attribute XXX 报错解决

问题描述&#xff1a; 粘了别人的tensorflow项目&#xff0c;运行总是报错module ‘tensorflow’ has no attribute什么什么 问题解决&#xff1a; 导入tensorflow的代码如下 import tensorflow as tf此时&#xff0c;某个某块报错&#xff0c;比如下面这个 那么就直接把tf.…

【【ZYNQ 7020显示 图片 实验 】】

ZYNQ 7020显示 图片 实验 关键配置 BRAM 因为本次 我想显示的 图片是 400*400 所以在 内部 的 ROM 存储单元选择 了160000 ZYNQ7020的内部资源 最多是 大概 200000左右的 大小 大家可以根据 资源选择合适的像素 此处存放 内部的 图片转文字的COE文件 PLL设置 我选用的是按…

言简意赅的 el-table 跨页多选

步骤一 在<el-table>中:row-key"getRowKeys"和selection-change"handleSelectionChange" 在<el-table-column>中type"selection"那列&#xff0c;添加:reserve-selection"true" <el-table:data"tableData"r…

第二证券:京沪楼市松绑,地产板块强势拉升,京能置业等涨停

地产板块15日盘中强势拉升&#xff0c;到发稿&#xff0c;上实开展、京能置业、大龙地产、新黄浦等涨停&#xff0c;京投开展涨逾6%&#xff0c;保利开展、招商蛇口等涨超3%。 消息面上&#xff0c;12月14日&#xff0c;北京发布调整优化一般住所标准和个人住所告贷政策的告诉…

MIT_线性代数笔记:第 17 讲 正交矩阵和施密特正交化

目录 正交向量 Orthonormal vectors标准正交矩阵 Orthonormal matrix标准正交列向量的优势 Orthonormal columns are good施密特正交化 Gram-Schmidt 本讲我们完成对“正交”的介绍。Gram-Schmidt 过程可以将原空间的一组基转变为标准正交基。 正交向量 Orthonormal vectors 满…

PyQt6 一个简单的例子

PyQt6简单例子 需求代码目录代码实现代码运行效果 需求 1、通过PyQt6实现一个小的应用程序&#xff0c;并设置应用程序的图标&#xff0c;应用程序的标题&#xff0c;然后再提示一个气泡框&#xff0c;不过显示一会就会消失不见。 代码目录 在PyQt文件夹下新建一个包&#x…

五、Shell 注释

一、单行注释 以井号&#xff08;#&#xff09;来注释单行&#xff0c;Shell 并不会处理 Shell 脚本中的注释行。然而 Shell 脚本第一行是个例外&#xff0c;# 号后面的感叹号&#xff08;!&#xff09;是用来告诉系统用哪个解释器来运行脚本。示例和运行结果如图所示&#xf…

基于Java SSM框架实现在线课程教育资源考试管理系统项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架实现在线课程教育资源考试管理系统演示 摘要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线教育资源管理系统&#xff0c;主要的模块包括管理员&#xff1b;个人中心、学生…

GoLang EASY 微服务游戏框架 01

1 Overview EASY 是一个go语言编写的框架&#xff0c;兼容性支持go版本1.19&#xff0c;go mod 方式构建管理。它是一个轻型&#xff0c;灵活&#xff0c;自定义适配强的微服务框架。 它支持多种网络协议TCP&#xff0c;websocket&#xff0c;UDP&#xff08;待完成&#xf…

java-sec-code的xss

java-sec-code 用于学习java漏洞代码 环境部署 直接在idea中使用git 运行即可 RequestMapping("/reflect") ResponseBody public static String reflect(String xss) {return xss;}当用户访问到/reflect URL地址时&#xff0c;程序会自动调用reflect方法&#xff0c…