需求场景
内部自研了一套内容管理系统,可以通过Web页面在线修改内容。为了方便对比修改前后差异点,我们需要在Web页面开发一个类似git对比的组件,最终效果如下:
实现方案
我们采用的是Java后台+diff2html前端组件的方案实现的本功能。
diff2html
diff2html是一套渲染类似git文本对比的组件,GitHub地址:https://github.com/rtfpessoa/diff2html
下面是组件官方的一套基于HTML+Javascript的代码实现Demo:
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<!-- Make sure to load the highlight.js CSS file before the Diff2Html CSS file -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css" />
<link
rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"
/>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
</head>
<script>
const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
document.addEventListener('DOMContentLoaded', function () {
var targetElement = document.getElementById('myDiffElement');
var configuration = {
drawFileList: true,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
};
var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
});
</script>
<body>
<div id="myDiffElement"></div>
</body>
</html>
将内容拷贝到任意html中,直接运行,能看到如下效果:
其实从渲染结果来看,diff2html符合我们最终的预期。但上面只是一个示例,const diffString
定义的是常量,我们需要寻找生成diffString变量的方案。
如何生成diffString
diff2html官网关于diffString格式的描述如下:
diff2html accepts the text contents of a unified diff or the superset format git diff (https://git-scm.com/docs/git-diff) (not combined or word diff). To provide multiples files as input just concatenate the diffs (just like the output of git diff).
其意思很明确:diffString等同于git unified diff,类似于git的diff生成效果。我们可以使用git diff特性来生成差异文件。
Springboot生成git unified diff
我们尝试在Springboot下,使用Java程序执行服务器上的git diff命令,代码如下:
@RequestMapping("/gitdiff")
@ResponseBody
public ResultObject gitdiff() throws Exception{
String file1 = "D:\\Develop\\Workspace\\Workspace_ctpstudio\\v5\\a.txt";
String file2 = "D:\\Develop\\Workspace\\Workspace_ctpstudio\\v5\\b.txt";
// 假设 git 命令在系统的 PATH 环境变量中
String[] command = {"git", "diff", "--no-index", file1, file2};
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true); // 合并标准输出和标准错误
try {
Process process = processBuilder.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder output = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
output.append(line).append("\n");
}
int exitCode = process.waitFor();
System.out.println("Exited with error code : " + exitCode);
return ResultObject.success(output.toString());
} catch (Exception e) {
return ResultObject.fail("Error occurred while executing git diff command."+e.getMessage());
}
}
最后为了让前端能获取Springboot Web服务的diff数据,我们可以在html前端通过ajax获取结果数据,前端最终改造代码如下:
<!-- 引入JQuery cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function () {
var url = window.location.href;
var contextPath = url.substring(0, url.indexOf('/', 8));
$.ajax({
url: contextPath+"/restdemo/gitdiff",
type: 'GET',
cache: false,
dataType: 'json',
success: function (data) {
console.log(data);
if (data.code == 200) {
var diffString = data.data;
var targetElement = document.getElementById('myDiffElement');
var configuration = {
drawFileList: true,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
};
var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
}
},
error: function (xhr, status, error) {
console.log(error);
}
});
});
</script>
其它
如果发现页面显示出现了横向滚动条,可以尝试设置div渲染的max-width,如前面demo所示,<div id="myDiffElement">
用于承载显示区域,可以在这个dom增加style为<div id="myDiffElement" style="max-width: 1024px">
,或者js动态设置宽度。
总结
要实现文本对比并在浏览器中可视化渲染,需要完成如下两步:
第一步:服务器安装git,并使用git diff命令生成git unified diff文本结果
第二步:前端获取git unified diff文本,并使用diff2html前端组件渲染结果到Web页面
总的来说,实现还是很简单的,小小总结,希望对大家有帮助。