Json字符串内容比较-超实用版

背景

之前有类似接口diff对比,数据对比的测试需求,涉及到json格式的数据对比,调研了几个大神们分享的代码,选了一个最符合自己需求的研究了下。

说明

这个对比方法,支持JsonObject和JsonArray类型的数据对比,支持:

  • 深度的对比:list变化(个数、内容)、层级结构变化

  • 字段的对比:新增、修改、删除数据可察觉,能找到对应的旧数据

  • 支持特定字段忽略对比

输出的对比结果格式为:

源码分为JsonCompareUtils, JsonAndMapSortUtils两个类,对比入口是compareTwoJson方法

核心逻辑在JsonCompareUtils类中,JsonAndMapSortUtils主要做过程中的数据排序功能,相对独立。

 上源码:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Stream;public class JsonCompareUtils {//标志位:对json报文中含有JsonArray类型的数据是否进行排序private static boolean isSort;private Map<String, Object> oldJsonToMap = new LinkedHashMap<>();private Map<String, Object> newJsonToMap = new LinkedHashMap<>();//每一个实体里的排序字段private static Map<String, String> filedNameMap = new HashMap<>();static {filedNameMap.put("ojb1", "id");filedNameMap.put("ojb2", "id");}//可以跳过比对的字段private static String[] skipCompareFiledNameMap = {"createTime"};/*** 两json报文比对入口** @param oldJsonStr* @param newJsonStr* @return*/public String compare2Json(String oldJsonStr, String newJsonStr) {/*** 递归遍历json对象所有的key-value,以map形式的path:value进行存储* 然后对两个map进行比较*/convertJsonToMap(JSON.parseObject(oldJsonStr), "", false);convertJsonToMap(JSON.parseObject(newJsonStr), "", true);//获取比较结果Map<String, Object> differenceMap = compareTwoMaps(oldJsonToMap, newJsonToMap);String diffJsonResult = convertMapToJson(differenceMap);return diffJsonResult;}/*** 将json数据转换为map存储--用于后续比较map** @param json* @param root* @param isNew 区别新旧报文*/private void convertJsonToMap(Object json, String root, boolean isNew) {if (json instanceof JSONObject) {JSONObject jsonObject = ((JSONObject) json);Iterator iterator = jsonObject.keySet().iterator();while (iterator.hasNext()) {Object key = iterator.next();Object value = jsonObject.get(key);String newRoot = "".equals(root) ? key + "" : root + "." + key;fillInResultMap(value, newRoot, isNew);}} else if (json instanceof JSONArray) {JSONArray jsonArray = (JSONArray) json;//将jsonArray进行排序if (isSort) {//需要排序String sortEntityName = root.substring(root.lastIndexOf(".") + 1);//需要排序 获取排序字段String sortFiledName = filedNameMap.get(sortEntityName);if (!StringUtils.isEmpty(sortFiledName)) {jsonArray = JsonAndMapSortUtils.jsonArrayToSort(jsonArray, sortFiledName, true);}}final JSONArray jsonArray1 = jsonArray;Stream.iterate(0, integer -> integer + 1).limit(jsonArray1.size()).forEach(index -> {Object value = jsonArray1.get(index);String newRoot = "".equals(root) ? "[" + index + "]" : root + ".[" + index + "]";fillInResultMap(value, newRoot, isNew);});}}/*** 封装json转map后的数据** @param value* @param newRoot* @param isNew   区别新旧json*/public void fillInResultMap(Object value, String newRoot, boolean isNew) {if (value instanceof JSONObject || value instanceof JSONArray) {convertJsonToMap(value, newRoot, isNew);} else {//设置跳过比对的字段,直接不装入mapboolean check = ArrayUtils.contains(JsonCompareUtils.skipCompareFiledNameMap, newRoot);if (!check){if (!isNew) {oldJsonToMap.put(newRoot, value);} else {newJsonToMap.put(newRoot, value);}}}}/*** 比较两个map,将不同的数据以map形式存储并返回** @param oldJsonMap* @param newJsonMap* @return*/private Map<String, Object> compareTwoMaps(Map<String, Object> oldJsonMap, Map<String, Object> newJsonMap) {//1.将newJsonMap的不同数据装进oldJsonMap,同时删除oldJsonMap中与newJsonMap相同的数据newJsonMap.forEach((k, v) -> {Map<String, Object> differenceMap = new HashMap<>();if (oldJsonMap.containsKey(k)) {Object oldValue = oldJsonMap.get(k);if (v.equals(oldValue)) {oldJsonMap.remove(k);} else {differenceMap.put("oldValue", oldValue);differenceMap.put("newValue", v);oldJsonMap.put(k, differenceMap);}} else {differenceMap.put("oldValue", "no exists " + k);differenceMap.put("newValue", v);oldJsonMap.put(k, differenceMap);}});//2.统一oldJsonMap中newMap不存在的数据的数据结构,便于解析oldJsonMap.forEach((k, v) -> {if (!(v instanceof Map)) {Map<String, Object> differenceMap = new HashMap<>();differenceMap.put("oldValue", v);differenceMap.put("newValue", "no exists " + k);oldJsonMap.put(k, differenceMap);}});return oldJsonMap;}/*** 将已经找出不同数据的map根据key的层级结构封装成json返回** @param map* @return*/private String convertMapToJson(Map<String, Object> map) {JSONObject resultJSONObject = new JSONObject();for (Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator(); it.hasNext(); ) {Map.Entry<String, Object> item = it.next();String key = item.getKey();Object value = item.getValue();String[] paths = key.split("\\.");int i = 0;//用於深度標識對象Object remarkObject = null;int indexAll = paths.length - 1;while (i <= paths.length - 1) {String path = paths[i];if (i == 0) {//初始化对象标识if (resultJSONObject.containsKey(path)) {remarkObject = resultJSONObject.get(path);} else {if (indexAll > i) {if (paths[i + 1].matches("\\[[0-9]+\\]")) {remarkObject = new JSONArray();} else {remarkObject = new JSONObject();}resultJSONObject.put(path, remarkObject);} else {resultJSONObject.put(path, value);}}i++;continue;}//匹配集合对象if (path.matches("\\[[0-9]+\\]")) {int startIndex = path.lastIndexOf("[");int endIndext = path.lastIndexOf("]");int index = Integer.parseInt(path.substring(startIndex + 1, endIndext));if (indexAll > i) {if (paths[i + 1].matches("\\[[0-9]+\\]")) {while (((JSONArray) remarkObject).size() <= index) {if (((JSONArray) remarkObject).size() == index) {((JSONArray) remarkObject).add(index, new JSONArray());} else {((JSONArray) remarkObject).add(null);}}} else {while (((JSONArray) remarkObject).size() <= index) {if (((JSONArray) remarkObject).size() == index) {((JSONArray) remarkObject).add(index, new JSONObject());} else {((JSONArray) remarkObject).add(null);}}}remarkObject = ((JSONArray) remarkObject).get(index);} else {while (((JSONArray) remarkObject).size() <= index) {if (((JSONArray) remarkObject).size() == index) {((JSONArray) remarkObject).add(index, value);} else {((JSONArray) remarkObject).add(null);}}}} else {if (indexAll > i) {if (paths[i + 1].matches("\\[[0-9]+\\]")) {if (!((JSONObject) remarkObject).containsKey(path)) {((JSONObject) remarkObject).put(path, new JSONArray());}} else {if (!((JSONObject) remarkObject).containsKey(path)) {((JSONObject) remarkObject).put(path, new JSONObject());}}remarkObject = ((JSONObject) remarkObject).get(path);} else {((JSONObject) remarkObject).put(path, value);}}i++;}}return JSON.toJSONString(resultJSONObject);}public boolean isSort() {return isSort;}public void setSort(boolean sort) {isSort = sort;}public static void main(String[] args) {String oldStr = "{\"abilityLevel\":\"2020101240000000000002\",\"activityId\":\"202208301413310000412\",\"addLibTime\":1662083360000,\"ansKnowModelIds\":\"1#201812051814150000475\",\"answer\":\"AB\",\"ascriptionItemLib\":\"0\",\"attributeList\":[{\"content\":\"<p>A</p>\",\"id\":\"202209020949170005783\",\"itemId\":\"202209020949150001521\",\"knowModelRelId\":\"201812051814150000475\",\"name\":\"A\",\"sort\":1,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">B</p>\",\"id\":\"202209020949170005784\",\"itemId\":\"202209020949150001521\",\"name\":\"B\",\"sort\":2,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">C</p>\",\"id\":\"202209020949170005785\",\"itemId\":\"202209020949150001521\",\"name\":\"C\",\"sort\":3,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">D</p>\",\"id\":\"202209020949170005786\",\"itemId\":\"202209020949150001521\",\"name\":\"D\",\"sort\":4,\"type\":\"option\"},{\"content\":\"11\",\"createTime\":1662083368000,\"createTimeString\":\"2022-09-02 09:49:28\",\"creater\":\"10001\",\"id\":\"202209020949170005787\",\"itemId\":\"202209020949150001521\",\"name\":\"大纲依据\",\"searchFlag\":\"1\",\"sort\":1,\"subItemTypeAttrId\":\"100041\",\"type\":\"expandAttr\"},{\"content\":\"11\",\"createTime\":1662083370000,\"createTimeString\":\"2022-09-02 09:49:30\",\"creater\":\"10001\",\"id\":\"202209020949280005788\",\"itemId\":\"202209020949150001521\",\"name\":\"教材依据\",\"searchFlag\":\"1\",\"sort\":2,\"subItemTypeAttrId\":\"100042\",\"type\":\"expandAttr\"},{\"content\":\"11\",\"createTime\":1662083371000,\"createTimeString\":\"2022-09-02 09:49:31\",\"creater\":\"10001\",\"id\":\"202209020949290005789\",\"itemId\":\"202209020949150001521\",\"name\":\"关键字\",\"searchFlag\":\"1\",\"sort\":3,\"subItemTypeAttrId\":\"100043\",\"type\":\"expandAttr\"}],\"auditCount\":0,\"auditStatus\":0,\"childItemList\":[],\"createTime\":1662083350000,\"createTimeString\":\"2022-09-02 09:49:10\",\"creater\":\"10001\",\"delFlag\":\"0\",\"difficult\":\"3\",\"id\":\"202209020949150001521\",\"isComposite\":0,\"isTopVersion\":0,\"itemCode\":\"KJCJ202209020949140001501\",\"itemContent\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">2.<span style=\\\"color: #333333; font-family: Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-size: 14px; text-align: justify; background-color: #FFFFFF;\\\">按照并购双方行业相关性划分,判断并购类型(横向并购or混合并购)</span></p>\",\"itemKnowledgeList\":[{\"id\":\"202209020949300001537\",\"itemId\":\"202209020949150001521\",\"knowledgeId\":\"1240004\",\"knowledgeStr\":\"2020年经济法基础/第一章总论/第一节法律基础/一、法和法律/(一)法和法律的概念\",\"level\":\"1\",\"pid\":\"202209020946580001519\"}],\"itemLevel\":1,\"itemSource\":\"202208301413310000412\",\"itemTypeId\":\"4\",\"itemVersion\":\"1\",\"keyWord\":\"\",\"knowledgeId\":\"1240004\",\"knowledgeStr\":\"2020年经济法基础/第一章总论/第一节法律基础/一、法和法律/(一)法和法律的概念\",\"knowledgeSyllabusName\":\"2020年经济法基础\",\"lockStatus\":1,\"modifyChlidItems\":[],\"paperCount\":0,\"paperItemRelation\":{},\"paperStructure\":{},\"parentId\":\"202209020946580001519\",\"processedItemContent\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">2.<span style=\\\"color: #333333; font-family: Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-size: 14px; text-align: justify; background-color: #FFFFFF;\\\">按照并购双方行业相关性划分,判断并购类型(横向并购or混合并购)</span></p>\",\"score\":2,\"sort\":2,\"sourceType\":\"2\",\"structId\":\"\",\"subItemTypeId\":\"20180228155501000004\",\"subjectId\":\"4\",\"updateTime\":1662083350000,\"updateTimeString\":\"2022-09-02 09:49:10\",\"updater\":\"10001\"}";String newStr = "{\"abilityLevel\":\"2020101240000000000002\",\"activityId\":\"202208301413310000412\",\"addLibTime\":1662083360000,\"analysis\":\"\",\"ansKnowModelIds\":\"1#201812051814150000475\",\"answer\":\"AB\",\"ascriptionItemLib\":\"0\",\"attributeList\":[{\"content\":\"<p>A</p>\",\"id\":\"202209021135210005855\",\"itemId\":\"202209020949150001521\",\"knowModelRelId\":\"201812051814150000475\",\"name\":\"A\",\"sort\":1,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">B</p>\",\"id\":\"202209021135210005856\",\"itemId\":\"202209020949150001521\",\"name\":\"B\",\"sort\":2,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">C</p>\",\"id\":\"202209021135210005857\",\"itemId\":\"202209020949150001521\",\"name\":\"C\",\"sort\":3,\"type\":\"option\"},{\"content\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">D</p>\",\"id\":\"202209021135210005858\",\"itemId\":\"202209020949150001521\",\"name\":\"D\",\"sort\":4,\"type\":\"option\"},{\"content\":\"11\",\"createTime\":1662089721000,\"createTimeString\":\"2022-09-02 11:35:21\",\"creater\":\"10001\",\"id\":\"202209021135210005859\",\"itemId\":\"202209020949150001521\",\"name\":\"大纲依据\",\"searchFlag\":\"1\",\"sort\":1,\"subItemTypeAttrId\":\"100041\",\"type\":\"expandAttr\"},{\"content\":\"11\",\"createTime\":1662089721000,\"createTimeString\":\"2022-09-02 11:35:21\",\"creater\":\"10001\",\"id\":\"202209021135210005860\",\"itemId\":\"202209020949150001521\",\"name\":\"教材依据\",\"searchFlag\":\"1\",\"sort\":2,\"subItemTypeAttrId\":\"100042\",\"type\":\"expandAttr\"},{\"content\":\"11\",\"createTime\":1662089722000,\"createTimeString\":\"2022-09-02 11:35:22\",\"creater\":\"10001\",\"id\":\"202209021135210005861\",\"itemId\":\"202209020949150001521\",\"name\":\"关键字\",\"searchFlag\":\"1\",\"sort\":3,\"subItemTypeAttrId\":\"100043\",\"type\":\"expandAttr\"}],\"auditCount\":0,\"auditStatus\":0,\"childItemList\":[],\"createTime\":1662083350000,\"createTimeString\":\"2022-09-02 09:49:10\",\"creater\":\"10001\",\"delFlag\":\"0\",\"difficult\":\"5\",\"id\":\"202209020949150001521\",\"isComposite\":0,\"isTopVersion\":0,\"itemCode\":\"KJCJ202209020949140001501\",\"itemContent\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">2.<span style=\\\"color: #333333; font-family: Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-size: 14px; text-align: justify; background-color: #FFFFFF;\\\">按照并购双方行业相关性划分,判断并购类型(横向并购or混合并购)</span></p>\",\"itemKnowledgeList\":[{\"id\":\"202209021135230001557\",\"itemId\":\"202209020949150001521\",\"knowledgeId\":\"1240004\",\"knowledgeStr\":\"2020年经济法基础/第一章总论/第一节法律基础/一、法和法律/(一)法和法律的概念\",\"level\":\"1\",\"pid\":\"202209020946580001519\"}],\"itemLevel\":1,\"itemSource\":\"202208301413310000412\",\"itemTypeId\":\"4\",\"itemVersion\":\"2\",\"keyWord\":\"\",\"knowledgeId\":\"1240004\",\"knowledgeStr\":\"2020年经济法基础/第一章总论/第一节法律基础/一、法和法律/(一)法和法律的概念\",\"knowledgeSyllabusName\":\"2020年经济法基础\",\"lockStatus\":1,\"modifyChlidItems\":[],\"paperCount\":0,\"paperItemRelation\":{},\"paperStructure\":{},\"parentId\":\"202209020946580001519\",\"processedItemContent\":\"<p style=\\\"font-family:&#39;Times New Roman&#39;,&#39;宋体&#39;;font-size:12pt;padding:0;margin:0;\\\">2.<span style=\\\"color: #333333; font-family: Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif; font-size: 14px; text-align: justify; background-color: #FFFFFF;\\\">按照并购双方行业相关性划分,判断并购类型(横向并购or混合并购)</span></p>\",\"score\":2,\"sort\":2,\"sourceType\":\"2\",\"structId\":\"\",\"subItemTypeId\":\"20180228155501000004\",\"subjectId\":\"4\",\"updateTime\":1662089720000,\"updateTimeString\":\"2022-09-02 11:35:20\",\"updater\":\"10001\"}";System.out.println(new JsonCompareUtils().compare2Json(oldStr, newStr));System.out.println("\n========测试复杂json的比对============");}
}

