springboot 文件差异化对比以及可视化展示

maven依赖

   <!--   文件内容对比-->
        <dependency>
            <groupId>io.github.java-diff-utils</groupId>
            <artifactId>java-diff-utils</artifactId>
            <version>4.11</version>
        </dependency>

创建Diff 工具类

package com.system.utlis.diff;


import com.github.difflib.UnifiedDiffUtils;
import com.github.difflib.patch.Patch;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component
public class DiffHandleUtils {
  public static void main(String[] args) {
    //对比 F:\n1.txt和 F:\n2.txt 两个文件,获得不同点
    List<String> diffString = DiffHandleUtils.diffString("E:\\test\\test1.java", "E:\\test\\test2.txt");
    //在F盘生成一个diff.html文件,打开便可看到两个文件的对比
    DiffHandleUtils.generateDiffHtml(diffString, "E:\\test");
    System.out.println("diff完成");
  }


  /**
   * 对比两文件的差异,返回原始文件+diff格式
   *
   * @param original 原文件内容
   * @param revised  对比文件内容
   */
  public static List<String> diffString(List<String> original, List<String> revised) {
    return diffString(original, revised, null, null);
  }

  /**
   * 对比两文件的差异,返回原始文件+diff格式
   *
   * @param original         原文件内容
   * @param revised          对比文件内容
   * @param originalFileName 原始文件名
   * @param revisedFileName  对比文件名
   */
  public static List<String> diffString(List<String> original, List<String> revised, String originalFileName, String revisedFileName) {
    originalFileName = originalFileName == null ? "原始文件" : originalFileName;
    revisedFileName = revisedFileName == null ? "对比文件" : revisedFileName;
    //两文件的不同点
    Patch<String> patch = com.github.difflib.DiffUtils.diff(original, revised);
    //生成统一的差异格式
    List<String> unifiedDiff = UnifiedDiffUtils.generateUnifiedDiff(originalFileName, revisedFileName, original, patch, 0);
    int diffCount = unifiedDiff.size();
    if (unifiedDiff.size() == 0) {
      //如果两文件没差异则插入如下
      unifiedDiff.add("--- " + originalFileName);
      unifiedDiff.add("+++ " + revisedFileName);
      unifiedDiff.add("@@ -0,0 +0,0 @@");
    } else if (unifiedDiff.size() >= 3 && !unifiedDiff.get(2).contains("@@ -1,")) {
      unifiedDiff.set(1, unifiedDiff.get(1));
      //如果第一行没变化则插入@@ -0,0 +0,0 @@
      unifiedDiff.add(2, "@@ -0,0 +0,0 @@");
    }
    //原始文件中每行前加空格
    List<String> original1 = original.stream().map(v -> " " + v).collect(Collectors.toList());
    //差异格式插入到原始文件中
    return insertOrig(original1, unifiedDiff);
  }


  /**
   * 对比两文件的差异,返回原始文件+diff格式
   *
   * @param filePathOriginal 原文件路径
   * @param filePathRevised  对比文件路径
   */
  public static List<String> diffString(String filePathOriginal, String filePathRevised) {
    //原始文件
    List<String> original = null;
    //对比文件
    List<String> revised = null;
    File originalFile = new File(filePathOriginal);
    File revisedFile = new File(filePathRevised);
    try {
      original = Files.readAllLines(originalFile.toPath());
      revised = Files.readAllLines(revisedFile.toPath());
    } catch (IOException e) {
      e.printStackTrace();
    }
    return diffString(original, revised, originalFile.getName(), revisedFile.getName());
  }

