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;
    }

结果

相关推荐
顾北川_野2 分钟前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
江深竹静,一苇以航5 分钟前
springboot3项目整合Mybatis-plus启动项目报错:Invalid bean definition with name ‘xxxMapper‘
java·spring boot
远望清一色11 分钟前
基于MATLAB的实现垃圾分类Matlab源码
开发语言·matlab
confiself21 分钟前
大模型系列——LLAMA-O1 复刻代码解读
java·开发语言
Wlq041525 分钟前
J2EE平台
java·java-ee
XiaoLeisj32 分钟前
【JavaEE初阶 — 多线程】Thread类的方法&线程生命周期
java·开发语言·java-ee
杜杜的man36 分钟前
【go从零单排】go中的结构体struct和method
开发语言·后端·golang
幼儿园老大*36 分钟前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
半桶水专家37 分钟前
go语言中package详解
开发语言·golang·xcode
llllinuuu38 分钟前
Go语言结构体、方法与接口
开发语言·后端·golang