> 文章列表 > 文本差异(变更)对比 ----------- java + vue 实现

文本差异(变更)对比 ----------- java + vue 实现

文本差异(变更)对比 ----------- java + vue 实现

目录

一、效果图

二、代码

1、maven

2、工具类

2、接口

3、前端

三、讲解

1、后端

2、前端


一、效果图

 

 

 

二、代码

1、maven

        <dependency><groupId>io.github.java-diff-utils</groupId><artifactId>java-diff-utils</artifactId><version>4.11</version></dependency>

2、工具类


/* 文本变更对比 @author zenglingyao* @date 2023/04/11*/
public class DiffTextUtil {/* 发现差异 @return {@link Map}*/public static Map<String, List<?>> findDiff(List<String> a, List<String> b) {//两文件的不同点Patch<String> patch = DiffUtils.diff(a, b);List<Integer[]> diffPosition = new ArrayList<>();List<Integer> insertList = new ArrayList<>();List<Integer> sourceChange = new ArrayList<>();List<Integer> targetChange = new ArrayList<>();List<Integer> deleteList = new ArrayList<>();List<AbstractDelta<String>> deltas = patch.getDeltas();for (AbstractDelta<String> abstractDelta : deltas) {int sourceStart = abstractDelta.getSource().getPosition();int sourceLast = abstractDelta.getSource().last();int targetStart = abstractDelta.getTarget().getPosition();int targetLast = abstractDelta.getTarget().last();switch (abstractDelta.getType()){case INSERT:insertList.addAll(getAll(targetStart,  targetLast));break;case CHANGE:sourceChange.addAll(getAll(sourceStart,  sourceLast));targetChange.addAll(getAll(targetStart,  targetLast));break;case DELETE:deleteList.addAll(getAll(sourceStart, sourceLast));break;default:continue;}diffPosition.add(new Integer[]{sourceStart, targetStart});}HashMap<String, List<?>> hashMap = new HashMap<>();hashMap.put("sourceList", a);hashMap.put("targetList", b);hashMap.put("insertList", insertList);hashMap.put("sourceChange", sourceChange);hashMap.put("targetChange", targetChange);hashMap.put("deleteList", deleteList);hashMap.put("diffPosition", diffPosition);return hashMap;}private static List<Integer> getAll(int start, int end) {List<Integer> result = new ArrayList<>(end - start + 1);for (int i = start; i <= end; i++) {result.add(i);}return result;}
}

2、接口


@RestController
@RequestMapping("/api/demo")
public class DiffTextController {@RequestMapping("diff")public Map findDiff() {List<String> a = null;List<String> b = null;try {a = FileUtils.readLines(new File("E:\\\\test\\\\diff1.conf"));b = FileUtils.readLines(new File("E:\\\\test\\\\diff2.conf"));} catch (IOException ignore) {}return DiffTextUtil.findDiff(a, b);}}

3、前端

<template><div><el-row><el-col :span="12"><div style="overflow-y: auto; height: 90vh"><divv-for="(item,index) in sourceList":key="index":id="'sourceList' + index"style="min-height: 23px; padding: 3px 0":class="deleteList.includes(index) ? 'red' : sourceChange.includes(index) ? 'blue' : ''">{{ item }}</div></div></el-col><el-col :span="12"><div style="overflow-y: auto; height: 90vh"><divv-for="(item,index) in targetList":key="index":id="'targetList' + index"style="min-height: 23px; padding: 3px 0":class="insertList.includes(index) ? 'green' : targetChange.includes(index) ? 'blue' : ''">{{ item}}</div></div></el-col></el-row><el-row style="background-color: darkgrey; margin-top: 10px">共{{diffPosition.length}}处差异跳转到<el-inputv-model="diffCurrent"size="mini"style="width: 80px; margin-right: 5px;"></el-input><el-tooltip class="item" effect="dark" content="跳转" placement="top"><el-button @click="jump()" size="mini" icon="el-icon-position" type="primary" style="margin: 0 10px" circle></el-button></el-tooltip><i class="el-icon-top" @click="jumpTop()" style="margin: 0 10px"></i><i class="el-icon-bottom" @click="jumpBottom()"></i></el-row></div>
</template><script>export default {name: "DiffDemo",data() {return {sourceList: [],targetList: [],insertList: [],sourceChange: [],targetChange: [],deleteList: [],diffPosition: [],diffCurrent: 1}},methods: {init() {this.post("/api/demo/diff", {},  d=>{this.sourceList = d.sourceList;this.targetList = d.targetList;this.insertList = d.insertList;this.sourceChange = d.sourceChange;this.targetChange = d.targetChange;this.deleteList = d.deleteList;this.diffPosition = d.diffPosition;});},checkDiffCurrent() {return this.diffCurrent > 0 && this.diffCurrent <= this.diffPosition.length;},goPosition() {location.href = "#sourceList" + this.diffPosition[this.diffCurrent - 1][0];setTimeout(()=>{location.href = "#targetList" +  + this.diffPosition[this.diffCurrent - 1][1];},0)},initPosition() {this.diffCurrent = 1;this.goPosition();},jump() {if (this.checkDiffCurrent()) {this.goPosition();}else {this.initPosition();}},jumpTop() {if (this.checkDiffCurrent()) {if (this.diffCurrent === 1){return;}this.diffCurrent--;this.goPosition();}else {this.initPosition();}},jumpBottom() {if (this.checkDiffCurrent()) {if (this.diffCurrent === this.diffPosition.length){return;}this.diffCurrent++;this.goPosition();}else {this.initPosition();}}},created() {this.init();let that = this;setTimeout(function (){that.initPosition();}, 0)},
}
</script><style scoped>
.green {background-color: #a8ec7c;
}
.red {background-color: #e88686;
}
.blue {background-color: #7bb5fd;
}</style>

三、讲解

1、后端

DiffTextUtil.findDiff 参数为两个需要对比的字符串列表,核心代码是

Patch<String> patch = DiffUtils.diff(a, b);
List<AbstractDelta<String>> deltas = patch.getDeltas();

第一个参数是源 (a),第二个参数是目的(b)

遍历对比的结果记录,找到新增、修改、删除对应的下标记录下来

insertList                记录目的新增下标      到前端变绿色用

sourceChange       记录源改变下标         到前端变蓝色用

targetChange         记录目的改变下标     到前端变蓝色用

deleteList               记录删除下标            到前端变红色用

diffPosition             记录每处差异开始位置,包括源和目的下标    到前端跳转到下一处差异按钮用


2、前端

  • 跳转功能通过 HTML锚点 实现
  • js 的 setTimeout​​ 方法,我调用时时间参数传的0,看起来没有,实际上可以等前面axios回调执行完再执行需要执行的方法
  • this.post 是我自己封装的axios,用的时候可以自己改一下