  /**
   * 通过两文件的差异diff生成 html文件,打开此 html文件便可看到文件对比的明细内容
   *
   * @param diffString 调用上面 diffString方法获取到的对比结果
   * @param htmlPath   生成的html路径,如:/user/var/mbos/ent/21231/
   */
  public static void generateDiffHtml(List<String> diffString, String htmlPath) {
    StringBuilder builder = new StringBuilder();
    for (String line : diffString) {
      builder.append(escapeStr(line));
      builder.append("\n");
    }
    //githubCss来自 https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css
    String githubCss = "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css";
    //diff2htmlCss来自 https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css
    String diff2htmlCss = "https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css";
    //diff2htmlJs来自 https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js
    String diff2htmlJs = "https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js";

    String template = "<!DOCTYPE html>\n" +
        "<html lang=\"en-us\">\n" +
        "  <head>\n" +
        "    <meta charset=\"utf-8\" />\n" +
        "    <link rel=\"stylesheet\" href=\"" + githubCss + "\" />\n" +
        "     <link rel=\"stylesheet\" type=\"text/css\" href=\"" + diff2htmlCss + "\" />\n" +
        "    <script type=\"text/javascript\" src=\"" + diff2htmlJs + "\"></script>\n" +
        "  </head>\n" +
        "  <script>\n" +
        "    const diffString = `\n" +
        "temp\n" +
        "`;\n" +
        "\n" +
        "\n" +
        "     document.addEventListener('DOMContentLoaded', function () {\n" +
        "      var targetElement = document.getElementById('myDiffElement');\n" +
        "      var configuration = {\n" +
        "        drawFileList: true,\n" +
        "        fileListToggle: true,\n" +
        "        fileListStartVisible: true,\n" +
        "        fileContentToggle: true,\n" +
        "        matching: 'lines',\n" +
        "        outputFormat: 'side-by-side',\n" +
        "        synchronisedScroll: true,\n" +
        "        highlight: true,\n" +
        "        renderNothingWhenEmpty: true,\n" +
        "      };\n" +
        "      var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);\n" +
        "      diff2htmlUi.draw();\n" +
        "      diff2htmlUi.highlightCode();\n" +
        "    });\n" +
        "  </script>\n" +
        "  <body>\n" +
        "    <div id=\"myDiffElement\"></div>\n" +
        "  </body>\n" +
        "</html>";
    template = template.replace("temp", builder.toString());
    File f = null; //文件读取为字符流
    //如果htmlPath文件夹不存在则创建
    File folder = new File(htmlPath);
    if (!folder.exists() && !folder.isDirectory()) {
      folder.mkdirs();
    }
    //写入diff.html
    try {
      f = new File(htmlPath + "diff.html");
      BufferedWriter buf = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f), StandardCharsets.UTF_8)); //文件加入缓冲区
      buf.write(template); //向缓冲区写入
      buf.close(); //关闭缓冲区并将信息写入文件
    } catch (IOException e) {
      e.printStackTrace();
    }
  }


  //对字符串中的特殊字符进行转义
  private static String escapeStr(String linStr) {
    //如果含有反斜杠对其转义为\\
    if (linStr.contains("\\")) {
      linStr = linStr.replaceAll("\\\\", "\\\\\\\\");
    }
    //如果含有</script>将其转义为<\/script> ,否则浏览器解析到</script>将报错
    if (linStr.contains("</script>")) {
      linStr = linStr.replaceAll("</script>", "<\\\\/script>");
    }
    //如果含有字符串模板的反引号对其转义为\`
    if (linStr.contains("`")) {
      linStr = linStr.replaceAll("`", "\\\\`");
    }
    //如果含有$符号对其转义为\$
    if (linStr.contains("$")) {
      linStr = linStr.replaceAll("\\$", "\\\\\\$");
    }
    return linStr;
  }

  //统一差异格式插入到原始文件
  public static List<String> insertOrig(List<String> original, List<String> unifiedDiff) {
    List<String> result = new ArrayList<>();
    //unifiedDiff中根据@@分割成不同行,然后加入到diffList中
    List<List<String>> diffList = new ArrayList<>();
    List<String> d = new ArrayList<>();
    for (int i = 0; i < unifiedDiff.size(); i++) {
      String u = unifiedDiff.get(i);
      if (u.startsWith("@@") && !"@@ -0,0 +0,0 @@".equals(u) && !u.contains("@@ -1,")) {
        List<String> twoList = new ArrayList<>();
        twoList.addAll(d);
        diffList.add(twoList);
        d.clear();
        d.add(u);
        continue;
      }
      if (i == unifiedDiff.size() - 1) {
        d.add(u);
        List<String> twoList = new ArrayList<>();
        twoList.addAll(d);
        diffList.add(twoList);
        d.clear();
        break;
      }
      d.add(u);
    }

    //将diffList和原始文件original插入到result,返回result
    for (int i = 0; i < diffList.size(); i++) {
      List<String> diff = diffList.get(i);
      List<String> nexDiff = i == diffList.size() - 1 ? null : diffList.get(i + 1);
      //含有@@的一行
      String simb = i == 0 ? diff.get(2) : diff.get(0);
      String nexSimb = nexDiff == null ? null : nexDiff.get(0);
      //插入到result
      insert(result, diff);
      //解析含有@@的行,得到原文件从第几行开始改变,改变了多少(即增加和减少的行)
      Map<String, Integer> map = getRowMap(simb);
      if (null != nexSimb) {
        Map<String, Integer> nexMap = getRowMap(nexSimb);
        int start = 0;
        if (map.get("orgRow") != 0) {
          start = map.get("orgRow") + map.get("orgDel") - 1;
        }
        int end = nexMap.get("revRow") - 2;
        //插入不变的
        insert(result, getOrigList(original, start, end));
      }

      int start = (map.get("orgRow") + map.get("orgDel") - 1);
      start = start == -1 ? 0 : start;
      if (simb.contains("@@ -1,") && null == nexSimb && map.get("orgDel") != original.size()) {
        insert(result, getOrigList(original, start, original.size() - 1));
      } else if (null == nexSimb && (map.get("orgRow") + map.get("orgDel") - 1) < original.size()) {
        insert(result, getOrigList(original, start, original.size() - 1));
      }
    }
    //如果你想知道两文件有几处不同可以放开下面5行代码注释,会在文件名后显示总的不同点有几处(即预览图中的xxx different),放开注释后有一个小缺点就是如果对比的是java、js等代码文件那代码里的关键字就不会高亮颜色显示,有一点不美观。
    int diffCount = diffList.size() - 1;
    if (!"@@ -0,0 +0,0 @@".equals(unifiedDiff.get(2))) {
      diffCount = diffList.size() > 1 ? diffList.size() : 1;
    }
    result.set(1, result.get(1) + " ( " + diffCount + " different )");
    return result;
  }

  //将源文件中没变的内容插入result
  public static void insert(List<String> result, List<String> noChangeContent) {
    for (String ins : noChangeContent) {
      result.add(ins);
    }
  }

  //解析含有@@的行得到修改的行号删除或新增了几行
  public static Map<String, Integer> getRowMap(String str) {
    Map<String, Integer> map = new HashMap<>();
    if (str.startsWith("@@")) {
      String[] sp = str.split(" ");
      String org = sp[1];
      String[] orgSp = org.split(",");
      //源文件要删除行的行号
      map.put("orgRow", Integer.valueOf(orgSp[0].substring(1)));
      //源文件删除的行数
      map.put("orgDel", Integer.valueOf(orgSp[1]));

      String[] revSp = org.split(",");
      //对比文件要增加行的行号
      map.put("revRow", Integer.valueOf(revSp[0].substring(1)));
      map.put("revAdd", Integer.valueOf(revSp[1]));
    }
    return map;
  }

  //从原文件中获取指定的部分行
  public static List<String> getOrigList(List<String> original1, int start, int end) {
    List<String> list = new ArrayList<>();
    if (original1.size() >= 1 && start <= end && end < original1.size()) {
      for (; start <= end; start++) {
        list.add(original1.get(start));
      }
    }
    return list;
  }
}


