java文本对比工具简单封装

功能描述

  由于项目中使用nacos做配置中心,测试环境和生产环境经常出现配置不同导致程序问题。为避免以后此类事情出现,所以要做一个文本对比小工具。

  把工程打包成 可执行  jar,mian方法运行,执行完毕自动打开浏览器输出对比文本内容。

  参考上一篇文章: https://www.cnblogs.com/meow-world/articles/15209517.html

目录:

  1.创建maven工程

  2.创建入口main方法类

  3.读取main方法参数中外部配置文件

  4.读取nacos测试和生产配置文件

  5.对比文本内容

  6.展示对比后有差异的文本

目录结构

  

 

 

1.创建maven工程

  

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>aicloud.com</groupId>
    <artifactId>DiffTools</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>    <dependencies>
        <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
            <version>4.9.0</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.7.10</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.74</version>
        </dependency>
        <!--对比工具依赖-->
        <dependency>
            <groupId>io.github.java-diff-utils</groupId>
            <artifactId>java-diff-utils</artifactId>
            <version>4.9</version>
        </dependency>
    </dependencies>

</project>

 

2.创建入口main方法类

package diff;

import diff.nacos.DiffContent;
import diff.nacos.ReadLocalConfig;
import diff.nacos.ReadResources;
import diff.nacos.ShowDiff;

import java.io.IOException;

/**
 * @date 2021/8/27
 */
public class TestMain {

    private static String path = "D:/temp/test.html";

    public static void main(String[] args) throws IOException {
        String configPath = args[0];
        ReadLocalConfig.readLocalConfig(configPath);
        ReadResources.readNacosConfig();
        DiffContent.diff();
        ShowDiff.show(path);
    }
}

 

3.读取main方法参数中外部配置文件

public class ReadLocalConfig {

    public static String nacosTestUrl;
    public static String nacosTestNameSpaceId;

    public static String nacosProdUrl;
    public static String nacosProdNameSpaceId;

    public static void readLocalConfig(String configPath) throws IOException {
        File file = new File(configPath);
        InputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

        String next;
        while ((next = bufferedReader.readLine()) != null) {
            if (StrUtil.isNotBlank(next)) {
                int index = next.indexOf(":") + 1;
                String substring = next.substring(index).trim();
                if (next.startsWith("nacosTestUrl")) {
                    nacosTestUrl = substring;
                }
                if (next.startsWith("nacosTestNameSpaceId")) {
                    nacosTestNameSpaceId = substring;
                }
                if (next.startsWith("nacosProdUrl")) {
                    nacosProdUrl = substring;
                }
                if (next.startsWith("nacosProdNameSpaceId")) {
                    nacosProdNameSpaceId = substring;
                }
            }
        }

        if (StrUtil.isBlank(nacosTestUrl)) {
            throw new RuntimeException("配置文件地址错误");
        }
    }
}

 

4.读取nacos测试和生产配置

package diff.nacos;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import diff.nacos.model.NacosPerConfig;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static diff.nacos.ReadLocalConfig.*;

/**
 * 读取nacos命令空间下的内容
 * @author wangzhihui
 * @date 2021/8/27
 */
public class ReadResources {

    //读取到的配置问价集合
    //key dataId : value: 文本内容
    public static Map<String, List<String>> configTestMap = new HashMap<>();
    public static Map<String, List<String>> configProdMap = new HashMap<>();

    public static OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

    public static void readNacosConfig() throws IOException {
        List<NacosPerConfig> testList = doRequest(nacosTestUrl, nacosTestNameSpaceId);
        List<NacosPerConfig> prodList = doRequest(nacosProdUrl, nacosProdNameSpaceId);

        testList.forEach(item -> configTestMap.put(item.getDataId(), Arrays.asList(item.getContent().split("\n"))));
        prodList.forEach(item -> configProdMap.put(item.getDataId(), Arrays.asList(item.getContent().split("\n"))));
    }
  
private static List<NacosPerConfig> doRequest(String url, String nameSpaceId) throws IOException { HttpUrl.Builder builder = HttpUrl.parse(url).newBuilder(); builder.addQueryParameter("dataId", null); builder.addQueryParameter("group", null); builder.addQueryParameter("appName", null); builder.addQueryParameter("config_tags", null); builder.addQueryParameter("pageNo", "1"); builder.addQueryParameter("pageSize", "50"); builder.addQueryParameter("tenant", nameSpaceId); builder.addQueryParameter("search", "accurate"); Request request = new Request.Builder() .url(builder.build()) .get() .build(); Response response = okHttpClient.newCall(request).execute(); String jsonStr = response.body().string(); JSONObject jsonObject = JSON.parseObject(jsonStr, JSONObject.class); List<NacosPerConfig> list = jsonObject.getObject("pageItems", new TypeReference<List<NacosPerConfig>>() { }); return list; } }

 

