jpa 修改信息拦截

发布时间:2023年12月18日

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

    // 线程变量,保存修改前的 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) {
        // 在新实体持久化之前(即在数据库插入之前)调用
        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 {
            // 根据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());
        }
    }


    @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;
    }

}
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)
//    @Transient
    private String haha;

}

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

在这里插入图片描述

user_abc表

在这里插入图片描述

最终效果

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

文章来源:https://blog.csdn.net/weixin_43275578/article/details/135013654
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。