java 工具类: CompareUtils(比较对象字段值变化)

一、前言

   我们在工作中,可能会在日志中记录数据的变化情况或者在公共处理的数据增加一个日志页面,记录每次修改的变化。我们可以根据CompareUtils工具类比较数据前后发生了怎样的变化, 这样我们就可以知道数据做了哪些改变.

二、条件限制

在写这个通用方法时,我们应该考虑到以下几点:

(1)可以接收任何对象的比较,但比较的对象应该是同个对象;

(2)可以给字段进行一个备注,因为我们看到的最终内容,应该是一个中文名称;

(3)一个对象中,可以忽略某些字段进行比较,只要我需要的字段进行比较。

2.1创建比较接口(自定义注解)

package com.zyqok.utils.compare;
 
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
/**
 * 字段标记注解
 *
 * @author qsg
 * @since 2022/05/05
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Compare {
 
    /**
     * 字段名称
     */
    String value();
}

 2.2 CompareNode(比较类)

package com.sinosoft.springbootplus.partyMember.compare;
/**
 * @author qsg
 * @since 2022/05/05
 */
public class CompareNode {

    /**
     * 字段
     */
    private String fieldKey;

    /**
     * 字段值
     */
    private Object fieldValue;

    /**
     * 字段名称
     */
    private String fieldName;

    public String getFieldKey() {
        return fieldKey;
    }

    public void setFieldKey(String fieldKey) {
        this.fieldKey = fieldKey;
    }

    public Object getFieldValue() {
        return fieldValue;
    }

    public void setFieldValue(Object fieldValue) {
        this.fieldValue = fieldValue;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }
}

2.3创建比较对象(比较同一个实体)

在字段上方加上我们的自定义注解 @Compare注解, 可以通过注解进行两个对象的字段值的比较。

package com.sinosoft.springbootplus.partyMember.exportExcel;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.sinosoft.springbootplus.mybaitsextend.dict.annotation.Dict;
import com.sinosoft.springbootplus.partyMember.compare.Compare;
import com.sinosoft.springbootplus.util.KeyStoreUtils;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * <pre>
 *
 * </pre>
 *
 * @Author qsg
 * @Date 2023/11/29 9:29
 * @Version 1.0
 **/
@Data
@Slf4j
public class PartyMemberDiffExcel {

   private static final long serialVersionUID = 1L;

    private Long id;

    @ExcelProperty(value = "序号",index = 0)
    private int sortNum;

    @ExcelProperty(value = "党员姓名",index = 1)
    @Compare("党员姓名")
    private String memberName;

    @ExcelProperty(value = "性别",index = 2)
    @Dict(name = "sex" , dataSource = Dict.Type.DB, target = "memberSex")
    @Compare("性别")
    private String memberSex;

    @ExcelProperty(value = "年龄",index = 3)
    @Compare("年龄")
    private String age;

    @ExcelProperty(value = "出生日期",index = 4)
    @Compare("出生日期")
    private String birthday;

    @ExcelProperty(value = "民族",index = 5)
    @Dict(name = "nation", dataSource = Dict.Type.DB, target = "nation")
    @Compare("民族")
    private String nation;

    @ExcelProperty(value = "籍贯",index = 6)
    @Compare("籍贯")
    private String nativePlace;

    @ExcelProperty(value = "身份证号",index = 7)
    @Compare("身份证")
    private String cardId;

    @ExcelProperty(value = "所属党组织",index = 8)
    @Dict(name = "part_org_name", dataSource = Dict.Type.SERVIE, target = "partyOrgId")
    @Compare("所属党组织")
    private String partyOrgId;

    @ExcelProperty(value = "学历",index = 9)
    @Dict(name = "education_type", dataSource = Dict.Type.DB, target = "degree")
    @Compare("学历")
    private String degree;

    @ExcelProperty(value = "参加工作时间",index = 10)
    @Compare("参加工作时间")
    private String workTime;

    @ExcelProperty(value = "加入党组织日期",index = 11)
    @Compare("加入党组织日期")
    private String joinTime;

    @ExcelProperty(value = "转为正式党员日期",index = 12)
    @Compare("转为正式党员日期")
    private String regularTime;

    @ExcelProperty(value = "党籍状态",index = 13)
    @Dict(name = "party_status", target = "partyStatus", dataSource = Dict.Type.DB)
    @Compare("党籍状态")
    private String partyStatus;

    @ExcelProperty(value = "行政职务",index = 14)
    @Dict(name = "amd_postion" , dataSource = Dict.Type.DB, target = "admPosition")
    @Compare("行政职务")
    private String admPosition;