5.对比文本内容

import cn.hutool.core.collection.CollectionUtil;
import com.github.difflib.DiffUtils;
import com.github.difflib.patch.AbstractDelta;
import com.github.difflib.patch.Chunk;
import com.github.difflib.patch.Patch;

import java.util.*;

public class DiffContent {

    public static Map<String, List<String>> ERROR_MAP = new HashMap<>();

    public static void diff() {

        ReadResources.configTestMap.forEach((k, original) -> {
            List<String> revised = ReadResources.configProdMap.get(k);
            if (CollectionUtil.isEmpty(revised)) {
                ERROR_MAP.put(k, Arrays.asList("--- 缺失"));
            }

            if (CollectionUtil.isNotEmpty(revised)) {
                diffDetail(revised, original, k);
            }
        });
    }

public static void diffDetail(List<String> original, List<String> revised, String dataId) {
        Patch<String> diff = DiffUtils.diff(original, revised);
        List<AbstractDelta<String>> deltas = diff.getDeltas();
        List<String> errorList = new LinkedList<>();

        deltas.forEach(delta -> {
            switch (delta.getType()) {
                case INSERT:
                    //新增
                    Chunk<String> insert = delta.getTarget();
                    int position = insert.getPosition();
                    String errorInsert = "+++ " + (position + 1) + " " + insert.getLines();
                    errorList.add(errorInsert);
                    break;
                case CHANGE://修改
                    Chunk<String> source = delta.getSource();
                    Chunk<String> target1 = delta.getTarget();
                    String errorChange = "+-- " + (source.getPosition() + 1) + " " + source.getLines() + "\n+ " + "" + (target1.getPosition() + 1) + " " + target1.getLines();
                    errorList.add(errorChange);
                    break;
                case DELETE:
                    //删除
                    Chunk<String> delete = delta.getSource();
                    String errorDelete = "--- " + (delete.getPosition() + 1) + " " + delete.getLines();
                    errorList.add(errorDelete);
                    break;
                case EQUAL:
                    break;
            }
        });

        ERROR_MAP.put(dataId, errorList);
    }

}

6.展示对比后有差异的文本

import cn.hutool.core.collection.CollectionUtil;

import java.awt.*;
import java.io.*;
import java.net.URI;
import java.nio.charset.StandardCharsets;

public class ShowDiff {

    public static void show(String path) throws IOException {
     //打开默认浏览器
if (Desktop.isDesktopSupported()) { writeData(path); URI uri = URI.create(path); Desktop desktop = Desktop.getDesktop(); if (desktop.isSupported(Desktop.Action.BROWSE)) { desktop.browse(uri); } } } private static void writeData(String path) throws IOException { File file = createFile(path); FileOutputStream fos = new FileOutputStream(file); OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8); osw.write(appendHtmlData()); osw.flush(); } @SuppressWarnings("all") private static File createFile(String path) throws IOException { File file = new File(path); if (!file.exists()) { file.createNewFile(); } return file; } private static String appendHtmlData() { StringBuilder builder = new StringBuilder(); builder.append(htmlPrefix); builder.append("<h1>一、字符说明</h1>"); builder.append("<ul>") .append("<li>").append(deltaInsert).append(":新增").append("</li>") .append("<li>").append(deltaChange).append(":修改").append("</li>") .append("<li>").append(deltaDelete).append(":删除").append("</li>") .append("</ul>"); builder.append("<h1>二、错误列表</h1>"); DiffContent.ERROR_MAP.forEach((k, errorList) -> { if (CollectionUtil.isNotEmpty(errorList)) { builder.append("<p style=\"color:#FF0000\">").append(k).append("</p>"); errorList.forEach(error -> { builder.append(error).append("<br><br>"); }); } }); builder.append(htmlSuffix); return builder.toString(); } private final static String htmlPrefix = "<!DOCTYPE html>\n" + "<html>\n" + "<head>\n" + "<meta charset=\"utf-8\">\n" + "<title>测试/生产配置diff</title>\n" + "</head>\n" + "<body>"; private final static String htmlSuffix = "</body>\n" + "</html>"; private final static String deltaInsert = "+++"; private final static String deltaChange = "+--"; private final static String deltaDelete = "---"; }

 

posted @ 2021-08-31 13:39  meow_world  阅读(1763)  评论(5编辑  收藏  举报