jpa 修改信息拦截

news2024/12/26 11:36:01

实现目标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表

在这里插入图片描述

最终效果

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

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

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

相关文章

PyVMomi 克隆虚拟机时将磁盘改为Thin模式

需求介绍&#xff1a; 之前已经使用pyvmomi库实现了虚拟机的自动备份&#xff0c;不过由于备份的虚拟机都是较为重要的系统&#xff0c;磁盘都是厚置备模式&#xff0c;终于有一天&#xff0c;备份目标的空间不够了&#xff0c;导致几个虚拟机无法备份。在不想增加磁盘的情况下…

Linux16 ftp文件服务区、vsftpd文件系统服务安装、lftp客户端安装、NFS远程共享存储

目录 一、FTP基础ftp主动模式ftp被动模式 二、vsftpd配置共享目录编辑配置文件使用windows 访问 三、客户端安装 &#xff08;lftp&#xff09;匿名用户的一些操作&#xff08;lftp {ip}&#xff09;ftp配置本地用户登录配置本地用户ftp配置文件 lftp操作 NFS远程共享存储安装n…

Leetcode—380.O(1) 时间插入、删除和获取随机元素【中等】

2023每日刷题&#xff08;五十七&#xff09; Leetcode—380.O(1) 时间插入、删除和获取随机元素 算法思想 实现代码 class RandomizedSet { public:vector<int> nums;unordered_map<int, int> dict;RandomizedSet() {srand((unsigned)time(NULL));}bool insert(…

如何为您的项目选择最优化的 RTLS系统方案

到 2030 年&#xff0c;实时定位市场预计将是当今市场规模的 10 倍&#xff1b;各种全球宏观经济趋势加剧了 RTLS 的指数增长&#xff0c;其中包括&#xff1a; 企业投资回报率的压力增加&#xff0c;从而扩大了对数字化、简化数据和分析的需求&#xff0c;尤其是在 COVID-19 之…

PS扣印章

1 印章区域图片 2 3 吸取印章上的颜色&#xff0c;调节容差&#xff0c;尽量小一点&#xff0c;过大会将背景也进来 4 CtrlJ 把选区复制出来&#xff0c;这个印章图层比较淡&#xff0c;可以通过多复制几个叠加或通过叠加模式来调节。 5 对几个图层选中后CtrlE合并图层 6 选…

Linux查询指定时间点段日志Linux查询指定文件

Linux服务器高效查询日志查询文件 Ⅰ、常用几种日志查询语法Ⅱ、常用几种查询语法 Ⅰ、常用几种日志查询语法 #查询某日志前xx行日志 head -n 行数 日志文件名 #查询某日志后xx行日志 tail -n 行数 日志文件名 #查询固定时间点日志&#xff08;前提是这个时间点确实有日志输出…

观测云产品更新 | 智能监控、数据访问、指标分析等优化

观测云更新 监控 > 智能监控 1、新增「智能监控」&#xff0c;您只需要在检测规则中设置好检测范围和通知对象即可快速开启监控。支持「主机监控」、「日志监控」、「应用监控」&#xff0c;每个监控包含的检测项如下&#xff1a; 智能监控器检测项主机监控CPU的突增/突降…

PyQt6 一个简单的例子

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

绿萝送温暖,扫雪助出行

今冬的大雪如约而至&#xff0c;给居民的出行带来诸多不便&#xff0c;为保障居民安全出行&#xff0c;绿萝志愿服务队第一时间召集志愿者参与扫雪铲冰工作。2023年12月13日&#xff0c;志愿者在房山城关街道青年北路园林所门口、星城生活区等地进行了志愿扫雪活动。 大雪把街道…

三星挑战台积电霸主地位,2nm订单争夺战硝烟四起

根据Trendforce报道&#xff0c;台积电依然在代工行业拥有绝对的领导地位。台积电和三星都计划在2025年开始生产2nm工艺&#xff0c;引发了相关订单的早期争夺战。 扩展阅读&#xff1a;华山论剑&#xff1a;2nm芯片工艺谁更强&#xff1f; 据英国《金融时报》报道&#xff0c…

【1】自动化测试环境配置(ARM服务器)

想要从事 or 了解自动化测试开发、装备开发的小伙伴&#xff0c;本专栏内容将从0到1学习如何针对ARM服务器产品进行自动化测试平台的搭建&#xff0c;包括&#xff1a;测试界面的实现&#xff08;GUI&#xff09;、测试项的功能实现&#xff08;压力测试、接口测试、版本更新&a…

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.这个处理指的是&…

Web开发:ibatis的使用笔记

一、简介 ibatis是一个基于SQL映射支持Java和.NET的持久层框架&#xff1a; 1.如下所示id是对应程序的statement&#xff0c;resultClass需要填写SQL查询到的字段对应的类的命名空间类名&#xff08;DAO.QueryForList<实体类>&#xff09;&#xff0c;以此完成持久层和…

第十五章 React使用UI(Ant Design)框架

一、专栏介绍 &#x1f606;&#x1f606; 欢迎加入本专栏&#xff01;本专栏将引领您快速上手React&#xff0c;让我们一起放弃放弃的念头&#xff0c;开始学习之旅吧&#xff01;我们将从搭建React项目开始&#xff0c;逐步深入讲解最核心的hooks&#xff0c;以及React路由、…

亚马逊云科技助力泡泡玛特快速部署全球弹性资源,打造国潮出海文化

企业全球化的终极目标就是品牌出海。1978年伴随着改革开放&#xff0c;中国企业开始放眼望世界输出中国产品&#xff0c;经过多年锤炼后&#xff0c;中国企业如TCL、泡泡玛特在不同的行业重塑版图&#xff0c;对外输出中国品牌&#xff0c;赢得了全球市场&#xff0c;中国企业实…

2023最快申请一张虚拟信用卡方式

虚拟信用卡就是不记名的信用卡&#xff0c;该卡种是预付性质&#xff0c;必须要先充值后消费&#xff0c;不支持转账。 虚拟卡&#xff08;Virtual Card&#xff09;是一种在线支付方式&#xff0c;它不需要实体卡片&#xff0c;而是由虚拟卡号和CVV码组成&#xff0c;可以用于…

图论专栏一《图的基础知识》

图论&#xff08;Graph Theory&#xff09;是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形&#xff0c;这种图形通常用来描述某些实体之间的某种特定关系&#xff0c;用点代表实体&#xff0c;用连接两点的线表示两个实体间具有的…

vscode报错:建立连接:XHR failed

文章目录 问题解决方案 问题 Windows端ssh远程连接Linux端&#xff0c;Windows端vscode报错&#xff1a;“…XHR failed.” 解决方案 参考&#xff1a;解决 Windows 端 VS Code “无法与 “…“ 建立连接&#xff1a;XHR failed.” 问题 亲测有效。 总结&#xff1a; linux…

2023PCTF Double_SS

记录一下 ssrf配合 ssti的结合 首先开启环境 明显的ssrf 让我们访问 5555端口 使用http协议访问 url127.0.0.1:5555 告诉我们去访问 name 并且给我们key url127.0.0.1:5555/name 出现报错 说我们不是admin 然后我们往下看 我们使用file协议读取app/app.py urlfile:///app…

Linux出击之网络环境设置

Linux中如果想要设置静态IP&#xff0c;这就需要我们进行自己去设置。 首先想知道是否有网络&#xff0c;我们就可以查看我们的网卡信息呀&#xff0c;ping 外网地址试试。 比如&#xff0c; ping www.baidu.com ip addr show, 这两个命令都可以让我们对网络有一个了解。 …