JsonAndMapSortUtils 用于jsonArray排序
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import sun.misc.ASCIICaseInsensitiveComparator;import java.util.*;public class JsonAndMapSortUtils {/*** map排序* @param map* @param keySort* @param <k>* @param <v>* @return*/public static <k,v> List mapByKeyToSort(Map<k,v> map , final Comparator keySort){List<Map.Entry<k,v>> entryList = new ArrayList<>(map.entrySet());Collections.sort(entryList, (o1, o2) -> keySort.compare(o1.getKey(),o2.getKey()));System.out.println("排序=====");entryList.forEach(m->{System.out.println(m.getKey()+"===>"+m.getValue());});return entryList;}/*** JSONArray排序* @param jsonArray* @param fildName* @param isAsc* @return*/public static JSONArray jsonArrayToSort(JSONArray jsonArray,final String fildName,final boolean isAsc){JSONArray afterSortJsonArray = new JSONArray();List<JSONObject> objectList = new ArrayList<>();jsonArray.forEach(obj ->{objectList.add((JSONObject)obj);});Collections.sort(objectList, (o1, o2) -> {String fildValueA = o1.getString(fildName);String fildValueB = o2.getString(fildName);if (isAsc){return fildValueA.compareTo(fildValueB);}return fildValueB.compareTo(fildValueA);});objectList.forEach(obj->{afterSortJsonArray.add(obj);});return afterSortJsonArray;}/***准备map测试数据*/public static Map<String,String> getMapData(){LinkedHashMap<String,String> map = new LinkedHashMap<>();map.put("key1","测试1");map.put("key3","测试3");map.put("key5","测试5");map.put("key2","测试2");map.put("key4","测试4");return map;}/***准备json测试数据*/public static JSONArray getJsonArrayData(){JSONArray jsonArray = new JSONArray();JSONObject jsonObject1 = new JSONObject();jsonObject1.put("userId","1001");jsonObject1.put("name","测试1");jsonArray.add(jsonObject1);JSONObject jsonObject3 = new JSONObject();jsonObject3.put("userId","1003");jsonObject3.put("name","测试3");jsonArray.add(jsonObject3);JSONObject jsonObject2 = new JSONObject();jsonObject2.put("userId","1002");jsonObject2.put("name","测试2");jsonArray.add(jsonObject2);return jsonArray;}public static void main(String[] args) {Map<String,String> map = JsonAndMapSortUtils.getMapData();JSONArray jsonArray = JsonAndMapSortUtils.getJsonArrayData();List afterSortMap = JsonAndMapSortUtils.mapByKeyToSort(map,new ASCIICaseInsensitiveComparator());JSONArray afterSortJsonArray_isAsc = JsonAndMapSortUtils.jsonArrayToSort(jsonArray,"userId",true);JSONArray afterSortJsonArray_noAsc = JsonAndMapSortUtils.jsonArrayToSort(jsonArray,"userId",false);System.out.println("map排序前:"+map);System.out.println("map排序后:"+afterSortMap+"\n");System.out.println("JsonArray排序前:"+jsonArray);System.out.println("JsonArray排序后==》升序:"+afterSortJsonArray_isAsc);System.out.println("JsonArray排序后==》降序:"+afterSortJsonArray_noAsc);}}


