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

结果

相关推荐
哎呦没21 分钟前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
Kalika0-039 分钟前
猴子吃桃-C语言
c语言·开发语言·数据结构·算法
_.Switch40 分钟前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
编程、小哥哥1 小时前
netty之Netty与SpringBoot整合
java·spring boot·spring
代码雕刻家1 小时前
课设实验-数据结构-单链表-文教文化用品品牌
c语言·开发语言·数据结构
一个闪现必杀技1 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
Fan_web1 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
龙图:会赢的1 小时前
[C语言]--编译和链接
c语言·开发语言
IT学长编程2 小时前
计算机毕业设计 玩具租赁系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·玩具租赁系统
莹雨潇潇2 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器