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

news2025/1/21 22:01:05

一、前言

   我们在工作中,可能会在日志中记录数据的变化情况或者在公共处理的数据增加一个日志页面,记录每次修改的变化。我们可以根据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;
    }

结果

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

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

相关文章

Ontrack EasyRecovery2024数据恢复软件详细功能介绍

Ontrack EasyRecovery2024是一款功能强大的数据恢复软件&#xff0c;它可以帮助用户从各种存储设备中恢复丢失或删除的数据。它支持多种文件系统和文件类型&#xff0c;可以恢复包括照片、视频、音频、文档、电子邮件和归档文件等不同类型的数据。 EasyRecovery15Mac版本下载如…

轻易云AI:引领企业数智化转型提升企业AI效率

近期&#xff0c;轻易云AI与汤臣倍健的合作引起了业界的广泛关注。通过这一合作&#xff0c;轻易云AI不仅成功打造了集团小汤AI助手这一标志性的企业智能助手&#xff0c;更重要的是&#xff0c;这一合作凸显了轻易云AI作为专业AI应用集成专家的核心能力。轻易云AI已成功集成了…

柯桥西班牙语学校|实用西语吉祥话,场景都帮你想好了

1. ¡Feliz cumpleaos! Que este da est lleno de alegra, amor y bendiciones. (祝你生日快乐&#xff01;愿这一天充满欢乐、爱和祝福。) 2. ¡Hey [nombre del amigo/a]! Sabes qu da es hoy? ¡Es tu cumpleaos! Quera aprovechar para desearte un da lleno…

SSL证书如何影响SEO优化结果?

1.搜索引擎偏好&#xff1a;谷歌、百度等主流搜索引擎明确表示&#xff0c;他们会优先收录并给予使用HTTPS协议的网站更高的排名。这是因为HTTPS提供了一种更为安全的浏览环境&#xff0c;有助于提升用户的信任度和满意度。 2.用户体验&#xff1a;安装SSL证书可以提高网站的信…

【面试攻略】Oracle中blob和clob的区别及查询修改方法

大家好&#xff0c;我是小米&#xff0c;欢迎来到小米的技术小屋&#xff01;今天我们要一起来聊聊一个在面试中常常被问到的问题——“Oracle中Blob和Clob有啥区别&#xff0c;在代码中怎么查询和修改这两个类型的字段里的内容&#xff1f;”别急&#xff0c;跟着小米一步步揭…

WordPress付费阅读、付费下载、付费复制插件推荐

如果我们是用WordPress内核程序&#xff0c;我们可以用插件解决这个功能。现在市面上小编有看到三款WordPress内容付费或者是有的称作WordPress会员插件&#xff0c;可以实现WordPress付费阅读、付费下载&#xff0c;甚至付费复制的功能。在这几个插件中&#xff0c;简单的盘点…

文案二次创作软件,文案二次创作的软件

文案创作成为品牌传播和营销不可或缺的一环。对于许多从业者而言&#xff0c;文案创作常常是一项既耗时又耗力的工作。为了解决这一文案创作的难题&#xff0c;市场上涌现出了众多的智能文案生成工具。我们通过对这些工具的介绍和分析&#xff0c;希望能够为你提供一些在文案创…

微服务实战系列之Redis

前言 云淡天高&#xff0c;落木萧萧&#xff0c;一阵西北风掠过&#xff0c;似寒刀。冬天渐渐变得更名副其实了&#xff0c;“暖冬”的说法有点言过其实了。——碎碎念 微服务实战系列之Cache微服务实战系列之Nginx&#xff08;技巧篇&#xff09;微服务实战系列之Nginx微服务实…

实战分析和精华总结:CORS跨域资源共享漏洞数据劫持、复现、分析、利用及修复过程

实战分析和精华总结:CORS跨域资源共享漏洞数据劫持、复现、分析、利用及修复过程。 CORS跨域资源共享漏洞与JSONP劫持漏洞类似,都是程序员在解决跨域问题中进行了错误的配置。攻击者可以利用Web应用对用户请求数据包的Origin头校验不严格,诱骗受害者访问攻击者制作好的恶意…

微前端实战:打造高效、灵活的前端应用架构

文章目录 一、微前端简介二、微前端的优势1. 高度模块化2. 独立部署3. 易于扩展4. 技术栈无关5. 独立升级 三、微前端的原理四、微前端案例思路《微前端实战》编辑推荐内容简介作者简介目录前言/序言 随着互联网行业的快速发展&#xff0c;前端应用的规模和复杂度也在不断增加。…

controller能接收到数据有数据但是前端无法显示数据

又是制作系统时遇到的问题。只是想做个查询商品的页面&#xff0c;结果弄了一天&#xff0c;在网上各种查问题&#xff0c;各种解决办法用在我的代码上&#xff0c;换了无数种关键词搜索终于找到了一条成功解决了问题。 问题描述&#xff1a; 事情是这样的&#xff1a;我要写一…

Go读取yaml文件,struct返回,json输出

程序模块中&#xff0c;缺少不了一些配置定义&#xff0c;这时定义yaml是个很好的选择 先定义yaml文件内容&#xff0c;文件名为&#xff1a;task_status_config.yaml confs:#阅读类任务&#xff0c;即提醒任务read:name: readawait: #待开始任务status_id: 0ing: #进行中任务…

Python遥感开发之批量拼接

Python遥感开发之批量拼接 1 遥感图像无交错的批量拼接2 遥感图像有交错的批量拼接 前言&#xff1a;主要借助python实现遥感影像的批量拼接&#xff0c;遥感影像的批量拼接主要分为两种情况&#xff0c;一种是遥感图像无交错&#xff0c;另一种情况是遥感图像相互有交错。具体…

模板可变参数/包装器

一、什么是模板可变参数 1、对比函数可变参数 可变参数即参数的数量是不确定的&#xff0c;底层根据用户传入的数量&#xff0c;开一个数组存储对应的参数。 2、基本形式 args -- argument 参数 [0,n]个参数 // Args是一个模板参数包&#xff0c;args是一个函数形参参数包…

mysql语句性能分析工具——profiling

以往我们已经介绍了一个mysql的分析工具&#xff1a;mysql慢查询日志分析工具&#xff08;pt-query-digest)&#xff0c;可以看我的文章&#xff1a;mysql慢查询日志分析工具&#xff08;pt-query-digest)-CSDN博客 一、profiling的介绍 sql查询慢的情况很常见&#xff0c;对…

43 - 什么是数据的强、弱一致性?

说到一致性&#xff0c;其实在系统的很多地方都存在数据一致性的相关问题。除了在并发编程中保证共享变量数据的一致性之外&#xff0c;还有数据库的 ACID 中的 C&#xff08;Consistency 一致性&#xff09;、分布式系统的 CAP 理论中的 C&#xff08;Consistency 一致性&…

【Docker实操】创建一个Nginx服务

一、获取nginx官方镜像 docker pull nginx //拉取nginx官方镜像 docker image nginx //查看镜像二、创建项目目录 项目目录&#xff1a;/root/www2/nginx //如果当前目录在root mkdir www2 mkdir www2/nginx cd www2/nginx //进入项目目录三、创建源码文件 //当前目录&…

jsp高校教师调课管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 高校教师调课管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

react native 环境准备

一、必备安装 1、安装node 注意 Node 的版本应大于等于 16&#xff0c;安装完 Node 后建议设置 npm 镜像&#xff08;淘宝源&#xff09;以加速后面的过程&#xff08;或使用科学上网工具&#xff09;。 node下载地址&#xff1a;Download | Node.js设置淘宝源 npm config s…

GEE:均值滤波

作者:CSDN @ _养乐多_ 本文将介绍在 Google Earth Engine(GEE)平台上,进行均值滤波操作的代码框架、核心函数和多种卷积核。 并分别以林地区域和农田区域为试验区,以NDVI图像为例。结果如下图所示, 文章目录 一、均值滤波二、完整代码三、代码链接一、均值滤波 均值滤…