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

总体思路是增加一个注解类,将注解加到要进行记录变化的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工具将实体类转换为Map
            Map 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);
}

最后的效果如图:

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

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

相关文章

六、VTK创建平面vtkPlaneSource

vtkPlaneSource创建位于平面中的四边形数组 先看看效果图: vtkPlaneSource 创建一个 m x n 个四边形数组,这些四边形在平面中排列为规则平铺。通过指定一个原点来定义平面,然后指定另外两个点,这两个点与原点一起定义平面的两个轴。这些轴不必是正交的 - 因此您可以创建平行…

基于yolov5的数据集自动标注功能脚本工具【附代码】

近年来&#xff0c;随着深度学习的迅猛发展&#xff0c;计算机视觉领域取得了巨大的突破。其中&#xff0c;目标检测是计算机视觉中的一个重要任务&#xff0c;它在许多应用领域中起到了至关重要的作用。然而&#xff0c;目标检测所需的大量标注数据集的制作却是一项耗时且繁琐…

FlashInternImage实战:使用 FlashInternImage实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

mac配置L2TP连接公司内网

1. 打开系统设置 2. 打开网络 3. 点击网络页面其他服务右下角三个点&#xff0c;添加VPN配置中的L2TP 4. 配置VPN&#xff0c;服务器填写公司的服务器ip&#xff0c;共享密钥没有可以随便填写 5. 打开终端编辑文件 sudo vim /etc/ppp/opt…

Linux系统简介及发展历史

Linux的概况 Linux是自由软件 Linux是一种类UNIX操作系统。Linux内核由Linus Torvalds在1991年发布。在加上用户空间的应用程序之后&#xff0c;成为Linux操作系统 只要遵循GNU通用公共许可证&#xff08;GPL&#xff09;&#xff0c;任何个人和机构都可以自由地使用Linux的所…

网络安全02--负载均衡下的webshell连接

目录 一、环境准备 1.1ubentu虚拟机一台&#xff0c;docker环境&#xff0c;蚁剑 1.2环境压缩包&#xff08;文件已上传资源&#xff09;&#xff1a; 二、开始复原 2.1上传ubentu&#xff1a; 2.2解压缩 2.3版本20没有docker-compose手动下载&#xff0c;包已上传资源 …

Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心,Kotlin(2)

Android双指缩放ScaleGestureDetector检测放大因子大图移动到双指中心点ImageView区域中心&#xff0c;Kotlin&#xff08;2&#xff09; 在 Android ScaleGestureDetector检测双指缩放Bitmap基于Matrix动画移动到双指捏合中心点ImageView区域中心&#xff0c;Kotlin-CSDN博客 …

vue+Element UI实现省市区镇四级联动

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 在一些需要填写地址的前端页面中&#xff0c;总是少不了需要填写地址的级联选择器&#xff0c;类似这样的&…

【Linux】第三十六站:信号

文章目录 一、信号的概念1.信号概念2.前台与后台进程3.信号的处理4.硬件层面5.信号与我们的代码是异步的 二、信号的产生1.产生的方式2.键盘组合键3.kill命令4.系统调用4.1 kill系统调用4.2 raise4.3 abort 5.异常软件条件5.1 异常产生信号5.2 alarm&#xff08;软件条件产生信…

【Linux】第三十七站:信号保存

文章目录 一、信号发送二、信号保存1.为什么要进行信号保存&#xff1f; 三、阻塞信号1.信号的一些相关概念2.在内核中的表示3.sigset_t4.信号集操作函数5.sigprocmask6.sigpending7. 总结 一、信号发送 如下所示&#xff0c;对于普通信号&#xff0c;它的编号是从1~31。这个是…

N-141基于springboot,vue网上拍卖平台

开发工具&#xff1a;IDEA 服务器&#xff1a;Tomcat9.0&#xff0c; jdk1.8 项目构建&#xff1a;maven 数据库&#xff1a;mysql5.7 系统分前后台&#xff0c;项目采用前后端分离 前端技术&#xff1a;vueelementUI 服务端技术&#xff1a;springbootmybatis-plusredi…

九州金榜|为什么鼓励式家庭教育?

鼓励式教育是一种积极的教育方式&#xff0c;它强调通过鼓励和肯定来激发孩子的积极性和自信心&#xff0c;帮助孩子更好地成长和发展。在家庭教育中&#xff0c;鼓励式教育同样具有重要意义。九州金榜家庭教育和大家一起探讨关于鼓励式教育的好处以及意义&#xff1a; 一.有助…

JRT实体比对

之前已经实现了JRT实体编译的菜单&#xff0c;用Linux指令编译放在网站下的实体代码。那么就有个问题&#xff0c;有人就是直接换实体jar文件不修改网站的实体代码。或者就只修改实体代码不编译搁置在那里&#xff0c;那么后面更新实体的人就得给别人背锅&#xff0c;后面人新编…

机器学习 | 如何使用 Seaborn 提升数据分析效率

Seaborn和Matplotlib都是Python可视化库&#xff0c;它们都可以用于创建各种类型的图表。但是&#xff0c;Seaborn 和Matplotlib在概念和设计上有一些不同。 Matplotlib虽然已经是比较优秀的绘图库了&#xff0c;但是它有个今人头疼的问题&#xff0c;那就是API使用过于复杂&am…

Blender教程(基础)-物体的移动、旋转与缩放-04

一、新建一个立方体 ShiftA新建一个立方体用来演示。 二、物体的移动 xyz轴移动 点击下图图左侧的移动选项后&#xff0c;选中要移动的物体&#xff0c;会出现三个箭头的方向&#xff0c;这分别代表沿着x、y、z轴移动。xyz平面移动 这个小正方体代表沿着某一个面移动&#…

04.领域驱动设计:了解聚合和聚合根,怎样设计聚合

目录 1、概述 2、聚合 3、聚合根 4、怎么设计聚合 4.1 聚合的构建过程主要步骤 第 1 步&#xff1a;采用事件风暴。 第 2 步&#xff1a;选出聚合根。 第 3 步&#xff1a;找出与聚合根关联的所有紧密依赖的实体和值对象。 第 4 步&#xff1a;画出对象的引用和依赖模型…

vue3框架基本使用

一、安装包管理工具 vite和vue-cli一样&#xff0c;都是脚手架。 1.node版本 PS E:\vuecode\vite1> node -v v18.12.12.安装yarn工具 2.1 yarn简单介绍 yarn是一个包管理工具&#xff0c;也是一个构建、打包工具 yarn需要借助npm进行安装&#xff1a;执行的命令行npm i…

找不同-《企业应用架构模式》2024典藏版

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 以下是2004年《企业应用架构模式》中译本和2024年《企业应用架构模式》典藏版译本的页面。 您能从中找出至少10处不同吗&#xff1f; 如何选择UMLChina服务 UMLChina公众号精选&…

Blender教程(基础)-面的细分与删除、挤出选区-07

一、Blender之面的细分 新建一个立方体&#xff0c;在编辑模式下、选中一个面。 在选中的面上单击右键弹出细分选项&#xff0c;选择细分。 在选中细分后、会默认细分1次。修改细分次数在左下角 二、Blender之面的删除 选择中需要操作的面&#xff0c;在英文状态下按X键弹…

VSCode 1.85.0更新的3个实用功能

1、单个文件可直接拖拽为独立窗口 当单文件过长&#xff0c;直接分成两个视图就不用上下频繁滚动 2、将终端移动到编辑器区域 此时&#xff0c;终端也可像文件一样拖拽为独立窗口 3、文件夹目录粘性头部 默认关闭&#xff0c;需要设置 "workbench.tree.enableStickyScro…