源码走读
整个源码调用链路如下图,简单来说过程就是:object拆分解析-新旧数据逐个对比-结果信息组装三个步骤

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/102534.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NIFI使用InvokeHTTP发送http请求

说明 这里介绍四种平时常用的http请求方法&#xff1a;GET、POST、PUT、DELETE。 在官方的介绍文档中关于InvokeHTTP处理器的描述是这么说的&#xff1a; An HTTP client processor which can interact with a configurable HTTP Endpoint. The destination URL and HTTP Met…

敏感接口权限校验

前端校验 &#xff08;从前端或者从token里面拿一下&#xff09;&#xff0c;看一下用户有没有这个页面的权限&#xff08;但是一般不用&#xff0c;因为nodejs也可以写后端&#xff0c;但是放到前端去校验不安全&#xff09; 后端校验 需要梳理敏感数据接口&#xff0c;将这…

LeetCode 1004.最大连续1的个数

题目链接 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 题目解析 硬往题目介绍上边去想的话其实非常困难&#xff0c;如果换种方式思考就会简单许多。 若我们将思想转化为&#xff0c;找出最长的子串(里面含有的0的数量最大为k)&#xff0c;然后返…

Python 网页爬虫原理及代理 IP 使用

目录 前言 一、Python 网页爬虫原理 二、Python 网页爬虫案例 步骤1&#xff1a;分析网页 步骤2&#xff1a;提取数据 步骤3&#xff1a;存储数据 三、使用代理 IP 四、总结 前言 随着互联网的发展&#xff0c;网络上的信息量变得越来越庞大。对于数据分析人员和研究人…