    @ExcelProperty(value = "职称",index = 15)
    @Dict(name = "title_type" , dataSource = Dict.Type.DB, target = "positionalTitles")
    @Compare("职称")
    private String positionalTitles;

    @ExcelProperty(value = "工作在一线情况",index = 16)
    @Compare("工作在一线情况")
    private String workingConditions;

    @ExcelProperty(value = "手机号码",index = 17)
    @Compare("手机号码")
    private String mobileNo;
}

2.4CompareUtils(比较工具类)

package com.sinosoft.springbootplus.partyMember.compare;

import org.apache.poi.ss.formula.functions.T;
import java.lang.reflect.Field;

import java.util.*;

/**
 * <pre>
 *
 * </pre>
 *
 * @Author qsg
 * @Date 2023/11/28 15:14
 * @Version 1.0
 **/
public class CompareUtils<T> {

    private static final String COMMA = ",";

    /**
     * 属性比较
     *
     * @param source 源数据对象
     * @param target 目标数据对象
     * @return 对应属性值的比较变化
     */
    public String compare(T source, T target) {
        return compare(source, target, null);
    }


    /**
     * 属性比较
     *
     * @param source              源数据对象
     * @param target              目标数据对象
     * @param ignoreCompareFields 忽略比较的字段
     * @return 对应属性值的比较变化
     */
    public String compare(T source, T target, List<String> ignoreCompareFields) {
        if (Objects.isNull(source) && Objects.isNull(target)) {
            return "";
        }
        Map<String, CompareNode> sourceMap = this.getFiledValueMap(source);
        Map<String, CompareNode> targetMap = this.getFiledValueMap(target);
        if (sourceMap.isEmpty() && targetMap.isEmpty()) {
            return "";
        }
        // 如果源数据为空,则只显示目标数据,不显示属性变化情况
        if (sourceMap.isEmpty()) {
            return doEmpty(targetMap, ignoreCompareFields);
        }
        // 如果源数据为空,则显示属性变化情况
        String s = doCompare(sourceMap, targetMap, ignoreCompareFields);
        if (!s.endsWith(COMMA)) {
            return s;
        }
        return s.substring(0, s.length() - 1);
    }

