操作日志应记录编辑的前后内容变化

总体思路是增加一个注解类,将注解加到要进行记录变化的Java类属性上却可。

上代码:

1. 实现注解类: 

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {String value();boolean isIgnoreNull() default false;
}

2. 将注解加到Java类属性

@FieldName("产品编码")
private String productNo;

3. 写一个LogUtil类,对新旧对象进行比较,将变化的内容记录下来,返回List<String>,为了防止异常出现影响正常的业务,用try-catch进行异常处理


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;import **.FieldName;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;@Slf4j
public class LogUtil {private static  SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");/*** 记录修改信息* @param newObj 更新后数据* @param oldObj 更新前数据* @param clazz* @return*/public static List<String> getUpdateContentList(Object newObj, Object oldObj, Class clazz) {List<String> contentList = new ArrayList<>();if (newObj == null || oldObj == null) {return contentList;}try {//通过hutool BeanUtil工具将实体类转换为MapMap newMap = BeanUtil.beanToMap(newObj);Map oldMap = BeanUtil.beanToMap(oldObj);//通过类对象获取类字段Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {//判断是否有FieldName注解if (field.isAnnotationPresent(FieldName.class)) {FieldName fieldName = field.getAnnotation(FieldName.class);//空的和忽略的字段不进行处理if (fieldName.isIgnoreNull() &&  ObjectUtil.isEmpty(newMap.get(field.getName()))) {continue;}String newValue =  newMap.get(field.getName()) == null ? "" : newMap.get(field.getName()).toString();String oldValue =  oldMap.get(field.getName()) == null ? "" : oldMap.get(field.getName()).toString();if(field.getType() == Date.class){try{if(StringUtils.isNotEmpty(newValue)){newValue = formatter.format(newMap.get(field.getName()));}if(StringUtils.isNotEmpty(oldValue)){oldValue = formatter.format(oldMap.get(field.getName()));}}catch (Exception e){e.printStackTrace();}}String changeField;Map<String, String> conMap = new HashMap<>();//新旧记录内容不同,说明是修改过,因此记录起来if (!newValue.equals(oldValue)) {//CHANGE_TEXT 自定义拼接内容//CHANGE_TEXT = "fieldName-oldValue --> 调整为 --> fieldName-newValue"String CHANGE_TEXT =  "fieldName:oldValue --> newValue";changeField = CHANGE_TEXT.replaceAll("fieldName", fieldName.value()).replaceAll("oldValue", oldValue).replaceAll("newValue", newValue);log.info(changeField);contentList.add(changeField);}}}}catch (Exception e){e.printStackTrace();}return contentList;}
}

LogUtil用到的依赖是:

<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.12</version>
</dependency>

一切准备就结果,接下来就是具体使用:

在Controller类的edit请求中:

// 某个Controller的edit方法中
List<String> updateContentList = getUpdateContentList(product);
String updateContent = "修改产品";
if(!updateContentList.isEmpty()){updateContent += ": "+updateContentList;
}
// 日志记录的service类新建一条更新日志
updateRecordService.setProductUpdateRecord(product.getId(), "编辑", updateContent);/*** 获取编辑前后的变化内容
*/private List<String> getUpdateContentList(Product product){Product oldObject = productService.getById(product.getId());return LogUtil.getUpdateContentList(product, oldObject, Product .class);
}

最后的效果如图:

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

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

相关文章

day34_js

今日内容 0 复习昨日 1 事件 1.1 事件介绍 1.2 事件绑定方式 1.3 不同事件的演示 2 DOM操作 2.1 概述 2.2 查找元素 2.3 元素内容的查找和设置 2.4 元素属性的查找和设置 2.5 元素CSS样式的查找和设置 2.6 创建元素 2.7 创建文本节点 2.8 追加元素 2.9 删除元素 3 案例练习 0 复…

TCP 异常断开连接【重点】

参考链接 https://xiaolincoding.com/network/3_tcp/tcp_down_and_crash.html https://xiaolincoding.com/network/3_tcp/tcp_unplug_the_network_cable.html#%E6%8B%94%E6%8E%89%E7%BD%91%E7%BA%BF%E5%90%8E-%E6%9C%89%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93 关键词&#xff1a…

无际线复选框

效果演示 实现了一个网格布局&#xff0c;其中每个网格是一个复选框&#xff0c;可以选择是否显示。每个复选框都有一个漂浮的天花板&#xff0c;表示它是一个房间的天花板。每个房间的天花板都有一个不同的形状和颜色&#xff0c;分别对应不同的房间。整个页面的背景是一个由两…

echarts多个折线图共用X轴,实现tooltip合并和分离

echarts共享X轴案例&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><title>Document</…

一、提升专注力的完整指南(The Complete Guide to Increasing Your Focus)- Scott Young

Focus is one of your most valuable resource.It acts as a multiplier on the value of your time.An hour of absorbing focus can be worth ten times that of a distracted one. 专注力是你的最宝贵的资源之一。它就像一个乘数因子&#xff0c;让时间的价值翻倍。全神贯注…

<el-date-picker>时间戳单位

神级操作&#xff0c;搞了半天&#xff0c;秒是大X&#xff0c;毫秒是小x&#xff0c;yue了。 // 秒 <el-date-pickerv-model"timestamp"value-format"X" ></el-date-picker>// 毫秒 <el-date-pickerv-model"timestamp"value-fo…

