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

一、前言

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

二、条件限制

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

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

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

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

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

java 复制代码
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(比较类)

java 复制代码
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注解, 可以通过注解进行两个对象的字段值的比较。

java 复制代码
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(比较工具类)

java 复制代码
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;
    }
}

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

代码实现

java 复制代码
 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;
    }

结果

相关推荐
猷咪6 分钟前
C++基础
开发语言·c++
IT·小灰灰7 分钟前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧9 分钟前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q9 分钟前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳09 分钟前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾9 分钟前
php 对接deepseek
android·开发语言·php
vx_BS8133013 分钟前
【直接可用源码免费送】计算机毕业设计精选项目03574基于Python的网上商城管理系统设计与实现:Java/PHP/Python/C#小程序、单片机、成品+文档源码支持定制
java·python·课程设计
2601_9498683613 分钟前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计27 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
qq_1777673739 分钟前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos