Browse Source

1.事件处置流程

2.比对工具
develop
lau572 12 months ago
parent
commit
50a56fed32
  1. 44
      zc-business/src/main/java/com/zc/business/controller/DcEventController.java
  2. 119
      zc-business/src/main/java/com/zc/business/enums/ValueConverter.java
  3. 21
      zc-business/src/main/java/com/zc/business/mapper/DcEventMapper.java
  4. 2
      zc-business/src/main/java/com/zc/business/mapper/DcEventProcessMapper.java
  5. 31
      zc-business/src/main/java/com/zc/business/service/IDcEventService.java
  6. 10
      zc-business/src/main/java/com/zc/business/service/impl/DcEventProcessServiceImpl.java
  7. 504
      zc-business/src/main/java/com/zc/business/service/impl/DcEventServiceImpl.java
  8. 82
      zc-business/src/main/java/com/zc/business/utils/diff/AlgorithmEnum.java
  9. 208
      zc-business/src/main/java/com/zc/business/utils/diff/Diff.java
  10. 49
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AbstractObjectAndArray.java
  11. 34
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AbstractPrimitiveAndOther.java
  12. 66
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AlgorithmModule.java
  13. 9
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/Comparator.java
  14. 22
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/AbstractArray.java
  15. 43
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/ArrayComparator.java
  16. 252
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/SimilarArrayComparator.java
  17. 62
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/SimpleArrayComparator.java
  18. 27
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/nulls/DefaultNullComparator.java
  19. 25
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/nulls/NullComparator.java
  20. 128
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/AbstractObject.java
  21. 30
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/LeftJoinObjectComparator.java
  22. 40
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/ObjectComparator.java
  23. 33
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/SimpleObjectComparator.java
  24. 38
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/other/DefaultOtherComparator.java
  25. 24
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/other/OtherComparator.java
  26. 39
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/primitive/DefaultPrimitiveComparator.java
  27. 23
      zc-business/src/main/java/com/zc/business/utils/diff/algorithm/primitive/PrimitiveComparator.java
  28. 20
      zc-business/src/main/java/com/zc/business/utils/diff/model/Constants.java
  29. 61
      zc-business/src/main/java/com/zc/business/utils/diff/model/DiffContext.java
  30. 122
      zc-business/src/main/java/com/zc/business/utils/diff/model/PathModule.java
  31. 71
      zc-business/src/main/java/com/zc/business/utils/diff/model/Result.java
  32. 66
      zc-business/src/main/java/com/zc/business/utils/diff/model/ResultConvertUtil.java
  33. 69
      zc-business/src/main/java/com/zc/business/utils/diff/model/SingleNodeDifference.java
  34. 14
      zc-business/src/main/resources/mapper/business/DcEventMapper.xml
  35. 6
      zc-business/src/main/resources/mapper/business/DcEventProcessMapper.xml

44
zc-business/src/main/java/com/zc/business/controller/DcEventController.java

@ -170,4 +170,48 @@ public class DcEventController extends BaseController
return toAjax(dcEventService.updateDcEventState(id,state));
}
/**
* @Description 查询事件流程状态
*
* @author liuwenge
* @date 2024/4/11 11:19
* @param eventId 事件id
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@ApiOperation("查询事件流程状态")
@GetMapping( "/getProcessNode/{eventId}")
public AjaxResult getProcessNode(@ApiParam(name = "eventId", value = "事件id", required = true) @PathVariable("eventId") String eventId){
return dcEventService.getProcessNode(eventId);
}
/**
* @Description 解除事件
*
* @author liuwenge
* @date 2024/4/11 14:12
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@ApiOperation("解除事件")
@PostMapping("/completeEvent")
public AjaxResult completeEvent(String eventId){
return dcEventService.completeEvent(eventId);
}
/**
* @Description 解除事件
*
* @author liuwenge
* @date 2024/4/11 14:12
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@ApiOperation("无需清障")
@PostMapping("/skipClear")
public AjaxResult skipClear(String eventId){
return dcEventService.skipClear(eventId);
}
}

119
zc-business/src/main/java/com/zc/business/enums/ValueConverter.java

@ -26,6 +26,8 @@ public class ValueConverter {
private static final Map<String, String> eventSourceName = new HashMap<>();
// 事件类型名称
private static final Map<String, String> eventTypeName = new HashMap<>();
// 事件字段
private static final Map<String, String> eventLabel = new HashMap<>();
static {
valueMappingSource.put(1,5);
@ -112,6 +114,115 @@ public class ValueConverter {
eventTypeName.put("9","设施设备隐患");
eventTypeName.put("10","异常天气");
eventTypeName.put("11","其他事件");
eventLabel.put("id","事件编号");
eventLabel.put("deptId","所属部门");
eventLabel.put("stakeMark","桩号");
eventLabel.put("direction","方向");
eventLabel.put("userId","处理人员");
eventLabel.put("startTime","开始时间");
eventLabel.put("endTime","结束时间");
eventLabel.put("estimatedEndTime","预计解除时间");
eventLabel.put("eventLevel","事件等级");
// eventLabel.put("eventType","事件类型");
eventLabel.put("eventCause","事件原因");
eventLabel.put("description","描述");
eventLabel.put("eventState","状态");
eventLabel.put("eventSource","来源");
// eventLabel.put("eventNature","事件性质");
eventLabel.put("eventSourceTips","来源补充说明");
eventLabel.put("occurrenceTime","发生时间");
// eventLabel.put("isPerceived","是否感知事件");
eventLabel.put("lang","影响车道");
eventLabel.put("roadName","高速名称");
eventLabel.put("eventTitle","时间标题");
eventLabel.put("remark","备注");
eventLabel.put("dcEventAbnormalWeather.weatherSituation","天气情况");
eventLabel.put("dcEventAbnormalWeather.emergencyLevel","紧急级别");
eventLabel.put("dcEventAbnormalWeather.endStakeMark","终止桩号");
eventLabel.put("dcEventAbnormalWeather.numericalValue","异常天气数值");
eventLabel.put("dcEventAccident.reporterName","报警人姓名");
eventLabel.put("dcEventAccident.reporterPhoneNumber","报警人电话");
eventLabel.put("dcEventAccident.locationType","地点");
eventLabel.put("dcEventAccident.trafficJam","压车(公里)");
eventLabel.put("dcEventAccident.weatherCondition","天气情况");
eventLabel.put("dcEventAccident.impactLevel","影响");
eventLabel.put("dcEventAccident.isReverseCargo","是否倒货");
eventLabel.put("dcEventAccident.isMaintenance","是否养护事故");
eventLabel.put("dcEventAccident.policeContact","交警电话");
eventLabel.put("dcEventAccident.towingServiceContact","清障电话");
eventLabel.put("dcEventAccident.congestionAhead","前方是否拥堵");
eventLabel.put("dcEventAccident.atIntersection","是否分岔口");
eventLabel.put("dcEventAccident.onCurve","是否处在弯道");
eventLabel.put("dcEventAccident.spillageItem","洒落物名称");
eventLabel.put("dcEventAccident.vehicleOwnerPhone","车主电话");
eventLabel.put("dcEventAccident.smallCar","小型车(辆)");
eventLabel.put("dcEventAccident.trucks","货车(辆)");
eventLabel.put("dcEventAccident.buses","客车(辆)");
eventLabel.put("dcEventAccident.tankers","罐车(辆)");
eventLabel.put("dcEventAccident.minorInjuries","轻伤(人)");
eventLabel.put("dcEventAccident.seriousInjuries","重伤(人)");
eventLabel.put("dcEventAccident.fatalities","死亡(人)");
eventLabel.put("dcEventAccident.isPrivate","私密事件");
eventLabel.put("dcEventAccident.facilityId","设施关联");
eventLabel.put("dcEventAccident.rampId","匝道id");
eventLabel.put("dcEventAccident.location","地点");
eventLabel.put("dcEventConstruction.controlMode","管制方式");
eventLabel.put("dcEventConstruction.locationType","地点类型");
eventLabel.put("dcEventConstruction.specialPlaceDescription","特殊地点描述");
eventLabel.put("dcEventConstruction.specialConstruction","专项施工");
eventLabel.put("dcEventConstruction.otherConstructionName","其他施工名称");
eventLabel.put("dcEventConstruction.constructionMeasurement","施工措施");
eventLabel.put("dcEventConstruction.facilityId","设施id");
eventLabel.put("dcEventConstruction.exitsInlets","出入口");
eventLabel.put("dcEventConstruction.laneOccupancy","占用车道");
eventLabel.put("dcEventConstruction.trafficCondition","通行情况");
eventLabel.put("dcEventConstruction.constructionMethod","施工方式");
eventLabel.put("dcEventConstruction.localRoadName","地方道路名称");
eventLabel.put("dcEventConstruction.endStakeMark","结束桩号");
eventLabel.put("dcEventConstruction.location","地点");
eventLabel.put("dcEventServiceArea.exitsInlets","出入口");
eventLabel.put("dcEventServiceArea.facilityId","服务区");
eventLabel.put("dcEventServiceArea.disableFacility","停用设施");
eventLabel.put("dcEventTrafficCongestion.congestionMileage","拥堵里程(公里)");
eventLabel.put("dcEventTrafficCongestion.maxCongestionMileage","最大拥堵里程(公里)");
eventLabel.put("dcEventTrafficCongestion.congestionCause","拥堵原因");
eventLabel.put("dcEventTrafficCongestion.facilityId","设施id");
eventLabel.put("dcEventTrafficCongestion.rampId","匝道");
eventLabel.put("dcEventTrafficCongestion.location","地点");
eventLabel.put("dcEventTrafficCongestion.detailedReasons","详细原因");
eventLabel.put("dcEventTrafficCongestion.locationType","地点类型");
eventLabel.put("dcEventTrafficCongestion.locationDescription","地点描述");
eventLabel.put("dcEventTrafficCongestion.endStakeMark","终止桩号");
eventLabel.put("dcEventVehicleAccident.reporterName","报警人姓名");
eventLabel.put("dcEventVehicleAccident.reporterPhoneNumber","报警人电话");
eventLabel.put("dcEventVehicleAccident.locationType","地点方式");
eventLabel.put("dcEventVehicleAccident.trafficJam","压车(公里)");
eventLabel.put("dcEventVehicleAccident.weatherCondition","天气情况");
eventLabel.put("dcEventVehicleAccident.congestionAhead","前方是否拥堵");
eventLabel.put("dcEventVehicleAccident.atIntersection","是否分岔口");
eventLabel.put("dcEventVehicleAccident.onCurve","是否处在弯道");
eventLabel.put("dcEventVehicleAccident.smallCar","小型车(辆)");
eventLabel.put("dcEventVehicleAccident.trucks","货车(辆)");
eventLabel.put("dcEventVehicleAccident.buses","客车(辆)");
eventLabel.put("dcEventVehicleAccident.tankers","罐车(辆)");
eventLabel.put("dcEventVehicleAccident.minorInjuries","轻伤(人)");
eventLabel.put("dcEventVehicleAccident.seriousInjuries","重伤(人)");
eventLabel.put("dcEventVehicleAccident.fatalities","死亡(人)");
eventLabel.put("dcEventVehicleAccident.isPrivate","私密事件");
eventLabel.put("dcEventVehicleAccident.facilityId","设施id");
eventLabel.put("dcEventVehicleAccident.rampId","匝道");
eventLabel.put("dcEventVehicleAccident.location","地点");
eventLabel.put("dcEventTrafficControl.controlType","管制分类");
eventLabel.put("dcEventTrafficControl.controlCause","管制原因");
eventLabel.put("dcEventTrafficControl.exitsInlets","出入口");
eventLabel.put("dcEventTrafficControl.facilityId","设施id");
eventLabel.put("dcEventTrafficControl.rampId","匝道");
eventLabel.put("dcEventTrafficControl.causeType","原因类型");
eventLabel.put("dcEventTrafficControl.measure","措施");
eventLabel.put("dcEventTrafficControl.classify","分类");
eventLabel.put("dcEventTrafficControl.limitedType","限制类型");
// eventLabel.put("dcEventTrafficControl.vehicleType","车辆类型");
}
}
@ -133,6 +244,10 @@ public class ValueConverter {
public static Map<String, String> getEventTypeName() {
return ValueMappingHolder.eventTypeName;
}
public static Map<String, String> getEventLabel() {
return ValueMappingHolder.eventLabel;
}
/**
* 根据输入值返回转换后的值
* 如果输入值不在映射中则返回输入值本身
@ -162,6 +277,10 @@ public class ValueConverter {
Map<String, String> mapping = getEventTypeName();
return mapping.getOrDefault(inputValue, inputValue);
}
public static String eventLabel(String inputValue) {
Map<String, String> mapping = getEventLabel();
return mapping.getOrDefault(inputValue, inputValue);
}
//测试
// @Test

21
zc-business/src/main/java/com/zc/business/mapper/DcEventMapper.java

@ -6,6 +6,7 @@ import com.zc.business.domain.DcEvent;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -85,6 +86,26 @@ public interface DcEventMapper extends BaseMapper<DcEvent>
boolean batchInsertDcEvent(List<DcEvent> eventList);
int updateDcEventState(@Param("id") String id,@Param("state") int state);
/**
* @Description 查询事件流程状态
*
* @author liuwenge
* @date 2024/4/11 11:19
* @param eventId 事件id
* @return com.ruoyi.common.core.domain.AjaxResult
*/
List<Map<String,Object>> getProcessNode(@Param("eventId") String eventId);
/**
* @Description 解除事件
*
* @author liuwenge
* @date 2024/4/11 14:15
* @param eventId
* @return boolean
*/
boolean completeEvent(@Param("eventId") String eventId);
}

2
zc-business/src/main/java/com/zc/business/mapper/DcEventProcessMapper.java

@ -73,4 +73,6 @@ public interface DcEventProcessMapper
* @return
*/
List<DcEventProcess> selectDcDispatchByEventId(String id);
int selectFinalNode(String eventId);
}

31
zc-business/src/main/java/com/zc/business/service/IDcEventService.java

@ -1,6 +1,7 @@
package com.zc.business.service;
import com.ruoyi.common.core.domain.AjaxResult;
import com.zc.business.domain.DcEvent;
import java.util.List;
@ -91,4 +92,34 @@ public interface IDcEventService
List<DcEvent> eventPileNumberQueryEvent(Map<String, Object> parameter);
int updateDcEventState(String id, int state);
/**
* @Description 查询事件流程状态
*
* @author liuwenge
* @date 2024/4/11 11:19
* @param eventId 事件id
* @return com.ruoyi.common.core.domain.AjaxResult
*/
AjaxResult getProcessNode(String eventId);
/**
* @Description 解除事件
*
* @author liuwenge
* @date 2024/4/11 14:13
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
AjaxResult completeEvent(String eventId);
/**
* @Description 无需清障
*
* @author liuwenge
* @date 2024/4/11 14:13
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
AjaxResult skipClear(String eventId);
}

10
zc-business/src/main/java/com/zc/business/service/impl/DcEventProcessServiceImpl.java

@ -7,6 +7,7 @@ import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.exception.file.InvalidExtensionException;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.common.utils.file.MimeTypeUtils;
import com.zc.business.domain.DcEvent;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.zc.business.mapper.DcEventProcessMapper;
@ -24,6 +25,8 @@ public class DcEventProcessServiceImpl implements IDcEventProcessService
{
@Autowired
private DcEventProcessMapper dcEventProcessMapper;
@Autowired
private DcEventServiceImpl dcEventService;
/**
* 查询事件处理流程
@ -69,6 +72,13 @@ public class DcEventProcessServiceImpl implements IDcEventProcessService
e.printStackTrace();
}
}
//判断是否最后一个节点
if (dcEventProcess.getProcessType() != null && dcEventProcess.getProcessType() == 1){
int finalNode = dcEventProcessMapper.selectFinalNode(dcEventProcess.getEventId());
if (finalNode == dcEventProcess.getProcessId()){
dcEventService.updateDcEventState(dcEventProcess.getEventId(),2);
}
}
return dcEventProcessMapper.insertDcEventProcess(dcEventProcess);
}

504
zc-business/src/main/java/com/zc/business/service/impl/DcEventServiceImpl.java

@ -1,9 +1,13 @@
package com.zc.business.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.system.service.ISysDeptService;
import com.sun.xml.bind.v2.TODO;
@ -13,10 +17,14 @@ import com.zc.business.mapper.*;
import com.zc.business.service.IDcEventProcessService;
import com.zc.business.service.IDcEventService;
import com.zc.business.service.IMiddleDatabaseService;
import com.zc.business.utils.diff.Diff;
import com.zc.business.utils.diff.model.Result;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -546,10 +554,24 @@ public class DcEventServiceImpl extends ServiceImpl<DcEventMapper, DcEvent> impl
*/
@Override
public int updateDcEvent(DcEvent dcEvent) {
DcEvent oldEvent = selectEventSubclassById(dcEvent.getEventType().intValue(),dcEvent.getId());
dcEvent.setUpdateTime(DateUtils.getNowDate());
int i7 = dcEventMapper.updateDcEvent(dcEvent);
if (i7 > 0) {
String context = comparisonInfo(oldEvent,dcEvent);
//事件处置流程记录
DcEventProcess dcEventProcess = new DcEventProcess();
dcEventProcess.setEventId(dcEvent.getId());
dcEventProcess.setOperationTime(new Date());
dcEventProcess.setOperator(SecurityUtils.getUserId().toString());
dcEventProcess.setSource(1);
dcEventProcess.setContext(context);
dcEventProcessService.insertDcEventProcess(dcEventProcess);
//中间库
MdEvent mdEvent = new MdEvent(dcEvent);
middleDatabaseService.updateMiddleDatabaseEvent(mdEvent);
@ -823,7 +845,29 @@ public class DcEventServiceImpl extends ServiceImpl<DcEventMapper, DcEvent> impl
@Override
public int updateDcEventState(String id, int state) {
return dcEventMapper.updateDcEventState(id,state);
int i = dcEventMapper.updateDcEventState(id,state);
if (i > 0){
DcEvent dcEvent = dcEventMapper.selectDcEventById(id);
//事件处置流程记录
DcEventProcess dcEventProcess = new DcEventProcess();
dcEventProcess.setEventId(dcEvent.getId());
dcEventProcess.setOperationTime(new Date());
dcEventProcess.setOperator(SecurityUtils.getUserId().toString());
dcEventProcess.setSource(1);
List<DcProcessConfig> processConfigList = dcProcessConfigMapper.selectDcProcessConfigByEventType(dcEvent.getEventType().intValue());
if (processConfigList != null && processConfigList.size() > 0){
DcProcessConfig dcProcessConfig = processConfigList.get(0);
dcEventProcess.setProcessType(1);
dcEventProcess.setProcessId(Long.valueOf(dcProcessConfig.getNodeNode()));
dcEventProcess.setProcessName(dcProcessConfig.getProcessNode());
}
String sourceName = ValueConverter.eventSourceName(dcEvent.getEventSource().toString());
String typeName = ValueConverter.eventTypeName(dcEvent.getEventType().toString());
dcEventProcess.setContext("由" + sourceName + "上报了一起" + typeName + "事件");
dcEventProcessService.insertDcEventProcess(dcEventProcess);
}
return i;
}
public static <T> List<T> castList(Object obj, Class<T> clazz) {
@ -836,4 +880,462 @@ public class DcEventServiceImpl extends ServiceImpl<DcEventMapper, DcEvent> impl
}
return null;
}
/**
* @Description 事件信息比对
*
* @author liuwenge
* @date 2024/4/10 16:24
* @param oldEvent 旧数据
* @param newEvent 新数据
* @return java.lang.String
*/
public String comparisonInfo(DcEvent oldEvent,DcEvent newEvent){
String context = "";
if (oldEvent == null || newEvent == null){
return context;
}
Diff diff = new Diff();
List<Result> diffList = diff.diff(JSON.toJSON(oldEvent).toString(),JSON.toJSON(newEvent).toString());
for (Result result : diffList) {
if ("ADD".equals(result.getDiffType()) || "MODIFY".equals(result.getDiffType())){
if ("startTime".equals(result.getRightPath())
|| "endTime".equals(result.getRightPath())
|| "estimatedEndTime".equals(result.getRightPath())
|| "occurrenceTime".equals(result.getRightPath())){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = new Date();
date.setTime(Long.parseLong(result.getRight().toString()));
result.setRight(df.format(date));;
} catch (Exception e){
e.printStackTrace();
}
} else if ("direction".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("上行");
} else if ("2".equals(result.getRight())){
result.setRight("中");
} else if ("3".equals(result.getRight())){
result.setRight("下行");
}
} else if ("eventState".equals(result.getRightPath())){
if ("0".equals(result.getRight())){
result.setRight("待确认");
} else if ("1".equals(result.getRight())){
result.setRight("处理中");
} else if ("2".equals(result.getRight())){
result.setRight("已完成");
}
} else if ("eventSource".equals(result.getRightPath())){
result.setRight(ValueConverter.eventSourceName(result.getRight().toString()));
} else if ("lang".equals(result.getRightPath())){
String langStr = "";
String langArr[] = result.getRight().toString().split(",");
for (String lang : langArr) {
if ("1".equals(lang)){
langStr = langStr + "行1,";
} else if ("2".equals(lang)){
langStr = langStr + "行2,";
} else if ("3".equals(lang)){
langStr = langStr + "行3,";
} else if ("4".equals(lang)){
langStr = langStr + "行4,";
} else if ("0".equals(lang)){
langStr = langStr + "应急车道,";
}
}
if (langStr.length() > 0){
langStr = langStr.substring(0,langStr.length() -1);
}
result.setRight(langStr);
} else if ("dcEventAbnormalWeather.weatherSituation".equals(result.getRightPath())){
if ("1-1".equals(result.getRight())){
result.setRight("雨雾");
} else if ("1-2".equals(result.getRight())){
result.setRight("雨雪");
} else if ("1-3".equals(result.getRight())){
result.setRight("中雨");
} else if ("1-4".equals(result.getRight())){
result.setRight("小雨");
} else if ("1-5".equals(result.getRight())){
result.setRight("大雨");
} else if ("1-6".equals(result.getRight())){
result.setRight("暴雨");
} else if ("2-1".equals(result.getRight())){
result.setRight("小雪");
} else if ("2-2".equals(result.getRight())){
result.setRight("中雪");
} else if ("2-3".equals(result.getRight())){
result.setRight("大雪");
} else if ("2-4".equals(result.getRight())){
result.setRight("暴雪");
} else if ("2-5".equals(result.getRight())){
result.setRight("大暴雪");
} else if ("2-6".equals(result.getRight())){
result.setRight("特大暴雪");
} else if ("3-1".equals(result.getRight())){
result.setRight("轻雾");
} else if ("3-2".equals(result.getRight())){
result.setRight("大雾");
} else if ("3-3".equals(result.getRight())){
result.setRight("浓雾");
} else if ("3-4".equals(result.getRight())){
result.setRight("强浓雾");
} else if ("3-5".equals(result.getRight())){
result.setRight("团雾");
}
} else if ("dcEventAbnormalWeather.emergencyLevel".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("一般");
} else if ("2".equals(result.getRight())){
result.setRight("紧急");
}
} else if ("dcEventAccident.locationType".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("高速主线");
} else if ("2".equals(result.getRight())){
result.setRight("服务区");
} else if ("3".equals(result.getRight())){
result.setRight("立交桥");
} else if ("4".equals(result.getRight())){
result.setRight("收费站");
}
} else if ("dcEventAccident.weatherCondition".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("晴");
} else if ("2".equals(result.getRight())){
result.setRight("雨");
} else if ("3".equals(result.getRight())){
result.setRight("雪");
} else if ("4".equals(result.getRight())){
result.setRight("雾");
} else if ("5".equals(result.getRight())){
result.setRight("其他");
}
} else if ("dcEventAccident.impactLevel".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("无");
} else if ("2".equals(result.getRight())){
result.setRight("危化品泄漏");
} else if ("3".equals(result.getRight())){
result.setRight("整车自燃");
} else if ("4".equals(result.getRight())){
result.setRight("车辆复燃");
} else if ("5".equals(result.getRight())){
result.setRight("散装人工倒货");
}
} else if ("dcEventAccident.isReverseCargo".equals(result.getRightPath())
|| "dcEventAccident.isMaintenance".equals(result.getRightPath())
|| "dcEventAccident.congestionAhead".equals(result.getRightPath())
|| "dcEventAccident.atIntersection".equals(result.getRightPath())
|| "dcEventAccident.onCurve".equals(result.getRightPath())
|| "dcEventAccident.isPrivate".equals(result.getRightPath())
|| "dcEventVehicleAccident.congestionAhead".equals(result.getRightPath())
|| "dcEventVehicleAccident.atIntersection".equals(result.getRightPath())
|| "dcEventVehicleAccident.onCurve".equals(result.getRightPath())
|| "dcEventVehicleAccident.isPrivate".equals(result.getRightPath())){
if ("0".equals(result.getRight())){
result.setRight("否");
} else if ("1".equals(result.getRight())){
result.setRight("是");
}
} else if ("dcEventConstruction.controlMode".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("封闭");
} else if ("2".equals(result.getRight())){
result.setRight("不封闭");
}
} else if ("dcEventConstruction.locationType".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("单点");
} else if ("2".equals(result.getRight())){
result.setRight("多点");
}
} else if ("dcEventConstruction.specialConstruction".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("专项工程施工");
} else if ("2".equals(result.getRight())){
result.setRight("改扩建专项工程施工");
} else if ("3".equals(result.getRight())){
result.setRight("桥梁专项工程施工");
} else if ("4".equals(result.getRight())){
result.setRight("其他专项工程施工");
}
} else if ("dcEventConstruction.constructionMeasurement".equals(result.getRightPath())){
if ("0".equals(result.getRight())){
result.setRight("无");
} else if ("1".equals(result.getRight())){
result.setRight("并道行驶");
} else if ("2".equals(result.getRight())){
result.setRight("临时保通");
} else if ("3".equals(result.getRight())){
result.setRight("借路侧服务区通行");
}
} else if ("dcEventConstruction.exitsInlets".equals(result.getRightPath())
|| "dcEventServiceArea.exitsInlets".equals(result.getRightPath())
|| "dcEventTrafficControl.exitsInlets".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("出口");
} else if ("2".equals(result.getRight())){
result.setRight("入口");
}
} else if ("dcEventConstruction.trafficCondition".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("通行正常");
} else if ("2".equals(result.getRight())){
result.setRight("通行受阻");
}
} else if ("dcEventServiceArea.disableFacility".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("卫生间");
} else if ("2".equals(result.getRight())){
result.setRight("餐厅");
} else if ("3".equals(result.getRight())){
result.setRight("停车场");
} else if ("4".equals(result.getRight())){
result.setRight("加油站");
} else if ("5".equals(result.getRight())){
result.setRight("充电桩");
}
} else if ("dcEventTrafficCongestion.congestionCause".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("车流量大");
} else if ("2".equals(result.getRight())){
result.setRight("交通事故");
} else if ("3".equals(result.getRight())){
result.setRight("恶劣天气");
} else if ("4".equals(result.getRight())){
result.setRight("施工");
} else if ("5".equals(result.getRight())){
result.setRight("其他");
}
} else if ("dcEventTrafficCongestion.location".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("入口");
} else if ("2".equals(result.getRight())){
result.setRight("出口");
} else if ("3".equals(result.getRight())){
result.setRight("入口内广场");
} else if ("4".equals(result.getRight())){
result.setRight("出口内广场");
} else if ("5".equals(result.getRight())){
result.setRight("外广场");
} else if ("6".equals(result.getRight())){
result.setRight("入口车道");
} else if ("7".equals(result.getRight())){
result.setRight("出口车道");
} else if ("8".equals(result.getRight())){
result.setRight("入口匝道");
} else if ("9".equals(result.getRight())){
result.setRight("出口匝道");
}
} else if ("dcEventTrafficCongestion.locationType".equals(result.getRightPath())
|| "dcEventVehicleAccident.locationType".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("高速主线");
} else if ("2".equals(result.getRight())){
result.setRight("服务区");
} else if ("3".equals(result.getRight())){
result.setRight("立交桥");
} else if ("4".equals(result.getRight())){
result.setRight("收费站");
}
} else if ("dcEventTrafficCongestion.weatherCondition".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("晴");
} else if ("2".equals(result.getRight())){
result.setRight("雨");
} else if ("3".equals(result.getRight())){
result.setRight("雪");
} else if ("4".equals(result.getRight())){
result.setRight("雾");
} else if ("5".equals(result.getRight())){
result.setRight("其他");
}
} else if ("dcEventTrafficControl.controlType".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("封闭");
} else if ("2".equals(result.getRight())){
result.setRight("限行");
}
} else if ("dcEventTrafficControl.controlCause".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("车流量大");
} else if ("2".equals(result.getRight())){
result.setRight("交通事故");
} else if ("3".equals(result.getRight())){
result.setRight("恶劣天气");
} else if ("4".equals(result.getRight())){
result.setRight("施工");
} else if ("5".equals(result.getRight())){
result.setRight("警备任务");
} else if ("6".equals(result.getRight())){
result.setRight("其他");
}
} else if ("dcEventTrafficControl.causeType".equals(result.getRightPath())){
if ("3-1".equals(result.getRight())){
result.setRight("雨");
} else if ("3-2".equals(result.getRight())){
result.setRight("雪");
} else if ("3-3".equals(result.getRight())){
result.setRight("雾");
} else if ("3-4".equals(result.getRight())){
result.setRight("道路积水");
} else if ("3-5".equals(result.getRight())){
result.setRight("道路湿滑");
} else if ("3-6".equals(result.getRight())){
result.setRight("道路结冰");
} else if ("3-7".equals(result.getRight())){
result.setRight("沙尘暴");
} else if ("4-1".equals(result.getRight())){
result.setRight("专项工程施工");
} else if ("4-2".equals(result.getRight())){
result.setRight("改扩建工程施工");
} else if ("4-3".equals(result.getRight())){
result.setRight("其他施工");
}
} else if ("dcEventTrafficControl.measure".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("临时关闭");
} else if ("2".equals(result.getRight())){
result.setRight("限行车辆");
} else if ("3".equals(result.getRight())){
result.setRight("限行车道");
} else if ("4".equals(result.getRight())){
result.setRight("限行车道且限行车辆");
} else if ("5".equals(result.getRight())){
result.setRight("间隔放行");
} else if ("6".equals(result.getRight())){
result.setRight("并道行驶");
} else if ("7".equals(result.getRight())){
result.setRight("限速");
}
} else if ("dcEventTrafficControl.classify".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("主线关闭");
} else if ("2".equals(result.getRight())){
result.setRight("主线限行");
} else if ("3".equals(result.getRight())){
result.setRight("主线间隔放行");
} else if ("4".equals(result.getRight())){
result.setRight("主线并道");
} else if ("5".equals(result.getRight())){
result.setRight("主线限速");
}
} else if ("dcEventTrafficControl.limitedType".equals(result.getRightPath())){
if ("1".equals(result.getRight())){
result.setRight("只允许");
} else if ("2".equals(result.getRight())){
result.setRight("禁止");
}
}
String label = ValueConverter.eventLabel(result.getRightPath());
context = context + label + "修改为:" + result.getRight() + ",";
}
}
if (context.length() > 0){
context = context.substring(0,context.length() -1);
}
return context;
}
/**
* @Description 查询事件流程状态
*
* @author liuwenge
* @date 2024/4/11 11:19
* @param eventId 事件id
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@Override
public AjaxResult getProcessNode(String eventId){
List<Map<String,Object>> processNode = dcEventMapper.getProcessNode(eventId);
return AjaxResult.success(processNode);
}
/**
* @Description 解除事件
*
* @author liuwenge
* @date 2024/4/11 14:13
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@Override
public AjaxResult completeEvent(String eventId){
boolean flag = dcEventMapper.completeEvent(eventId);
if (flag){
DcEvent dcEvent = dcEventMapper.selectDcEventById(eventId);
String datePoor = getDatePoor(dcEvent.getEndTime(),dcEvent.getStartTime());
//事件处置流程记录
DcEventProcess dcEventProcess = new DcEventProcess();
dcEventProcess.setEventId(eventId);
dcEventProcess.setOperationTime(new Date());
dcEventProcess.setOperator(SecurityUtils.getUserId().toString());
dcEventProcess.setSource(1);
dcEventProcess.setContext("事件解除,处置完毕,处置时长:" + datePoor);
dcEventProcessService.insertDcEventProcess(dcEventProcess);
return AjaxResult.success("解除事件成功");
}
return AjaxResult.error("解除事件失败");
}
/**
* @Description 无需清障
*
* @author liuwenge
* @date 2024/4/11 14:13
* @param eventId
* @return com.ruoyi.common.core.domain.AjaxResult
*/
@Override
public AjaxResult skipClear(String eventId){
//事件处置流程记录
DcEventProcess dcEventProcess = new DcEventProcess();
dcEventProcess.setEventId(eventId);
dcEventProcess.setOperationTime(new Date());
dcEventProcess.setOperator(SecurityUtils.getUserId().toString());
dcEventProcess.setSource(1);
dcEventProcess.setProcessType(1);
dcEventProcess.setProcessId(6L);
dcEventProcess.setProcessName("清障结束");
dcEventProcess.setContext("选择不需要清障");
dcEventProcessService.insertDcEventProcess(dcEventProcess);
return AjaxResult.success("无需清障成功");
}
//时间比对
public static String getDatePoor(Date endDate, Date nowDate) {
long nd = 1000 * 24 * 60 * 60;
long nh = 1000 * 60 * 60;
long nm = 1000 * 60;
long ns = 1000;
// 获得两个时间的毫秒时间差异
long diff = endDate.getTime() - nowDate.getTime();
// 计算差多少天
long day = diff / nd;
// 计算差多少小时
long hour = diff % nd / nh;
// 计算差多少分钟
long min = diff % nd % nh / nm;
// 计算差多少秒//输出结果
long sec = diff % nd % nh % nm / ns;
return day + "天" + hour + "小时" + min + "分钟" + sec + "秒";
}
}

82
zc-business/src/main/java/com/zc/business/utils/diff/AlgorithmEnum.java

@ -0,0 +1,82 @@
package com.zc.business.utils.diff;
import com.zc.business.utils.diff.algorithm.AlgorithmModule;
import com.zc.business.utils.diff.algorithm.array.SimilarArrayComparator;
import com.zc.business.utils.diff.algorithm.array.SimpleArrayComparator;
import com.zc.business.utils.diff.algorithm.nulls.DefaultNullComparator;
import com.zc.business.utils.diff.algorithm.object.LeftJoinObjectComparator;
import com.zc.business.utils.diff.algorithm.object.SimpleObjectComparator;
import com.zc.business.utils.diff.algorithm.other.DefaultOtherComparator;
import com.zc.business.utils.diff.algorithm.primitive.DefaultPrimitiveComparator;
/**
* 算法模型枚举类提供一些默认实现的算法模型
* @Author JingWei
* @create 2022/3/2
*/
public enum AlgorithmEnum {
/**
* 默认的比较算法模型
*/
DEFAULT(defaultAlgorithmModule()),
/**
* 数组比较采用Simple对象比较采用Simple
*/
SIMPLE_ARRAY_AND_SIMPLE_OBJECT(simpleAndSimpleAlgorithmModule()),
/**
* 数组比较采用Simple对象比较采用LeftJoin
*/
SIMPLE_ARRAY_AND_LEFTJOIN_OBJECT(simpleAndLeftJoinAlgorithmModule()),
/**
* 数组比较采用Similar对象比较采用LeftJoin
*/
SIMLAR_ARRAY_AND_LEFTJOIN_OBJECT(similarAndLeftJoinAlgorithmModule()),
/**
* 数组比较采用Similar对象比较采用Simple
*/
MOST_COMMONLY_USED(similarAndSimpleAlgorithmModule());
final private AlgorithmModule algorithmModule;
AlgorithmEnum(AlgorithmModule algorithmModule) {
this.algorithmModule = algorithmModule;
}
public AlgorithmModule getAlgorithmModule() {
return algorithmModule;
}
private static AlgorithmModule defaultAlgorithmModule() {
return new AlgorithmModule(new SimpleObjectComparator(), new SimilarArrayComparator(),
new DefaultPrimitiveComparator(), new DefaultNullComparator(), new DefaultOtherComparator());
}
private static AlgorithmModule simpleAndSimpleAlgorithmModule() {
return new AlgorithmModule(new SimpleObjectComparator(), new SimpleArrayComparator(),
new DefaultPrimitiveComparator(), new DefaultNullComparator(), new DefaultOtherComparator());
}
private static AlgorithmModule simpleAndLeftJoinAlgorithmModule() {
return new AlgorithmModule(new LeftJoinObjectComparator(), new SimpleArrayComparator(),
new DefaultPrimitiveComparator(), new DefaultNullComparator(), new DefaultOtherComparator());
}
private static AlgorithmModule similarAndLeftJoinAlgorithmModule() {
return new AlgorithmModule(new LeftJoinObjectComparator(), new SimilarArrayComparator(),
new DefaultPrimitiveComparator(), new DefaultNullComparator(), new DefaultOtherComparator());
}
private static AlgorithmModule similarAndSimpleAlgorithmModule() {
return new AlgorithmModule(new SimpleObjectComparator(), new SimilarArrayComparator(),
new DefaultPrimitiveComparator(), new DefaultNullComparator(), new DefaultOtherComparator());
}
}

208
zc-business/src/main/java/com/zc/business/utils/diff/Diff.java

@ -0,0 +1,208 @@
package com.zc.business.utils.diff;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.zc.business.utils.diff.algorithm.AlgorithmModule;
import com.zc.business.utils.diff.algorithm.array.ArrayComparator;
import com.zc.business.utils.diff.algorithm.array.SimilarArrayComparator;
import com.zc.business.utils.diff.algorithm.nulls.DefaultNullComparator;
import com.zc.business.utils.diff.algorithm.nulls.NullComparator;
import com.zc.business.utils.diff.algorithm.object.ObjectComparator;
import com.zc.business.utils.diff.algorithm.object.SimpleObjectComparator;
import com.zc.business.utils.diff.algorithm.other.DefaultOtherComparator;
import com.zc.business.utils.diff.algorithm.other.OtherComparator;
import com.zc.business.utils.diff.algorithm.primitive.DefaultPrimitiveComparator;
import com.zc.business.utils.diff.algorithm.primitive.PrimitiveComparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import com.zc.business.utils.diff.model.Result;
import com.zc.business.utils.diff.model.ResultConvertUtil;
import java.util.List;
/**
* DIFF入口用于比较两个Json字符串
* @Author JingWei
* @create 2022/2/25
*/
public class Diff {
/**
* 算法模型根据传入的算法模型使用该算法模型进行diff比较
*/
private AlgorithmEnum algorithmEnum;
/**
* 特殊路径集合当前路径符合特殊路径且特殊路径下比较结果相同会在返回结果中做额外标识标识
*/
private List<String> specialPath;
/**
* 噪音字段集合如果当前路径符合噪音字段路径则不会比较
*/
private List<String> noisePahList;
/**
* 以下为5种可以自定义的比较器条件是algorithmEnum为空如果algorithmEnum有值直接使用algorithmEnum对应算法模型比较器不生效
*/
private ObjectComparator objectComparator;
private ArrayComparator arrayComparator;
private PrimitiveComparator primitiveComparator;
private NullComparator nullComparator;
private OtherComparator otherComparator;
/**
* @param a 要比较的第一个JsonElement
* @param b 要比较的第二个JsonElement
* @return 用来展示的diff结果
*/
public List<Result> diffElement(JsonElement a, JsonElement b) {
DiffContext diffContext;
//用噪音路径和自定义路径构造路径模型
PathModule pathModule = new PathModule(noisePahList, specialPath);
//如果有算法模型直接使用算法模型
if(algorithmEnum != null){
diffContext = algorithmEnum.getAlgorithmModule().diffElement(a, b, pathModule);
}//如果也没有比较器,直接用默认算法模型
else if(objectComparator == null && arrayComparator == null && primitiveComparator == null && nullComparator == null && otherComparator == null){
diffContext = AlgorithmEnum.DEFAULT.getAlgorithmModule().diffElement(a, b, pathModule);
}//如果有比较器,为空的比较器用默认替换,然后构造算法模型,
else {
constrcutDefaultComparator();
diffContext = new AlgorithmModule(objectComparator, arrayComparator, primitiveComparator, nullComparator, otherComparator).diffElement(a, b, pathModule);
}
return ResultConvertUtil.constructResult(diffContext);
}
/**
* @param strA 要比较的第一个字符串
* @param strB 要比较的第二个字符串
* @return 用来展示的diff结果
*/
public List<Result> diff(String strA, String strB) {
return diffElement(new JsonParser().parse(strA), new JsonParser().parse(strB));
}
public Diff() {
}
/**
* 没有初始的比较器替换成默认的
*/
private void constrcutDefaultComparator() {
//如果没有初始化算法,则采用默认的算法。
if(objectComparator == null){
objectComparator = defaultObjectComparator();
}
if(arrayComparator == null){
arrayComparator = defaultArrayComparator();
}
if(primitiveComparator == null){
primitiveComparator = defaultPrimitiveComparator();
}
if(nullComparator == null){
nullComparator = defaultNullComparator();
}
if(otherComparator == null){
otherComparator = defaultOtherComparator();
}
}
private ObjectComparator defaultObjectComparator() {
return new SimpleObjectComparator();
}
private ArrayComparator defaultArrayComparator() {
return new SimilarArrayComparator();
}
private PrimitiveComparator defaultPrimitiveComparator() {
return new DefaultPrimitiveComparator();
}
private NullComparator defaultNullComparator() {
return new DefaultNullComparator();
}
private OtherComparator defaultOtherComparator() {
return new DefaultOtherComparator();
}
/**
* 选择算法模型
* @param algorithmEnum 算法模型枚举类
* @return 对象本身
*/
public Diff withAlgorithmEnum(AlgorithmEnum algorithmEnum){
this.algorithmEnum = algorithmEnum;
return this;
}
/**
* 设置自定义路径
* @param specialPath 自定义路径列表
* @return 对象本身
*/
public Diff withSpecialPath(List<String> specialPath){
this.specialPath = specialPath;
return this;
}
/**
* 设置噪音路径
* @param noisePahList 噪音路径列表
* @return 对象本身
*/
public Diff withNoisePahList(List<String> noisePahList){
this.noisePahList = noisePahList;
return this;
}
/**
* 自定义对象比较器
* @param objectComparator 对象比较器
* @return 对象本身
*/
public Diff withObjectComparator(ObjectComparator objectComparator) {
this.objectComparator = objectComparator;
return this;
}
/**
* 自定义数组比较器
* @param arrayComparator 数组比较器
* @return 对象本身
*/
public Diff withArrayComparator(ArrayComparator arrayComparator) {
this.arrayComparator = arrayComparator;
return this;
}
/**
* 自定义基本类型比较器
* @param primitiveComparator 基本类型比较器
* @return 对象本身
*/
public Diff withPrimitiveAlgorithm(PrimitiveComparator primitiveComparator) {
this.primitiveComparator = primitiveComparator;
return this;
}
/**
* 自定义空类型比较器
* @param nullComparator 空类型比较器
* @return 对象本身
*/
public Diff withNullComparator(NullComparator nullComparator) {
this.nullComparator = nullComparator;
return this;
}
/**
* 自定义其他类型比较器
* @param otherComparator 其他类型比较器
* @return 对象本身
*/
public Diff withOtheComparator(OtherComparator otherComparator) {
this.otherComparator = otherComparator;
return this;
}
}

49
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AbstractObjectAndArray.java

@ -0,0 +1,49 @@
package com.zc.business.utils.diff.algorithm;
import com.google.gson.JsonElement;
import com.zc.business.utils.diff.model.Constants;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import com.zc.business.utils.diff.model.SingleNodeDifference;
/**
* 数组和对象比较的公有方法抽象类
* @Author JingWei
* @create 2022/3/1
*/
public abstract class AbstractObjectAndArray {
protected AlgorithmModule algorithmModule;
/**
* diff算法比较核心方法比较2个JsonElement的入口
* @param a 比较的第一个JsonElement
* @param b 比较的第二个JsonElement
* @param pathModule 路径模型
* @return 不同的比较结果
*/
public DiffContext diffElement(JsonElement a, JsonElement b, PathModule pathModule) {
return algorithmModule.diffElement(a, b, pathModule);
}
/**
* 构造算法模型,比如使用对象和数组类型算法比较时内部会用到其他类型的算法
* @param algorithmModule 算法模型
*/
public void constructAlgorithmModule(AlgorithmModule algorithmModule) {
this.algorithmModule = algorithmModule;
}
/**
* 如果下层diff结果不同会把下层diff结果加入到上层diff结果中去
* @param parentResult 上层结果
* @param childResult 下层结果
*/
public void parentContextAddChildContext(DiffContext parentResult, DiffContext childResult) {
if(childResult.isSame() == Constants.DIFFERENT) {
for (SingleNodeDifference singleNodeDifference : childResult.getDiffResultModels()) {
parentResult.getDiffResultModels().add(singleNodeDifference);
}
parentResult.setSame(false);
}
}
}

34
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AbstractPrimitiveAndOther.java

@ -0,0 +1,34 @@
package com.zc.business.utils.diff.algorithm;
import com.google.gson.JsonElement;
/**
* 基本类型和其它类型比较的公有方法抽象类
* @Author JingWei
* @create 2022/1/11
*/
public abstract class AbstractPrimitiveAndOther {
/**
* 将比较的元素转换成String类型方便结果展示
* @param element 元素
* @return 元素转换成的字符串
*/
protected static String jsonElement2Str(JsonElement element){
//该对象不存在的情况
if(element == null){
return null;
} else if (element.isJsonObject()) {
return "{省略内部字段}";
} else if (element.isJsonArray()) {
return "[省略内部元素]";
} else if (element.isJsonPrimitive()) {
return element.getAsJsonPrimitive().getAsString();
} else if (element.isJsonNull()) {
return "null";
}else{
throw new RuntimeException("异常");
}
}
}

66
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/AlgorithmModule.java

@ -0,0 +1,66 @@
package com.zc.business.utils.diff.algorithm;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.zc.business.utils.diff.algorithm.array.ArrayComparator;
import com.zc.business.utils.diff.algorithm.nulls.NullComparator;
import com.zc.business.utils.diff.algorithm.object.ObjectComparator;
import com.zc.business.utils.diff.algorithm.other.OtherComparator;
import com.zc.business.utils.diff.algorithm.primitive.PrimitiveComparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 算法模型
* 算法模型包含5种比较器对象数组基本类型空类型其他类型比较器
* 当2个JsonElement的子类同时为对象数组基本类型空类型使用前4种比较器当2个JsonElement的子类类型不相同时使用其它类型比较器
* @Author JingWei
* @create 2022/1/13
*/
public class AlgorithmModule{
protected ObjectComparator objectAlgorithm;
protected ArrayComparator arrayAlgorithm;
protected PrimitiveComparator primitiveComparator;
protected NullComparator nullComparator;
protected OtherComparator otherComparator;
public AlgorithmModule(ObjectComparator objectAlgorithm, ArrayComparator arrayAlgorithm,
PrimitiveComparator primitiveComparator, NullComparator nullComparator, OtherComparator otherComparator) {
this.arrayAlgorithm = arrayAlgorithm;
this.objectAlgorithm = objectAlgorithm;
this.primitiveComparator = primitiveComparator;
this.nullComparator = nullComparator;
this.otherComparator = otherComparator;
objectAlgorithm.constructAlgorithmModule(this);
arrayAlgorithm.constructAlgorithmModule(this);
}
/**
* 判断要比较的两个JsonElement的类型并根据类型调用对应的算法进行比较
* @param a 要比较的第一个元素
* @param b 要比较的第二个元素
* @param pathModule 路径模型
* @return 返回比较结果
*/
public DiffContext diffElement(JsonElement a, JsonElement b, PathModule pathModule) {
if (a instanceof JsonObject && b instanceof JsonObject) {
return objectAlgorithm.diff( (JsonObject) a, (JsonObject) b, pathModule);
} else if (a instanceof JsonArray && b instanceof JsonArray) {
return arrayAlgorithm.diffArray((JsonArray) a, (JsonArray) b, pathModule);
} else if (a instanceof JsonPrimitive && b instanceof JsonPrimitive) {
return primitiveComparator.diff((JsonPrimitive) a, (JsonPrimitive) b, pathModule);
} else if (a instanceof JsonNull && b instanceof JsonNull) {
return nullComparator.diff((JsonNull) a, (JsonNull) b, pathModule);
} else {
return otherComparator.diff(a, b, pathModule);
}
}
public ArrayComparator getArrayAlgorithm() {
return arrayAlgorithm;
}
}

9
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/Comparator.java

@ -0,0 +1,9 @@
package com.zc.business.utils.diff.algorithm;
/**
* 比较器最顶层的接口逻辑意义
* @Author JingWei
* @create 2022/3/2
*/
public interface Comparator {
}

22
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/AbstractArray.java

@ -0,0 +1,22 @@
package com.zc.business.utils.diff.algorithm.array;
import com.zc.business.utils.diff.algorithm.AbstractObjectAndArray;
/**
* 数组比较的公有方法抽象类
* @Author JingWei
* @create 2022/3/1
*/
public abstract class AbstractArray extends AbstractObjectAndArray implements ArrayComparator {
/**
* 数组索引号加一个中括号表示数组路径
* @param i 数组元素的索引号
* @return 索引号增加中括号
*/
protected String constructArrayPath(Integer i){
if(i == null || i < 0 ){
throw new RuntimeException("数组索引号入参为空或者为负。 入参:" + i);
}
return "[" + i + "]";
}
}

43
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/ArrayComparator.java

@ -0,0 +1,43 @@
package com.zc.business.utils.diff.algorithm.array;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.zc.business.utils.diff.algorithm.AlgorithmModule;
import com.zc.business.utils.diff.algorithm.Comparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 数组类型比较器接口用于2个JsonElement均为数组时对2个元素进行比较
* @Author JingWei
* @create 2022/2/23
*/
public interface ArrayComparator extends Comparator {
/**
* 对两个JsonArray进行比较的方法
* @param a 要比较的第一个JsonArray
* @param b 要比较的第二个JsonArray
* @param pathModule 路径模型
* @return 返回不相等的结果
*/
DiffContext diffArray(JsonArray a, JsonArray b, PathModule pathModule) ;
/**
* 对象内部包含其他非数组类型对这些类型比较需要使用JsonElement比较方法
* @param a 要比较的第一个JsonElement
* @param b 要比较的第一个JsonElement
* @param pathModule 路径模型
* @return 返回不相等的结果
*/
DiffContext diffElement(JsonElement a, JsonElement b, PathModule pathModule);
/**
* 构造算法模型数组中元素比较需要使用到其他非数组算法
* @param algorithmModule 算法模型包含对象数组基本类型空类型其他类型算法
*/
void constructAlgorithmModule(AlgorithmModule algorithmModule);
}

252
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/SimilarArrayComparator.java

@ -0,0 +1,252 @@
package com.zc.business.utils.diff.algorithm.array;
import com.google.gson.JsonArray;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import com.zc.business.utils.diff.model.SingleNodeDifference;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
/**
* 相似度数组算法比较器:当数组进行比较找不到相等元素时通过算法优先找最接近的元素进行匹配
*
* 举例
*"[{\"a\":7,\"b\":5,\"c\":6},{\"a\":6,\"b\":2,\"c\":3}]"
*"[{\"a\":1,\"b\":2,\"c\":3},{\"a\":4,\"b\":5,\"c\":6},{\"a\":7,\"b\":8,\"c\":9}]"比较
* 数组一中第一个元素依次和数组二中元素比较分别有3组不同1组不同2组不同
* 数组一中第二个元素依次和数组二中元素比较分别有1组不同3组不同3组不同
* 得到相似矩阵如下
* 3 1 2
* 1 3 3
* 遍历矩阵所有元素找到值最小的元素并且行和列的其他元素不能再被使用行和列即为要比较的2个元素在各自数组中的索引号
* 第一次找到1第二次找到另外一个1.
* 遍历矩阵中未使用所有列列索引号为多余的元素在数组中的位置
* 只有第三列可以使用 第二组中第3个元素为新增元素
*
* @Author JingWei
* @create 2022/2/24
*/
public class SimilarArrayComparator extends AbstractArray {
/**
* USEABLE表示当前位置可以使用
*/
private final boolean USEABLE = false;
/**
* USED表示当前位置已经被使用过
*/
private final boolean USED = true;
/**
* @param a 要比较的第一个数组
* @param b 要比较的第二个数组
* @param pathModule 路径模型
* @return 返回不相等的结果
*/
@Override
public DiffContext diffArray(JsonArray a, JsonArray b, PathModule pathModule) {
DiffContext diffContext;
//a数组长度小于等于b,直接使用diff数组比较算法
if(a.size() <= b.size()){
diffContext = diff(a, b, pathModule);
}
//当a数组长度大于b时,需要交换pathModule中a和b路径, 并交换数组a和b,再使用diff数组比较算法
else {
exchangeLeftAndRightPath(pathModule);
diffContext = diff(b, a, pathModule);
exchangeLeftAndRightPath(pathModule);
exchangeResult(diffContext);
}
return diffContext;
}
/**
* 交换返回结果中每一个路径和结果
* @param diffContext 返回结果
*/
private void exchangeResult(DiffContext diffContext) {
List<SingleNodeDifference> singleNodeDifferences = diffContext.getDiffResultModels();
for(SingleNodeDifference singleNodeDifference : singleNodeDifferences){
exchangePathAndResult(singleNodeDifference);
}
}
/**
* 交换返回结果中的路径和结果
* @param singleNodeDifference 返回结果
*/
private void exchangePathAndResult(SingleNodeDifference singleNodeDifference) {
String tempStringA = singleNodeDifference.getLeftPath();
Object tempLeft = singleNodeDifference.getLeft();
singleNodeDifference.setLeftPath(singleNodeDifference.getRightPath());
singleNodeDifference.setRightPath(tempStringA);
singleNodeDifference.setLeft(singleNodeDifference.getRight());
singleNodeDifference.setRight(tempLeft);
}
/**
* 将路径模型中a和b的路径交换
* @param pathModule 路径模型
*/
private void exchangeLeftAndRightPath(PathModule pathModule) {
LinkedList<String> tempA = pathModule.getLeftPath();
pathModule.setLeftPath(pathModule.getRightPath());
pathModule.setRightPath(tempA);
}
/**
* 数组比较核心算法支持数组a长度小于b长度时使用
*/
DiffContext diff(JsonArray a, JsonArray b, PathModule pathModule ) {
int rowlength = a.size();
int linelength = b.size();
//a数组中m个元素,与b数组中n个元素比较,共比较m*n次,所有比较结果会得组成一个矩阵,矩阵中的数字用来存储比较结果。
int [][] similarMatrix = new int[rowlength][linelength];
//创建一个行和列数组 用来判断当前行和列是否被使用过
boolean []row = new boolean[rowlength];
boolean []line = new boolean[linelength];
for (int i = 0; i < rowlength; i++) {
pathModule.addLeftPath(constructArrayPath(i));
//a数组中m个元素,与b数组中n个元素比较,比较结果生成一个m*n的矩阵
constructSimilarMatrix(a, b, i, pathModule, similarMatrix, row, line);
pathModule.removeLastLeftPath();
}
return obtainDiffResult(a, b, pathModule, row, line, similarMatrix);
}
/**
* 通过相似度矩阵获取比较结果 第一步在矩阵找到最小的数字即找到最接近的几对结果 第二步找剩余未使用的列数即多余的元素
*/
private DiffContext obtainDiffResult(JsonArray a, JsonArray b, PathModule pathModule, boolean[] row, boolean[] line, int[][] similarMatrix) {
DiffContext arrayDiffContext = new DiffContext();
//找到a和b都有的结果,并且是最接近的几对结果
obtainModifyDiffResult(a,b,pathModule,row,line,similarMatrix, arrayDiffContext);
//a没有b有的结果,即新增的结果
obtainAddDiffResult(b,pathModule,line, arrayDiffContext);
return arrayDiffContext;
}
/**
* 得到新增的结果由于b数组长度大于a会有几个元素多余在选出a和b最接近的几对元素后剩下的几个元素被认为是新增的
*/
private void obtainAddDiffResult(JsonArray b, PathModule pathModule, boolean[] line, DiffContext arrayDiffContext) {
for (int j = 0; j < line.length; j++) {
if (line[j] == USED) {
continue;
}
DiffContext addOrDeleteDiffContext = constructAddContext(b, j, pathModule);
parentContextAddChildContext(arrayDiffContext, addOrDeleteDiffContext);
}
}
/**
* 从m*n的矩阵中选出最接近的几组结果矩阵中的数字越小说明2个元素比较时结果相差越少
*/
private void obtainModifyDiffResult(JsonArray a, JsonArray b, PathModule pathModule, boolean[] row, boolean[] line, int[][] similarMatrix, DiffContext arrayDiffContext) {
int counts = 0;
//找到还未使用行的数量(行数小于列数)
for (boolean value : row) {
if (Objects.equals(USEABLE, value)) {
counts++;
}
}
//不同结果对数等于未使用的行数
for (int n = 0; n < counts; n++) {
int bestLineIndex = 0;
int bestRowIndex = 0;
int minDiffPair = Integer.MAX_VALUE;
//遍历矩阵中所有元素,找最小的数字,矩阵中的数字越小,说明2个元素比较时结果相差越少
for (int i = 0; i < row.length; i++) {
for (int j = 0; j < line.length; j++) {
//如果行或列被使用,跳过该行
if (row[i] == USED || line[j] == USED) {
continue;
}
//如果当前元素数字更小,那么把当前行和列保存下来,数字更新为当前最优结果
if (similarMatrix[i][j] < minDiffPair) {
bestRowIndex = i;
bestLineIndex = j;
minDiffPair = similarMatrix[i][j];
}
}
}
//将找到的最优结果添加到返回结果中
DiffContext modifyDiffContext = constructModifyContext(a, b, bestRowIndex, bestLineIndex, pathModule);
row[bestRowIndex] = USED;
line[bestLineIndex] = USED;
parentContextAddChildContext(arrayDiffContext, modifyDiffContext);
}
}
/**
* 此时a数组没有该元素b数组有元素结果为新增
* @param b 数组
* @param index 索引号
* @param pathModule 路径模型
* @return 生成的不同结果
*/
private DiffContext constructAddContext(JsonArray b, int index, PathModule pathModule) {
pathModule.addAllpath(constructArrayPath(index));
DiffContext diffContext = diffElement(null, b.get(index), pathModule);
pathModule.removeAllLastPath();
return diffContext;
}
/**
* 返回两个数组对应索引号元素比较结果
* @param a 数组a
* @param b 数组b
* @param i 数组a中元素的索引号
* @param bestLineIndex 数组b中元素的索引号即找到的和a中元素接接近的元素索引号
* @param pathModule 路径模型
* @return 返回不同的结果
*/
private DiffContext constructModifyContext(JsonArray a, JsonArray b, int i, int bestLineIndex, PathModule pathModule) {
pathModule.addLeftPath(constructArrayPath(i));
pathModule.addRightPath(constructArrayPath(bestLineIndex));
DiffContext diffContext = diffElement(a.get(i), b.get(bestLineIndex), pathModule);
pathModule.removeAllLastPath();
return diffContext;
}
/**
* 用数组a的一个元素与数组b中所有元素分别比较会得到n次比较结果结果为不相等的结果对数在矩阵中更新n次结果
*/
private void constructSimilarMatrix(JsonArray arrayA, JsonArray arrayB, int rowIndex, PathModule pathModule, int [][]similarArray, boolean[] row, boolean[] line) {
if(rowIndex < 0 || rowIndex >= arrayB.size()){
throw new RuntimeException("索引号入参超出数组长度。 索引号:" + rowIndex +" 数组B:" + arrayB);
}
for (int j = 0; j < arrayB.size(); j++) {
if (line[j] == USEABLE) {
pathModule.addRightPath(constructArrayPath(j));
DiffContext diffContext = diffElement(arrayA.get(rowIndex), arrayB.get(j), pathModule);
pathModule.removeLastRightPath();
if (diffContext.isSame()) {
row[rowIndex] = USED;
line[j] = USED;
return;
} else if(existSpecialPath(diffContext.getSpecialPathResult())){
similarArray[rowIndex][j] = 0 ;
} else {
similarArray[rowIndex][j] = diffContext.getDiffResultModels().size();
}
}
}
}
/**
* 判断比较结果是否有特殊路径
*/
private boolean existSpecialPath(LinkedList<String> specialPathResult) {
return specialPathResult != null && !specialPathResult.isEmpty();
}
}

62
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/array/SimpleArrayComparator.java

@ -0,0 +1,62 @@
package com.zc.business.utils.diff.algorithm.array;
import com.google.gson.JsonArray;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 简单数组比较器数组对比时按照索引号顺序依次进行比较
* [A,B,C] [C,B,A]比较时依次找索引号为0为1为2进行比较相同结果对为<A,C> <B,B> <C,A>不同结果<A,C> <C,A>会加入到返回结果中
* @Author JingWei
* @create 2022/1/14
*/
public class SimpleArrayComparator extends AbstractArray {
/**
* 对两个JsonArray进行比较的方法
* @param a 要比较的第一个数组
* @param b 要比较的第二个数组
* @param pathModule 路径模型
* @return 返回不相等的比较结果
*/
@Override
public DiffContext diffArray(JsonArray a, JsonArray b, PathModule pathModule) {
DiffContext arrayDiffContext = new DiffContext();
int maxLength = Math.max(a.size(), b.size());
//根据数组a和b长度的大的值进行遍历
for (int i = 0; i < maxLength; i++) {
pathModule.addAllpath(constructArrayPath(i));
DiffContext diffContext = generateDiffResult(a,b,i,pathModule);
parentContextAddChildContext(arrayDiffContext, diffContext);
}
return arrayDiffContext;
}
/**
* 生成比较结果,分以下3种情况考虑
* i < a.size() && i < b.size()
* a.size() <= i
* b.size() <= i
* @param a 数组a
* @param b 数组b
* @param i 数组a和b中正在比较的元素索引号
* @param pathModule 路径模型
* @return 返回不相等的比较结果
*/
private DiffContext generateDiffResult(JsonArray a, JsonArray b, int i, PathModule pathModule) {
if(i >= a.size() && i >= b.size()){
throw new RuntimeException("数组索引号入参超过数组长度。 索引号:" + i + " 数组a:" + a + "数组b:" + b);
}
DiffContext diffContext;
if(i < a.size() && i < b.size()){
diffContext = diffElement(a.get(i), b.get(i), pathModule);
}else if (i >= a.size()){
diffContext = diffElement(null, b.get(i), pathModule);
}else{
diffContext = diffElement(a.get(i), null, pathModule);
}
return diffContext;
}
}

27
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/nulls/DefaultNullComparator.java

@ -0,0 +1,27 @@
package com.zc.business.utils.diff.algorithm.nulls;
import com.google.gson.JsonNull;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 当要比较的两个JsonElement都为空类型时默认实现的算法比较器
* @Author JingWei
* @create 2022/1/10
*/
public class DefaultNullComparator implements NullComparator {
/**
* 当要比较的两个JsonElement是空类型时默认比较方法
* @param a 第一个空类型
* @param b 第二个空类型
* @param pathModule 路径模型
* @return 返回结果
*/
@Override
public DiffContext diff(JsonNull a, JsonNull b, PathModule pathModule){
return new DiffContext();
}
}

25
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/nulls/NullComparator.java

@ -0,0 +1,25 @@
package com.zc.business.utils.diff.algorithm.nulls;
import com.google.gson.JsonNull;
import com.zc.business.utils.diff.algorithm.Comparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 空类型比较器接口用于2个JsonElement均为JsonNull时对2个元素进行比较
* @Author JingWei
* @create 2022/2/23
*/
public interface NullComparator extends Comparator {
/**
* 对两个JsonNull进行比较时需要实现此方法
* @param a 要比较的第一个JsonNull
* @param b 要比较的第二个JsonNull
* @param pathModule 路径模型
* @return 返回不同的比较结果
*/
DiffContext diff(JsonNull a, JsonNull b, PathModule pathModule);
}

128
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/AbstractObject.java

@ -0,0 +1,128 @@
package com.zc.business.utils.diff.algorithm.object;
import com.google.common.base.Joiner;
import com.google.gson.JsonObject;
import com.zc.business.utils.diff.algorithm.AbstractObjectAndArray;
import com.zc.business.utils.diff.model.Constants;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 对象比较的一些公有方法抽象类
* @Author JingWei
* @create 2022/2/24
*/
public abstract class AbstractObject extends AbstractObjectAndArray implements ObjectComparator {
/**
* 对两个对象进行比较遍历keySet中的所有key 在a和b对象中找对应的value值进行比较
* @param a 要比较的第一个对象
* @param b 要比较的第二个对象
* @param keySet key的集合
* @param pathModule 路径模型
* @return 不同的比较结果
*/
protected DiffContext diffValueByKey(JsonObject a, JsonObject b, Set<String> keySet, PathModule pathModule) {
DiffContext objectDiffContext = new DiffContext();
LinkedList<String> specialPathResult = new LinkedList<>();
for (String key : keySet) {
//更新a和b当前路径
pathModule.addAllpath(key);
//如果对象当前路径在噪音路径集合中,直接跳过比较
if (!needDiff(pathModule.getNoisePahList(), pathModule.getLeftPath())) {
pathModule.removeAllLastPath();
continue;
}
//生成比较结果
DiffContext diffContext = diffElement(a.get(key), b.get(key), pathModule);
parentContextAddChildContext(objectDiffContext, diffContext);
//特殊路径处理
specialPathHandle(diffContext.isSame(), specialPathResult, pathModule);
pathModule.removeAllLastPath();
}
objectDiffContext.setSpecialPathResult(specialPathResult);
return objectDiffContext;
}
/**
* 如果比较的路径为特殊路径并且比较相等特殊路径会被标识添加到返回结果中
* @param isSame 比较结果是否相等
* @param specialPathResult 返回的特殊路径结果
* @param pathModule 路径模型
*/
private void specialPathHandle(boolean isSame,LinkedList<String> specialPathResult, PathModule pathModule) {
//如果比较结果不等,直接返回。
if (!isSame){
return;
}
//如果存在特殊路径,将特殊路径加入到集合中
String specialPath = getSpecialPath(pathModule);
if( existPath(specialPath)){
specialPathResult.add(specialPath);
}
}
/**
* 校验路径是否存在即路径是否为空
* @param specialPath 特殊路径
* @return 特殊路径是否为空
*/
private boolean existPath(String specialPath) {
return specialPath != null;
}
/**
* 判断当前路径是否在特殊路径集合中如果在则返回特殊路径
* @param pathModule 路径模型
* @return 返回的特殊路径字符串
*/
protected String getSpecialPath(PathModule pathModule) {
if(pathModule == null || pathModule.getSpecialPath() == null || pathModule.getSpecialPath().isEmpty()){
return null;
}
String currentPath = listJoin(pathModule.getLeftPath());
if(pathModule.getSpecialPath().contains(currentPath)){
return currentPath;
}
return null;
}
/**
* 判断当前字段是否需要diff如果在噪音字段集合中则不需要diff返回false
* @param noisePahList 噪音路径列表
* @param pathList 当前路径
* @return 当前路径是否在噪音路径中
*/
protected boolean needDiff(List<String> noisePahList, LinkedList<String> pathList) {
if(noisePahList == null || pathList == null || noisePahList.isEmpty() || pathList.isEmpty()){
return true;
}
String path = listJoin(pathList);
if(noisePahList.contains(path)){
return false;
}
return true;
}
/**
* 将path路径列表改为字符串
* @param path 当前路径
* @return 当前路径字符串
*/
protected String listJoin(LinkedList<String> path) {
if(path == null){
throw new RuntimeException("当前路径不能为空");
}
List<String> collect = path.stream().filter(e -> e.charAt(0) != '[').collect(Collectors.toList());
return Joiner.on(Constants.MERGE_PATH).join(collect);
}
}

30
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/LeftJoinObjectComparator.java

@ -0,0 +1,30 @@
package com.zc.business.utils.diff.algorithm.object;
import com.google.gson.JsonObject;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 左匹配对象比较器当对两个JsonObject进行比较时只对第一个对象中keySet中存在keyValue值进行比较
*
* 举例
* {"a":1,"b":2,"c":3}{"a":1,"b":4,"c":3,"d":4}进行比较
* 只会比较第一个对象中有的字段即比较第一个对象中有的"a","b","c"3个字段第二个对象中的"d"字段没有被比较
*
* @Author JingWei
* @create 2022/2/18
*/
public class LeftJoinObjectComparator extends AbstractObject {
/**
* @param a 要比较的第一个JsonObject
* @param b 要比较的第二个JsonObject
* @param pathModule 路径模型
* @return 不同的比较结果
*/
@Override
public DiffContext diff(JsonObject a, JsonObject b, PathModule pathModule){
//用a的keySet作为遍历集合。
return diffValueByKey(a, b, a.keySet(), pathModule);
}
}

40
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/ObjectComparator.java

@ -0,0 +1,40 @@
package com.zc.business.utils.diff.algorithm.object;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.zc.business.utils.diff.algorithm.AlgorithmModule;
import com.zc.business.utils.diff.algorithm.Comparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 对象类型比较器接口用于2个JsonElement均为JsonObject时对2个元素进行比较
* @Author JingWei
* @create 2022/2/23
*/
public interface ObjectComparator extends Comparator {
/**
* 对两个JsonObject进行比较时需要实现此方法
* @param a 要比较的第一个JsonObject
* @param b 要比较的第二个JsonObject
* @param pathModule 路径模型
* @return 返回不同的比较结果
*/
DiffContext diff(JsonObject a, JsonObject b, PathModule pathModule);
/**
* 对象内部包含其他非JsonObject类型对这些类型比较需要使用JsonElement比较方法
* @param a 元素a
* @param b 元素b
* @param pathModule 路径模型
* @return 返回不同的比较结果
*/
DiffContext diffElement(JsonElement a, JsonElement b, PathModule pathModule);
/**
* 构造算法模型对象比较时内部元素比较需要使用到其他非数组算法
* @param algorithmModule 算法模型包含对象数组基本类型空类型其他类型算法
*/
void constructAlgorithmModule(AlgorithmModule algorithmModule);
}

33
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/object/SimpleObjectComparator.java

@ -0,0 +1,33 @@
package com.zc.business.utils.diff.algorithm.object;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import java.util.Set;
/**
* 简单对象比较器当对两个JsonObject进行比较时两个对象所有keySet中key对应的Value都会被比较
* 举例
* {"b":2,"c":3}{"a":1,"d":4}进行比较
* 会比较两个对象中所有的字段即比较两个对象中并集"a","b","c","d"4个字段
* @Author JingWei
* @create 2022/2/16
*/
public class SimpleObjectComparator extends AbstractObject {
/**
* @param a 要比较的第一个JsonObject
* @param b 要比较的第二个JsonObject
* @param pathModule 路径模型
* @return 不同的比较结果
*/
@Override
public DiffContext diff(JsonObject a, JsonObject b, PathModule pathModule) {
Set<String> unionSet = Sets.union(a.keySet(), b.keySet());
//用a和b的keySet的并集作为遍历集合。
return diffValueByKey(a, b, unionSet, pathModule);
}
}

38
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/other/DefaultOtherComparator.java

@ -0,0 +1,38 @@
package com.zc.business.utils.diff.algorithm.other;
import com.google.common.base.Joiner;
import com.google.gson.JsonElement;
import com.zc.business.utils.diff.algorithm.AbstractPrimitiveAndOther;
import com.zc.business.utils.diff.model.Constants;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import com.zc.business.utils.diff.model.SingleNodeDifference;
import java.util.ArrayList;
import java.util.List;
/**
* 当要比较的两个JsonElement的不同时为对象组数基本类型时默认实现的比较器
* @Author JingWei
* @create 2022/1/10
*/
public class DefaultOtherComparator extends AbstractPrimitiveAndOther implements OtherComparator {
/**
* @param a 要比较的第一个JsonElement
* @param b 要比较的第二个JsonElement
* @param pathModule 路径模型
* @return 不同的比较结果
*/
@Override
public DiffContext diff(JsonElement a, JsonElement b, PathModule pathModule){
//比较结果一定会不同,因为要比较的a和b类型不同才会调用该方法。
DiffContext otherDiffContext = new DiffContext(Constants.DIFFERENT);
List<SingleNodeDifference> singleNodeDifferences = new ArrayList<>();
singleNodeDifferences.add(new SingleNodeDifference(Joiner.on(Constants.MERGE_PATH).join(pathModule.getLeftPath()), Joiner.on(Constants.MERGE_PATH).join(pathModule.getRightPath()), jsonElement2Str(a), jsonElement2Str(b)));
otherDiffContext.setDiffResultModels(singleNodeDifferences);
return otherDiffContext;
}
}

24
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/other/OtherComparator.java

@ -0,0 +1,24 @@
package com.zc.business.utils.diff.algorithm.other;
import com.google.gson.JsonElement;
import com.zc.business.utils.diff.algorithm.Comparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 其他类型比较器接口用于2个JsonElement不同时为对象数组基本类型时对2个元素进行比较
*
* 举例第一个要比较类型为对象类型第二个要比较类型为数组类型
* @Author JingWei
* @create 2022/2/23
*/
public interface OtherComparator extends Comparator {
/**
* 对两个JsonElement进行比较并且两个JsonElement的类型不相等时需要实现此方法
* @param a 要比较的第一个JsonElement
* @param b 要比较的第二个JsonElement
* @return 不同的比较结果
*/
DiffContext diff(JsonElement a, JsonElement b, PathModule pathModule);
}

39
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/primitive/DefaultPrimitiveComparator.java

@ -0,0 +1,39 @@
package com.zc.business.utils.diff.algorithm.primitive;
import com.google.common.base.Joiner;
import com.google.gson.JsonPrimitive;
import com.zc.business.utils.diff.algorithm.AbstractPrimitiveAndOther;
import com.zc.business.utils.diff.model.Constants;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
import com.zc.business.utils.diff.model.SingleNodeDifference;
import java.util.ArrayList;
import java.util.List;
/**
* 当要比较的两个JsonElement是基本类型时默认实现的比较器
* @Author JingWei
* @create 2022/1/10
*/
public class DefaultPrimitiveComparator extends AbstractPrimitiveAndOther implements PrimitiveComparator {
/**
* @param a 要比较的第一个JsonPrimitive
* @param b 要比较的第二个JsonPrimitive
* @param pathModule 路径模型
* @return 不同的比较结果
*/
@Override
public DiffContext diff(JsonPrimitive a, JsonPrimitive b, PathModule pathModule){
DiffContext primitiveDiffContext = new DiffContext();
//如果a和b不相等,返回a和b的比较结果。
if(Constants.DIFFERENT == a.equals(b)) {
List<SingleNodeDifference> singleNodeDifferences = new ArrayList<>();
singleNodeDifferences.add(new SingleNodeDifference(Joiner.on(Constants.MERGE_PATH).join(pathModule.getLeftPath()), Joiner.on(Constants.MERGE_PATH).join(pathModule.getRightPath()), jsonElement2Str(a), jsonElement2Str(b)));
primitiveDiffContext.setDiffResultModels(singleNodeDifferences);
primitiveDiffContext.setSame(Constants.DIFFERENT);
}
return primitiveDiffContext;
}
}

23
zc-business/src/main/java/com/zc/business/utils/diff/algorithm/primitive/PrimitiveComparator.java

@ -0,0 +1,23 @@
package com.zc.business.utils.diff.algorithm.primitive;
import com.google.gson.JsonPrimitive;
import com.zc.business.utils.diff.algorithm.Comparator;
import com.zc.business.utils.diff.model.DiffContext;
import com.zc.business.utils.diff.model.PathModule;
/**
* 基本类型比较器接口用于2个JsonElement均为基本类型的时对2个元素进行比较
* @Author JingWei
* @create 2022/2/23
*/
public interface PrimitiveComparator extends Comparator {
/**
* 对两个基本类型进行比较时需要实现此方法
* @param a 要比较的第一个JsonPrimitive
* @param b 要比较的第二个JsonPrimitive
* @param pathModule 路径模型
* @return 不同的比较结果
*/
DiffContext diff(JsonPrimitive a, JsonPrimitive b, PathModule pathModule);
}

