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

该文章介绍了一个使用java-diff-utils库进行文本差异对比的Java工具类,通过Maven引入依赖。工具类处理两个字符串列表的差异,返回不同类型的变更列表。后端提供一个接口读取文件并调用此工具,前端利用Vue.js展示差异,用颜色标记插入、修改和删除的内容,并实现跳转至差异位置的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、效果图

二、代码

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">
          <div
              v-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">
          <div
              v-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-input
          v-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,用的时候可以自己改一下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值