    private String doEmpty(Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
        StringBuilder sb = new StringBuilder();
        Collection<CompareNode> values = targetMap.values();
        int size = values.size();
        int current = 0;
        for (CompareNode node : values) {
            current++;
            Object o = Optional.ofNullable(node.getFieldValue()).orElse("");
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(node.getFieldKey())) {
                continue;
            }
            if (o.toString().length() > 0) {
                sb.append("[" + node.getFieldName() + ":" + o + "]");
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        return sb.toString();
    }

    private String doCompare(Map<String, CompareNode> sourceMap, Map<String, CompareNode> targetMap, List<String> ignoreCompareFields) {
        StringBuilder sb = new StringBuilder();
        Set<String> keys = sourceMap.keySet();
        int size = keys.size();
        int current = 0;
        for (String key : keys) {
            current++;
            CompareNode sn = sourceMap.get(key);
            CompareNode tn = targetMap.get(key);
            if (Objects.nonNull(ignoreCompareFields) && ignoreCompareFields.contains(sn.getFieldKey())) {
                continue;
            }
            String sv = Optional.ofNullable(sn.getFieldValue()).orElse("").toString();
            String tv = Optional.ofNullable(tn.getFieldValue()).orElse("").toString();
            // 只有两者属性值不一致时, 才显示变化情况
            if (!sv.equals(tv)) {
                sb.append(String.format("[%s:%s -> %s]", sn.getFieldName(), sv, tv));
                if (current < size) {
                    sb.append(COMMA);
                }
            }
        }
        return sb.toString();
    }

    private Map<String, CompareNode> getFiledValueMap(T t) {
        if (Objects.isNull(t)) {
            return Collections.emptyMap();
        }
        Field[] fields = t.getClass().getDeclaredFields();
        if (Objects.isNull(fields) || fields.length == 0) {
            return Collections.emptyMap();
        }
        Map<String, CompareNode> map = new LinkedHashMap();
        for (Field field : fields) {
            Compare annotation = field.getAnnotation(Compare.class);
            if (Objects.isNull(annotation)) {
                continue;
            }
            field.setAccessible(true);
            try {
                String fieldKey = field.getName();
                CompareNode node = new CompareNode();
                node.setFieldKey(fieldKey);
                node.setFieldValue(field.get(t));
                node.setFieldName(annotation.value());
                map.put(field.getName(), node);
            } catch (IllegalArgumentException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return map;
    }
}

三、比较现在的对象和之前的对象的值的变化

代码实现

 public List<String> expDiffPartyMembers(PartyMemberDifferentParam partyMemberDifferentParam,HttpServletResponse response) throws IOException {
        //日志标题设置为常量
        final String TITLE = "修改党员基本信息服务";
        //查询出sys_log表中更新党员的数据信息
        List<SysLog> sysLogs = sysLogMapper.selectList(
                new QueryWrapper<SysLog>().eq("type", LogTypeEnum.UPDATE.getCode())
                        .eq("title", TITLE)
                        .ge("request_time", partyMemberDifferentParam.getStarTime())
                        .le("request_time", partyMemberDifferentParam.getEndTime()));
        List<PartyMemberDiffExcel> partyMemberDiffs = new ArrayList<>();
        // 创建SimpleDateFormat对象,指定日期时间格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Gson gson = new Gson();
        for (SysLog sysLog : sysLogs) {
            //获取党员修改json数据
            SysLogParam sysLogParam = sysLogParamMapper.selectById(sysLog.getId());
            String param = sysLogParam.getParam();
            //将党员信息json转换为对象
            PartyMemberDiffDto partyMemberDiffDto = gson.fromJson(param, PartyMemberDiffDto.class);
            PartyMemberDiffExcel partyMember = new PartyMemberDiffExcel();
            partyMember.setId(partyMemberDiffDto.getId());
            partyMember.setMemberName(partyMemberDiffDto.getMemberName());
            partyMember.setMemberSex(partyMemberDiffDto.getMemberSex());
            partyMember.setAge(String.valueOf(partyMemberDiffDto.getAge()));
            partyMember.setBirthday(ObjectUtils.isNotEmpty(partyMemberDiffDto.getBirthday())? sdf.format(new Date(partyMemberDiffDto.getBirthday())) :"" );
            partyMember.setNation(partyMemberDiffDto.getNation());
            partyMember.setNativePlace(partyMemberDiffDto.getNativePlace());
            partyMember.setCardId(partyMemberDiffDto.getCardId());
            partyMember.setPartyOrgId(String.valueOf(partyMemberDiffDto.getPartyOrgId()));
            partyMember.setDegree(partyMemberDiffDto.getDegree());
            partyMember.setWorkTime(partyMemberDiffDto.getWorkTime()!=null? sdf.format(new Date(partyMemberDiffDto.getWorkTime())):"");
            partyMember.setJoinTime(partyMemberDiffDto.getJoinTime()!=null? sdf.format(new Date(partyMemberDiffDto.getJoinTime())):"");
            partyMember.setRegularTime(partyMemberDiffDto.getRegularTime()!=null?sdf.format(new Date(partyMemberDiffDto.getJoinTime())):"");
            partyMember.setPartyStatus(partyMemberDiffDto.getPartyStatus());
            partyMember.setAdmPosition(partyMemberDiffDto.getAdmPosition());
            partyMember.setPositionalTitles(partyMemberDiffDto.getPositionalTitles());
            partyMember.setWorkingConditions(partyMemberDiffDto.getWorkingConditions());
            partyMember.setMobileNo(partyMemberDiffDto.getMobileNo());
            //放到list中存贮
            partyMemberDiffs.add(partyMember);
        }
        //去重
        List<PartyMemberDiffExcel> collect = partyMemberDiffs.stream().distinct().collect(Collectors.toList());
        //存储修改之后的党员信息id(现在党员表中的信息)
            List<Long> memberIds = new ArrayList<>();
        //获取在时间段修改的党员信息
        for (PartyMemberDiffExcel partyMemberDiffExcel : collect) {
            memberIds.add(partyMemberDiffExcel.getId());
        }
        List<String> list  = new ArrayList<>();
        //获取改之后的党员信息id(现在党员表中的信息)
        List<PartyMember> partyMemberList = partyMemberDomain.getPartyMemberDiff(memberIds);
        //现在的党员
        List<PartyMemberDiffExcel> partyMemberDiffNows = new ArrayList<>();
        for (PartyMember partyMember:partyMemberList){
            PartyMemberDiffExcel partyMemberDiffExcel = new PartyMemberDiffExcel();
            partyMemberDiffExcel.setId(partyMember.getId());
            partyMemberDiffExcel.setMemberName(partyMember.getMemberName());
            partyMemberDiffExcel.setMemberSex(partyMember.getMemberSex());
            partyMemberDiffExcel.setAge(String.valueOf(partyMember.getAge()));
            partyMemberDiffExcel.setBirthday(ObjectUtils.isNotEmpty(partyMember.getBirthday())? sdf.format(partyMember.getBirthday()) :"" );
            partyMemberDiffExcel.setNation(partyMember.getNation());
            partyMemberDiffExcel.setNativePlace(partyMember.getNativePlace());
            partyMemberDiffExcel.setCardId(partyMember.getCardId());
            partyMemberDiffExcel.setPartyOrgId(String.valueOf(partyMember.getPartyOrgId()));
            partyMemberDiffExcel.setDegree(partyMember.getDegree());
            partyMemberDiffExcel.setWorkTime(partyMember.getWorkTime()!=null? sdf.format(partyMember.getWorkTime()):"");
            partyMemberDiffExcel.setJoinTime(partyMember.getJoinTime()!=null? sdf.format(partyMember.getJoinTime()):"");
            partyMemberDiffExcel.setRegularTime(partyMember.getRegularTime()!=null?sdf.format(partyMember.getJoinTime()):"");
            partyMemberDiffExcel.setPartyStatus(partyMember.getPartyStatus());
            partyMemberDiffExcel.setAdmPosition(partyMember.getAdmPosition());
            partyMemberDiffExcel.setPositionalTitles(partyMember.getPositionalTitles());
            partyMemberDiffExcel.setWorkingConditions(partyMember.getWorkingConditions());
            partyMemberDiffExcel.setMobileNo(partyMember.getMobileNo());

            partyMemberDiffNows.add(partyMemberDiffExcel);
        }
//循环比较两个对象值的变化
        for (int i = 0; i < partyMemberList.size(); i++) {
            String compare = new CompareUtils<PartyMemberDiffExcel>().compare(collect.get(i), partyMemberDiffNows.get(i));
            System.out.println(compare);
            list.add(compare);
        return list;
    }

结果

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

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

相关文章

【Leetcode题单】(01 数组篇)刷题关键点总结01【数组的遍历】

【Leetcode题单】&#xff08;01 数组篇&#xff09;刷题关键点总结01【数组的遍历】&#xff08;4题&#xff09; Easy数组的遍历485. 最大连续 1 的个数 Easy495. 提莫攻击 Easy414. 第三大的数 Easy628. 三个数的最大乘积 Easy 大家好&#xff0c;这里是新开的LeetCode刷题系…

【数组和函数实战: 斗地主游戏】

目录 1. 玩法说明 2. 分析和设计 3. 代码实现 4. 游戏演示1. 玩法说明 一副54张牌,3最小,两个王最大,其实是2,和上面一样从大到小排列 2. 分析和设计 2.1 分析和设计 常量和变量设计 一副牌有54张,有牌的数值和花色,可以分别用两个数组来存储,card为卡牌表示的数值,color为…

Git 标签管理

前言 标签 tag&#xff0c;就相当于对 某一次的 commit 做一个标识&#xff0c;起了一个别名&#xff0c;例如&#xff1a;在某个项目发布版本的时候&#xff0c;可针对最后一次 commit 起一个别名 v1.0 来标识这一次的commit。tag 的作用&#xff1a;commit id 相对于 tag 是很…

openwrt上开启syslog打印方法

最近在openwrt上调试蓝牙时&#xff0c;出现问题&#xff0c;设备上的蓝牙适配器已经正常工作了&#xff0c;执行pair命令后&#xff0c;openwrt和待连接的设备上都出现了配对码&#xff0c;两边都同意&#xff0c;但连接失败 尝试分析log&#xff0c;发现在如下代码处打印了错…

代码随想录算法训练营 ---第五十二天

第一题&#xff1a; 简介&#xff1a; 动态规划五部曲&#xff1a; 1.确定 dp数组下标的定义 dp[i] 到达 i 时 最长递增子序列的长度 2.确定递推公式 我们确定当前的最大长度需要遍历前面所有的最大长度&#xff0c;然后如果序列最后一个值小于nums[i]那就dp[j] 1&#xf…

Redis--13--缓存一致性问题

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 缓存一致性问题1、先更新缓存&#xff0c;再更新DB方案二&#xff1a;先更新DB&#xff0c;再更新缓存方案三&#xff1a;先删缓存&#xff0c;再写数据库推荐1&…

Elk-filebeat

前言 Elk&#xff1a;filebeat搜集日志工具和logstash相同 Filebeat是一个轻量级的日志收集工具&#xff0c;所使用的资源比logstash部署和启动时使用的资源更小 Filebeat可以运行在非Java环境&#xff0c;他可以代理logstash在非Java环境上收集日志 Filebeat无法实现数据的…

【选择题】校招笔试选择题第一辑

题目 以下程序的运行结果是&#xff08; &#xff09; #include <stdio.h> int main(void) {printf("%s , %5.3s\n", "computer", "computer");return 0; }A. computer , puter B. computer , com C. computer , computer D. computer…

zookeeper+kafka+ELK+filebeat集群

目录 一、zookeeper概述&#xff1a; 1、zookeeper工作机制&#xff1a; 2、zookeeper主要作用&#xff1a; 3、zookeeper特性&#xff1a; 4、zookeeper的应用场景&#xff1a; 5、领导者和追随者&#xff1a;zookeeper的选举机制 二、zookeeper安装部署&#xff1a; 三…

STM32-SPI 中断

SPI协议 1.1 SPI总线介绍 SPI接口是Motorola &#xff08;motorola | Smartphones, Accessories & Smart Home Devices&#xff09;首先提出的全双工三线/四线同步串行外围接口采用主从模式&#xff08;Master Slave&#xff09;架构。 时钟由Master控制&#xff0c;在时钟…

【Leetcode题单】(01 数组篇)刷题关键点总结02【统计数组中的元素】

【Leetcode题单】&#xff08;01 数组篇&#xff09;刷题关键点总结02【统计数组中的元素】&#xff08;6题&#xff09; 统计数组中的元素645. 错误的集合 Easy697. 数组的度 Easy448. 找到所有数组中消失的数字 Easy442. 数组中重复的数据 Medium41. 缺失的第一个正数 Hard27…

Docker镜像制作与推送

目录 Docker镜像制作 搭建私服 将本地镜像推送到私有库 Docker镜像制作 以创建一个新ubuntu镜像&#xff0c;并安装vim命令示例 运行一个ubuntu镜像&#xff0c;发现在镜像里面无法使用vim命令&#xff0c;因为该ubuntu镜像只包括了其最基本的内核命令 [rootlocalhost ~]…

找不到msvcp110.dll如何修复?分享5个亲测有效的修复方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp110.dll丢失”。这个错误通常发生在运行某些程序时&#xff0c;系统无法找到所需的动态链接库文件。那么&#xff0c;msvcp110.dll到底是什么呢&#xff1f;它又有什么作用&#xff1…

算法通关村第七关—理解二叉树的遍历(白银)

深入理解前中后序遍历 给定一棵二叉树 二叉树前序遍历 public void preorder(TreeNode root,List<Integer>res){if&#xff08;rootnull){return;}res.add(root.val);preorder(root.left,res);preorder(root.right,res); }递归的过程如下图所示 从图中可以看到&#x…

〖大前端 - 基础入门三大核心之JS篇㊺〗- 定时器和延时器

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;不渴望力量的哈士奇(哈哥)&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xf…

12月1号作业

实现运算符重载 #include <iostream>using namespace std; class Person{friend const Person operator-(const Person &L,const Person &R);friend bool operator<(const Person &L,const Person &R);friend Person operator-(Person &L,const …

第二十二章 指定元素和属性的命名空间 - 指定被视为Global元素的对象的命名空间

文章目录 第二十二章 指定元素和属性的命名空间 - 指定被视为Global元素的对象的命名空间指定被视为Global元素的对象的命名空间指定映射为元素的属性的命名空间案例1&#xff1a;属性被视为本地元素案例2:属性被视为Global元素 第二十二章 指定元素和属性的命名空间 - 指定被视…

Unity 简单打包脚本

打包脚本 这个打包脚本适用于做demo&#xff0c;脚本放在Editor目录下 using System; using System.Collections; using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEngine;public class BuildAB {[MenuItem("Tools/递归遍历文件夹下…

【蓝桥杯】带分数

带分数 题目要求用一个ab/c的形式得到一个值&#xff0c;而且只能在1~9里面不重复的组合。 可以对1~9进行全排列&#xff0c;然后不断划分区间。 #include<iostream> #include<vector> using namespace std; int st[15]; int num[15]; int res; int n;int calc(i…

基于Python实现的滑动验证码自动识别工具源码

滑动验证码识别 今天的目标地址是字节的巨量纵横&#xff0c;目前东家是一家广告营销型的公司&#xff0c;专注于在各大平台投放信息流广告。巨量纵横为字节跳动的广告平台&#xff0c;用于管理推广账户。今天破解一下这个平台的登陆入口&#xff0c;为今后的数据爬取开个头。…