DevSecOps核心流程基本组成分析

目录 一、DevSecOps核心流程基本组成 1.1 核心流程概述 1.2 DevSecOps 核心流程说明 1.2.1 核心流程图 1.2.2 流程说明 1.2.2.1 持续开发 1.2.2.2 持续构建 1.2.2.3 持续运维 1.2.2.4 持续监控 二、DevSecOps核心流程经典场景 2.1 Azure DevSecOps核心流程 2.1.1 核…

OpenCV 3 - Mat对象介绍

1 Mat对象与IplImage对象 Mat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分,头部与数据部分lpllmage是从2001年OpenCv发布之后就一直存在,是c语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序…

HCIA-HarmonyOS设备开发认证-3.内核基础

目录 前言目标一、进程与线程待续。。。 前言 对于任何一个操作系统而言&#xff0c;内核的运行机制与原理是最为关键的部分。本章内容从多角度了解HarmonyOS的内核运行机制&#xff0c;涵盖进程与线程的概念&#xff0c;内存管理机制&#xff0c;网络特性&#xff0c;文件系统…

HTTP连接池在Java中的应用:轻松应对网络拥堵

网络拥堵是现代生活中无法避免的问题&#xff0c;尤其是在我们这个“点点点”时代&#xff0c;网页加载速度直接影响到我们的心情。此时&#xff0c;我们需要一位“救世主”——HTTP连接池。今天&#xff0c;就让我们一起探讨一下&#xff0c;这位“救世主”如何在Java中大显神…

C 练习实例46-宏#define命令练习

宏定义的三种用法&#xff1a; 给变量赋初值替换某一个操作符宏定义函数 代码&#xff1a; #include <stdio.h> #define PI 3.1415926 //给变量赋初值 #define CH * //替换某一个操作符 #define area(a,b) a*b*b //函数 int main() {printf("PI%f\n",PI);…

力扣151 反转字符串中的单词 Java版本

目录 题目描述代码补充知识 题目描述 给你一个字符串 s &#xff0c;请你反转字符串中 单词 的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意&#xff1a;输…

redis持久化知识汇总

redis持久化知识汇总 主要分两个持久化方式RDB和AOF RDB RDB是以快照的形式将数据写入二进制文件&#xff0c;可以通过save和bgsave触发&#xff0c;也可以自动化 Save方式是直接在主进程进行持久化操作&#xff0c;缺点就是会导致阻塞服务器。 Bgsave方式会先创建子进程&…

Blender教程(基础)-初识快捷键-02

Blender是一款开源的跨平台全能三维动画制作软件&#xff0c;提供从建模、动画、材质、渲染到音频处理、视频剪辑等一系列动画短片制作解决方案。Blender拥有方便在不同工作下使用的多种用户界面。以下是一些常用的Blender快捷键&#xff1a; 全选物体&#xff1a;A 框选物体&…

Linux下安装openresty

Linux下安装openresty 十一、Linux下安装openresty11.1.概述11.2.下载OpenResty并安装相关依赖&#xff1a;11.3.使用wget下载:11.4.解压缩:11.5.进入OpenResty目录:11.6.编译和安装11.7.进入OpenResty的目录&#xff0c;找到nginx&#xff1a;11.8.在conf目录下的nginx.conf添…

2870.使数组为空的最少操作次数

给你一个下标从 0 开始的正整数数组 nums 。 你可以对数组执行以下两种操作 任意次 &#xff1a; 从数组中选择 两个 值 相等 的元素&#xff0c;并将它们从数组中 删除 。从数组中选择 三个 值 相等 的元素&#xff0c;并将它们从数组中 删除 。 请你返回使数组为空的 最少…

C# 获取计算机信息

目录 一、本机信息 1、本机名 2、获得本机MAC地址 3、获得计算机名 4、显示器分辨率 5、主显示器分辨率 6、系统路径 二、操作系统信息 1、操作系统类型 2、获得操作系统位数 3、获得操作系统版本 三、处理器信息 1 、处理器个数 四、CPU信息 1、CPU的个数 2、…

【分布式技术专题】「探索高性能远程通信」基于Netty的分布式通信框架实现(附通信协议和代码)(上)

基于Netty的分布式通信框架实现 前提介绍回顾Dubbo分布式通信框架组成元素程序执行流程消息协议设计实现机制ChannelInboundHandlerAdapter自定义事件处理 ChannelOutboundHandlerAdapter 编(解)码处理器编码过程阶段ChannelOutboundHandlerAdapter序列化实现ChannelOutboundHa…

wireshark利用sshdump自身组件进行远程实时抓包过滤

引言 以前在不了解wireshark可以远程抓包的时间&#xff0c;经常通过tcpdump在远程linux主机将抓包文件保存下来后&#xff0c;然后拖拽入windows中再打开&#xff0c;进行分析查看。 此过程比较繁琐&#xff0c;也不够实时。比较常用的抓包动作是仅出现某特征的报文后&#…

秀!巧用字典推导式将列表中的元素“值”转换字典格式

示例&#xff1a; contact_list [{display_name: 10手机, data1: 1-000-10}, {display_name: 11手机, data1: 1-000-11}, ] 把上面的列表转成下面的字典 contact_dir {10手机: 1-000-10, 11手机: 1-000-11} 巧用字典推导式将列表中的元素转换为所需的字典格式&#xff0c;下…