20
zc-business/src/main/java/com/zc/business/utils/diff/model/Constants.java

@ -0,0 +1,20 @@
package com.zc.business.utils.diff.model;
/**
* 常量
* @Author JingWei
* @create 2022/3/2
*/
public class Constants {
/**
* 描述比较结果不同
*/
public static final boolean DIFFERENT = false;
/**
* 描述比较结果相同
*/
public static final boolean SAME = true;
public static final String SPLIT_PATH = "\\.";
public static final String MERGE_PATH = ".";
}

61
zc-business/src/main/java/com/zc/business/utils/diff/model/DiffContext.java

@ -0,0 +1,61 @@
package com.zc.business.utils.diff.model;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
* diff比较上下文
* @Author JingWei
* @create 2022/3/2
*/
public class DiffContext {
/**
* 比较结果是否相同
*/
private boolean isSame;
/**
* 比较结果不同时存储所有不同的结果对
*/
private List<SingleNodeDifference> singleNodeDifferences;
/**
* 比较结果中出现了特殊路径下值相等的情况会存储该特殊路径
*/
private LinkedList<String> specialPathResult;
public DiffContext(boolean isSame) {
this.isSame = isSame;
this.singleNodeDifferences = new ArrayList<>();
}
public boolean isSame() {
return isSame;
}
public void setSame(boolean same) {
isSame = same;
}
public List<SingleNodeDifference> getDiffResultModels() {
return singleNodeDifferences;
}
public void setDiffResultModels(List<SingleNodeDifference> singleNodeDifferences) {
this.singleNodeDifferences = singleNodeDifferences;
}
public DiffContext() {
this.isSame = true;
this.singleNodeDifferences = new ArrayList<>();
}
public LinkedList<String> getSpecialPathResult() {
return specialPathResult;
}
public void setSpecialPathResult(LinkedList<String> specialPathResult) {
this.specialPathResult = specialPathResult;
}
}

122
zc-business/src/main/java/com/zc/business/utils/diff/model/PathModule.java

@ -0,0 +1,122 @@
package com.zc.business.utils.diff.model;
import java.util.LinkedList;
import java.util.List;
/**
* 路径模型
* A和B比较时实时更新当前正在进行比较的元素路径
*
* @Author JingWei
* @create 2022/2/15
*/
public class PathModule {
/**
* 对象A当前遍历到的路径
*/
private LinkedList<String> leftPath;
/**
* 对象B当前遍历到的路径
*/
private LinkedList<String> rightPath;
/**
* 特殊路径集合当前路径符合特殊路径且特殊路径下比较结果相同会在返回结果中做额外标识标识
*/
private List<String> specialPath;
/**
* 噪音字段集合如果当前路径符合噪音字段路径则不会比较
*/
private List<String> noisePahList;
public PathModule() {
this.leftPath = new LinkedList<>();
this.rightPath = new LinkedList<>();
}
public PathModule(List<String> noisePahList) {
this.leftPath = new LinkedList<>();
this.rightPath = new LinkedList<>();
this.noisePahList = noisePahList;
}
public PathModule(List<String> noisePahList, List<String> specialPath) {
this.leftPath = new LinkedList<>();
this.rightPath = new LinkedList<>();
this.noisePahList = noisePahList;
this.specialPath = specialPath;
}
public List<String> getNoisePahList() {
return noisePahList;
}
public void setNoisePahList(List<String> noisePahList) {
this.noisePahList = noisePahList;
}
public List<String> getSpecialPath() {
return specialPath;
}
public void setSpecialPath(LinkedList<String> specialPath) {
this.specialPath = specialPath;
}
public LinkedList<String> getLeftPath() {
return leftPath;
}
public void setLeftPath(LinkedList<String> leftPath) {
this.leftPath = leftPath;
}
public LinkedList<String> getRightPath() {
return rightPath;
}
public void setRightPath(LinkedList<String> rightPath) {
this.rightPath = rightPath;
}
/**
* 同时在A和B路径列表最后加上一个Path路径
*/
public void addAllpath(String lastPath) {
leftPath.add(lastPath);
rightPath.add(lastPath);
}
public void addLeftPath(String lastPath) {
leftPath.add(lastPath);
}
public void addRightPath(String lastPath) {
rightPath.add(lastPath);
}
/**
* 同时移除A和B路径列表中最后的一个路径
*/
public void removeAllLastPath() {
leftPath.removeLast();
rightPath.removeLast();
}
/**
* 移除A路径列表中最后的一个路径
*/
public void removeLastLeftPath() {
leftPath.removeLast();
}
/**
* 移除B路径列表中最后的一个路径
*/
public void removeLastRightPath() {
rightPath.removeLast();
}
}

71
zc-business/src/main/java/com/zc/business/utils/diff/model/Result.java

@ -0,0 +1,71 @@
package com.zc.business.utils.diff.model;
import java.io.Serializable;
/**
* diff比较最终结果
* @Author JingWei
* @create 2022/3/2
*/
public class Result implements Serializable {
/**
* 第一个对象路径
*/
private String leftPath;
/**
* 第二个对象路径
*/
private String rightPath;
/**
* 第一个对象值
*/
private Object left;
/**
* 第二个对象值
*/
private Object right;
/**
* 比较结果
*/
private String diffType;
public String getLeftPath() {
return leftPath;
}
public String getRightPath() {
return rightPath;
}
public void setLeftPath(String leftPath) {
this.leftPath = leftPath;
}
public void setRightPath(String rightPath) {
this.rightPath = rightPath;
}
public Object getLeft() {
return left;
}
public void setLeft(Object left) {
this.left = left;
}
public Object getRight() {
return right;
}
public void setRight(Object right) {
this.right = right;
}
public String getDiffType() {
return diffType;
}
public void setDiffType(String diffType) {
this.diffType = diffType;
}
}

66
zc-business/src/main/java/com/zc/business/utils/diff/model/ResultConvertUtil.java

@ -0,0 +1,66 @@
package com.zc.business.utils.diff.model;
import java.util.ArrayList;
import java.util.Objects;
/**
* 结果转换工具:将diff上下文转换成diff最终结果
* @Author JingWei
* @create 2022/2/25
*/
public class ResultConvertUtil {
public static final String OBJECT_NULL = null;
//diff结果类型分为修改、新增、删除
public static final String TYPE_MODIFY = "MODIFY";
public static final String TYPE_ADD = "ADD";
public static final String TYPE_DELETE = "DELETE";
/**
* 将diff上下文转换成diff最终结果
* @param diffContext diff比较的直接结果
* @return diff展示的结果
*/
public static ArrayList<Result> constructResult(DiffContext diffContext) {
ArrayList<Result> list = new ArrayList<>();
for (SingleNodeDifference resultModel : diffContext.getDiffResultModels()) {
Result printModel = convert(resultModel);
boolean leftAndRightBothNull = (Objects.equals(OBJECT_NULL,resultModel.getLeft()))
&& Objects.equals(OBJECT_NULL,resultModel.getRight()) ;
//判断两个对象是否同时为空
if (leftAndRightBothNull) {
printModel.setDiffType(TYPE_MODIFY);
}
//这种情况为对象A中keySet没这个key,或者A数组长度小于B 数组中没这个元素。
else if (Objects.equals(OBJECT_NULL,resultModel.getLeft()) ) {
printModel.setDiffType(TYPE_ADD);
printModel.setLeftPath(null);
}
//这种情况为对象B中keySet没这个key,或者B数组长度小于A 数组中没这个元素。
else if (Objects.equals(OBJECT_NULL,resultModel.getRight()) ) {
printModel.setDiffType(TYPE_DELETE);
printModel.setRightPath(null);
}
//其他情况
else {
printModel.setDiffType(TYPE_MODIFY);
}
list.add(printModel);
}
return list;
}
/**
* 数据模型转换增加类型字段
* @param resultModel 比较结果
* @return 展示模型
*/
private static Result convert(SingleNodeDifference resultModel) {
Result printModel = new Result();
printModel.setLeft(resultModel.getLeft());
printModel.setRight(resultModel.getRight());
printModel.setLeftPath(resultModel.getLeftPath());
printModel.setRightPath(resultModel.getRightPath());
return printModel;
}
}

69
zc-business/src/main/java/com/zc/business/utils/diff/model/SingleNodeDifference.java

@ -0,0 +1,69 @@
package com.zc.business.utils.diff.model;
import java.io.Serializable;
/**
* 单对元素比较结果
* @Author JingWei
* @create 2022/3/2
*/
public class SingleNodeDifference implements Serializable {
/**
* 第一个对象路径
*/
private String leftPath;
/**
* 第二个对象路径
*/
private String rightPath;
/**
* 第一个对象值
*/
private Object left;
/**
* 第二个对象值
*/
private Object right;
/**
* 比较结果
*/
public SingleNodeDifference(String leftPath, String rightPath, Object left, Object right) {
this.leftPath = leftPath;
this.rightPath = rightPath;
this.left = left;
this.right = right;
}
public String getLeftPath() {
return leftPath;
}
public void setLeftPath(String leftPath) {
this.leftPath = leftPath;
}
public String getRightPath() {
return rightPath;
}
public void setRightPath(String rightPath) {
this.rightPath = rightPath;
}
public Object getLeft() {
return left;
}
public void setLeft(Object left) {
this.left = left;
}
public Object getRight() {
return right;
}
public void setRight(Object right) {
this.right = right;
}
}

14
zc-business/src/main/resources/mapper/business/DcEventMapper.xml

@ -681,6 +681,15 @@
) t ON s.event_state = t.event_state;
</select>
<select id="getProcessNode" resultType="java.util.Map">
select t2.node_node,t2.process_node,t3.operation_time,
case when ISNULL(t3.id) then '0' else '1' end status
from dc_event t1
LEFT JOIN dc_process_config t2 on t1.event_type = t2.event_type
left join dc_event_process t3 on t2.node_node = t3.process_id and t3.process_type = '1'
where t1.id = #{eventId}
</select>
<update id="updateDcEventState" parameterType="string">
update dc_event
@ -689,4 +698,9 @@
</trim>
where id = #{id}
</update>
<update id="completeEvent">
update dc_event set end_time = now(),event_state = '2'
where id = #{eventId}
</update>
</mapper>

6
zc-business/src/main/resources/mapper/business/DcEventProcessMapper.xml

@ -131,5 +131,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where event_id = #{id}
ORDER BY operation_time ASC;
</select>
<select id="selectFinalNode" resultType="java.lang.Integer">
SELECT IFNULL(max(t2.node_node),0) finalNode
FROM `dc_event` t1
LEFT JOIN dc_process_config t2 on t1.event_type = t2.event_type
where t1.id = #{eventId};
</select>
</mapper>
Loading…
Cancel
Save