实现目标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表
最终效果