vue3:3、项目目录和关键文件

关于vsvode的更改 <!-- 加上setup允许在script中直接编写组合式api --> <script setup> // 组件引入后直接用 import HelloWorld from ./components/HelloWorld.vue import TheWelcome from ./components/TheWelcome.vue</script><!-- 1、js放在最上面&am…

Nginx(动静分离、分配缓冲区、资源缓存、防盗链、资源压缩、IP黑白名单、大文件传输配置、跨域配置、高可用、性能优化)

Nginx&#xff0c;负载均衡&#xff0c;Http反向代理服务器&#xff0c;支持大部分协议&#xff0c;如TCP、UDP、SMTP、HTTPS 环境搭建 Nginx反向代理-负载均衡 首先通过SpringBootFreemarker快速搭建一个WEB项目&#xff1a;springboot-web-nginx&#xff0c;然后在该项目中&…

PlantUML入门教程:画时序图

软件工程中会用到各种UML图&#xff0c;例如用例图、时序图等。那我们能不能像写代码一样去画图呢&#xff1f; 今天推荐一款软件工程师的作图利器--PlantUML&#xff0c;它能让你用写代码的方式快速画出UML图。 一、什么是PlantUML&#xff1f; PlantUML是一个允许你快速作出…

全网超50万粉丝的Linux大咖良许,出书了!