测试效果

在这里插入图片描述

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用Spring Boot与Vue.js结合可以实现网页端的可视化展示Spring Boot是一个用于快速构建企业级应用程序的Java开发框架,它简化了Java Web应用的开发过程,并提供了丰富的功能和插件。而Vue.js则是一个轻量级的JavaScript框架,可以方便地构建用户界面。 在使用Spring Boot与Vue.js构建网页端可视化展示时,可以采用前后端分离的架构方式。前端使用Vue.js开发用户界面,通过HTTP请求与后端Spring Boot应用进行数据交互。后端Spring Boot应用则负责处理前端请求,从数据库中获取数据,并将处理结果返回给前端展示。 在前端的Vue.js应用中,可以利用Vue.js的数据驱动特性和组件化开发思想,快速构建出具有交互性和可视化效果的用户界面。可以使用各种第三方可视化组件库,如Echarts、AntV等,来实现图表、地图等各种形式的数据可视化展示后端Spring Boot应用则需要提供RESTful API接口,通过这些接口供前端调用和获取数据。可以使用Spring Boot提供的注解和工具,快速开发出符合业务需求的接口。同时,为了保证应用的安全性和性能,还可以采用Spring Security等框架进行用户认证和授权,以及使用缓存技术进行数据的缓存和优化。 综上所述,使用Spring Boot与Vue.js结合可以实现网页端的可视化展示,通过前后端分离的架构,实现数据的交互和展示。这种方式具有快速开发、易于维护和扩展的特点,适用于各种类型的企业应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

缘不易

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值