全网超50万粉丝的Linux大咖良许 出书了&#xff01; 今天我们要说的就是这本由Linux领域头部号主&#xff0c;良许老师编写的这本《速学Linux&#xff1a;系统应用从入门到精通》 如果你是刚开始学习Linux的小白同学&#xff0c;相信你已经体会到与学习一门编程语言相比&…

简单斜率优化

凸壳取点 现在平面上有 n n n个点&#xff1a; ( x i , y i ) (x_i,y_i) (xi​,yi​) 现有一次函数&#xff1a; y k x b ykxb ykxb。 要求一次函数必须至少经过平面当中的一个点。则一次函数可以写作&#xff1a; y i k ⋅ x i b y_ik\cdot x_ib yi​k⋅xi​b 如果斜率…

NPM 常用命令(五)

目录 1、npm doctor 1.1 命令 1.2 描述 npm ping npm -v node -v npm config get registry which git 1.3 权限检查 1.4 验证缓存包的校验和 2、npm edit 2.1 命令 2.2 描述 2.3 配置 editor 3、npm exec 3.1 命令 3.2 描述 npx 与 npm exec 3.3 配置 pac…

SQL sever中用户管理

目录 一、用户管理常见方法 二、用户管理方法示例 2.1. 创建登录账户&#xff1a; 2.1.1 检查是否创建账户成功&#xff1a; 2.2. 创建数据库用户&#xff1a; 2.2.1检查用户是否创建成功&#xff1a; 2.3. 授予权限&#xff1a; 2.3.1授予 SELECT、INSERT 和 U…

Ubuntu安装NVIDIA显卡驱动

目录 0. 引言1. 方法1 - 使用系统自带渠道安装2. 方法2 - 手动安装2.1. 卸载原有显卡驱动2.2. 安装显卡驱动2.3. 补救措施 0. 引言 \qquad 第一次入坑的建议看一下这部分。如果说要问我什么时候应该给Ubuntu装显卡驱动&#xff0c;我建议新系统用户第一件事就是安装显卡驱动&am…