背景:在平时的开发中,我们时常会遇到下列场景

  1. 公司的组织架构的数据存储与展示
  2. 文件夹层级的数据存储与展示
  3. 评论系统中,父评论与诸多子评论的数据存储与展示
  4. ......

对于这种有层级的结构化数据,就像是一棵一样。在关系型数据库中,通常将一个个的节点信息存储到表中,通过一个字段(例如,pid),指向其父节点。而在数据展示的时候,我们又希望它是呈现层级的,例如:

id  name        pid
1 总公司 -1
2 上海分公司 1
3 浙江分公司 1
4 闵行区分公司 2
5 嘉兴分公司 3 {
"id": 1,
"name": "总公司",
"pid": -1,
"branch":
[
{
"id": 2,
"name": "上海分公司",
"pid": 1,
"branch":
[
{
"id": 4,
"name": "闵行区分公司",
"pid": 2,
"branch":
[]
}
]
},
{
"id": 3,
"name": "浙江分公司",
"pid": 1,
"branch":
[
{
"id": 5,
"name": "嘉兴分公司",
"pid": 3,
"branch":
[]
}
]
}
]
}

所以,本文的主要内容就是提供几种方案,实现这两类数据的转换方式。

内容导览


存储树的表结构

如何在一张数据库表中表示一颗树结构中的所有节点信息,这里有一个示例:

DROP TABLE IF EXISTS zj_city;
CREATE TABLE zj_city (
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(50) COMMENT '节点名称',
pid int NOT NULL COMMENT '父节点', create_time DATETIME DEFAULT now() COMMENT '创建时间: 年-月-日 时:分:秒',
update_time DATETIME DEFAULT now() ON UPDATE now() COMMENT '更新时间',
is_deleted BIT DEFAULT 0 COMMENT '是否删除:0-false-未删除;1-true-已删除',
PRIMARY KEY (id)
)COMMENT '浙江城市'; INSERT INTO zj_city(name, pid) VALUES
('浙江省',0),
('金华市',1),
('嘉兴市',1),
('杭州市',1),
('宁波市',1); INSERT INTO zj_city(name, pid) VALUES
('下城区',4),
('钱塘区',4),
('西湖区',4),
('上城区',4); INSERT INTO zj_city(name, pid) VALUES
('南湖区',3),
('秀洲区',3),
('桐乡市',3),
('平湖市',3),
('海宁市',3); INSERT INTO zj_city(name, pid) VALUES
('梧桐街道',12),
('凤鸣街道',12),
('龙翔街道',12),
('崇福镇',12),
('乌镇镇',12),
('高桥镇',12),
('河山镇',12),
('濮院镇',12); SELECT * from zj_city;

扁平List转树形List

应用场景

  • 公司组织结构
  • 省市级
  • 评论系统中,父评论与诸多子评论
  • 其他层级展示的数据

双层for

主要思想:外层循环-找父节点;内层循环-找子节点;因为每个元素都会找一遍,所有最终得到完整的树

import com.alibaba.fastjson.JSON;
import com.ks.boot.entity.CityEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.ArrayList;
import java.util.List; public class TreeListDemo {
List<CityEntity> cityEntities;
/**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
@BeforeEach
public void init() {
cityEntities = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0},\n" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1},\n" +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1},\n" +
"{\"id\":4,\"name\":\"南湖\",\"pid\":3},\n" +
"{\"id\":5,\"name\":\"桐乡\",\"pid\":3},\n" +
"{\"id\":6,\"name\":\"余杭\",\"pid\":2},\n" +
"{\"id\":7,\"name\":\"西湖\",\"pid\":2},\n" +
"{\"id\":8,\"name\":\"云南\",\"pid\":0},\n" +
"{\"id\":9,\"name\":\"昆明\",\"pid\":8},\n" +
"{\"id\":10,\"name\":\"昭通\",\"pid\":8}]", CityEntity.class);
} @Test
public void testList2Tree() {
List<CityEntity> resultTree = list2Tree(this.cityEntities);
System.out.println(JSON.toJSONString(resultTree));
} /**
* 双层for,List转Tree
* 主要思想:外层循环-找父节点;内层循环-找子节点;因为每个元素都会找一遍,所有最终得到完整的树
* 时间复杂度:N^2;空间复杂度:N
*/
public List<CityEntity> list2Tree(List<CityEntity> cityEntities) {
List<CityEntity> resultCities = new ArrayList<>();
for (CityEntity city : cityEntities) {
if(0 == city.getPid()) { //根节点、顶级节点,直接放入最终返回结果的List
resultCities.add(city);
}
for (CityEntity curCity : cityEntities) { //根据当前city找它的子节点
if(city.getId().equals(curCity.getPid())) {
if(city.getSubCityList() == null) { //还没有任何子节点,new一个空的放进去
city.setSubCityList(new ArrayList<>());
}
city.getSubCityList().add(curCity);
}
}
} return resultCities;
}
} public class CityEntity {
private Long id;
private String name;
private Long pid; private List<CityEntity> subCityList; getter/setter
}

递归

主要思想:获取所有根节点、顶级节点,再从List中查找根节点的子节点;

import com.alibaba.fastjson.JSON;
import com.ks.boot.entity.CityEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.ArrayList;
import java.util.List; public class TreeListDemo {
List<CityEntity> cityEntities;
/**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
@BeforeEach
public void init() {
cityEntities = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0},\n" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1},\n" +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1},\n" +
"{\"id\":4,\"name\":\"南湖\",\"pid\":3},\n" +
"{\"id\":5,\"name\":\"桐乡\",\"pid\":3},\n" +
"{\"id\":6,\"name\":\"余杭\",\"pid\":2},\n" +
"{\"id\":7,\"name\":\"西湖\",\"pid\":2},\n" +
"{\"id\":8,\"name\":\"云南\",\"pid\":0},\n" +
"{\"id\":9,\"name\":\"昆明\",\"pid\":8},\n" +
"{\"id\":10,\"name\":\"昭通\",\"pid\":8}]", CityEntity.class);
} /**
* 递归,List转Tree
* 主要思想:获取所有根节点、顶级节点,再从List中查找根节点的子节点;
* 时间复杂度:N*(1+N)/2,O(N^2),因为递归方法中,最好是List的第一元素就是要找的子节点,最坏是
* List的最后一个元素是子节点
*/
@Test
public void testList2Tree() {
List<CityEntity> resultCities = new ArrayList<>();
for (CityEntity city : cityEntities) {
if(0 == city.getPid()) { //获取所有根节点、顶级节点,再根据根节点进行递归
CityEntity topCity = findChild(cityEntities, city); //此时的topCity已经包含它的所有子节点
resultCities.add(topCity);
}
} System.out.println(JSON.toJSONString(resultCities));
} /**
*
* @param cityEntities 在那个里面找
* @param curCity 找谁的子节点
* @return curCity的子节点
*/
public CityEntity findChild(List<CityEntity> cityEntities, CityEntity curCity) {
for (CityEntity city : cityEntities) {
if(curCity.getId().equals(city.getPid())) {
if(null == curCity.getSubCityList()) {
curCity.setSubCityList(new ArrayList<>());
}
CityEntity subChild = findChild(cityEntities, city); //每次递归,都从头开始查找有没有city的子节点
curCity.getSubCityList().add(subChild);
}
}
return curCity;
} } public class CityEntity {
private Long id;
private String name;
private Long pid; private List<CityEntity> subCityList; getter/setter
}

转换为Map

主要思想

  • 在双层for的解法中,由于内层for也需要遍历以便List,造成时间复杂度上身为平方级
  • 如果内层for不需要遍历完整的List,而是事先预处理到Map中,寻找时直接从Map中获取,则时间复杂度降为LogN
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; public class TreeListDemo {
List<CityEntity> cityEntities;
/**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
@BeforeEach
public void init() {
cityEntities = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0},\n" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1},\n" +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1},\n" +
"{\"id\":4,\"name\":\"南湖\",\"pid\":3},\n" +
"{\"id\":5,\"name\":\"桐乡\",\"pid\":3},\n" +
"{\"id\":6,\"name\":\"余杭\",\"pid\":2},\n" +
"{\"id\":7,\"name\":\"西湖\",\"pid\":2},\n" +
"{\"id\":8,\"name\":\"云南\",\"pid\":0},\n" +
"{\"id\":9,\"name\":\"昆明\",\"pid\":8},\n" +
"{\"id\":10,\"name\":\"昭通\",\"pid\":8}]", CityEntity.class);
} /**
* 在双层for的解法中,由于内层for也需要遍历以便List,造成时间复杂度上身为平方级
* 如果内层for不需要遍历完整的List,而是事先预处理到Map中,寻找时直接从Map中获取,则时间复杂度降为LogN
*/
@Test
public void list2tree() {
//收集每个PID下的节点为Map
Map<Long, List<CityEntity>> cityMapByPid = cityEntities.stream().collect(Collectors.groupingBy(CityEntity::getPid)); List<CityEntity> resultCityList = new ArrayList<>();
for (CityEntity city : cityEntities) {
if(0 == city.getPid()) { //根节点、顶点
resultCityList.add(city);
} List<CityEntity> citiesByPid = cityMapByPid.get(city.getId());
if(null != citiesByPid && citiesByPid.size() > 0) { //有子节点
if(null == city.getSubCityList()) {
city.setSubCityList(new ArrayList<>());
}
city.getSubCityList().addAll(citiesByPid); //塞入
}
} System.out.println(JSON.toJSONString(resultCityList));
} /**
* 简化写法:在收集到Map时,对于没有子节点的节点,创建一个空的塞入到Map中
*/
@Test
public void list2tree4Simple() {
List<CityEntity> resultCityList = new ArrayList<>(); //保存每个PID下的子节点
Map<Long, List<CityEntity>> cityMapByPid = new HashMap<>();
for (CityEntity city : cityEntities) { //收集每个PID下的子节点
//获取当前PID对应的子节点List,如果没有则创建一个空的List塞入
//这个设计得很巧妙
List<CityEntity> children = cityMapByPid.getOrDefault(city.getPid(), new ArrayList<>());
children.add(city); //插入当前元素
cityMapByPid.put(city.getPid(), children);
} for (CityEntity city : cityEntities) {
if(0 == city.getPid()) { //根节点、顶点
resultCityList.add(city);
}
city.setSubCityList(cityMapByPid.get(city.getId()));
} System.out.println(JSON.toJSONString(resultCityList));
}
}

主要思想

  • 收集根节点、顶级节点,存入resultList,并且压栈
  • 循环出栈,栈元素Cur
    • 找Cur的所有子元素为child
    • 如果child不为空,则再压入栈中。这一步的目的是,再一次找child的子元素
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.*;
import java.util.stream.Collectors; public class TreeListDemo {
List<CityEntity> cityEntities;
/**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
@BeforeEach
public void init() {
cityEntities = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0},\n" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1},\n" +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1},\n" +
"{\"id\":4,\"name\":\"南湖\",\"pid\":3},\n" +
"{\"id\":5,\"name\":\"桐乡\",\"pid\":3},\n" +
"{\"id\":6,\"name\":\"余杭\",\"pid\":2},\n" +
"{\"id\":7,\"name\":\"西湖\",\"pid\":2},\n" +
"{\"id\":8,\"name\":\"云南\",\"pid\":0},\n" +
"{\"id\":9,\"name\":\"昆明\",\"pid\":8},\n" +
"{\"id\":10,\"name\":\"昭通\",\"pid\":8}]", CityEntity.class);
} /**
* 主要思想:
* 收集根节点、顶级节点,存入resultList,并且压栈
* 循环出栈,栈元素Cur
* 找Cur的所有子元素为child
* 如果child不为空,则再压入栈中。这一步的目的是,再一次找child的子元素
* 时间复杂度:N(过滤出所有跟节点) + 常数(出栈) * N(遍历List找当前节点的子元素)
*/
@Test
public void list2tree() {
List<CityEntity> resultCityList = new ArrayList<>(); Stack<CityEntity> stack = new Stack<>();
resultCityList = cityEntities.stream().filter(ele -> 0 == ele.getPid()).collect(Collectors.toList());
stack.addAll(resultCityList); //根节点、顶点入栈 while(!stack.isEmpty()) {
CityEntity curCity = stack.pop();
List<CityEntity> child = cityEntities.stream().filter(ele -> curCity.getId().equals(ele.getPid())).collect(Collectors.toList());
if(!child.isEmpty()) { //这一步处理的原因是:当没有子元素,不显示该个字段。流处理后没有元素只会返回空List,不会返回null
curCity.setSubCityList(child);
}
if(!child.isEmpty()) {
stack.addAll(child);
}
} System.out.println(JSON.toJSONString(resultCityList));
}
}

树形List转扁平List

递归

主要思想:遍历树节点,一个树节点如果有子树,则再次递归此子树,直到没有子树为止

import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.ArrayList;
import java.util.List; /**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
public class ListTreeDemo {
List<CityEntity> treeList; @BeforeEach
public void init() {
treeList = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0,\"subCityList\":[" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1,\"subCityList\":[{\"id\":6,\"name\":\"余杭\",\"pid\":2},{\"id\":7,\"name\":\"西湖\",\"pid\":2}]}," +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1,\"subCityList\":[{\"id\":4,\"name\":\"南湖\",\"pid\":3},{\"id\":5,\"name\":\"桐乡\",\"pid\":3}]}]}," +
"{\"id\":8,\"name\":\"云南\",\"pid\":0,\"subCityList\":[{\"id\":9,\"name\":\"昆明\",\"pid\":8},{\"id\":10,\"name\":\"昭通\",\"pid\":8}]}]", CityEntity.class);
} @Test
public void tree2list() {
List<CityEntity> resList = new ArrayList<>(); //这一层for的目的是:遍历根节点
for (CityEntity city : treeList) {
reversion(city,resList);
}
System.out.println(JSON.toJSONString(resList));
}
public void reversion(CityEntity curNode, List<CityEntity> resList) {
resList.add(beanCopy(curNode)); List<CityEntity> subCityList = curNode.getSubCityList();
if(subCityList != null && !subCityList.isEmpty()) {
for (CityEntity city : subCityList) { //递归寻找子节点的子节点们
reversion(city, resList);
}
} //递归的出口就是subCityList为null或者empty
} private CityEntity beanCopy(CityEntity source) {
CityEntity res = new CityEntity();
res.setId(source.getId());
res.setName(source.getName());
res.setPid(source.getPid());
return res;
}
}

主要思想

  1. 依次遍历树形List,当前节点为Cur

    1. 将Cur收集到某个存储结果的List
    2. 如果Cur有子树,压入某个栈中
  2. 依次弹出栈元素,当前弹出的元素为StackSubTree
    1. 如果StackSubTree还有子树,继续压栈
    2. 如果StackSubTree没有子树,则放入结果List
import com.alibaba.fastjson2.JSON;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import java.util.ArrayList;
import java.util.List;
import java.util.Stack; /**
* id name pid
* 1 浙江 0
* 2 杭州 1
* 3 嘉兴 1
* 4 南湖 3
* 5 桐乡 3
* 6 余杭 2
* 7 西湖 2
* 8 云南 0
* 9 昆明 8
* 10 昭通 8
*/
public class ListTreeDemo {
List<CityEntity> treeList; @BeforeEach
public void init() {
treeList = JSON.parseArray("[{\"id\":1,\"name\":\"浙江\",\"pid\":0,\"subCityList\":[" +
"{\"id\":2,\"name\":\"杭州\",\"pid\":1,\"subCityList\":[{\"id\":6,\"name\":\"余杭\",\"pid\":2},{\"id\":7,\"name\":\"西湖\",\"pid\":2}]}," +
"{\"id\":3,\"name\":\"嘉兴\",\"pid\":1,\"subCityList\":[{\"id\":4,\"name\":\"南湖\",\"pid\":3},{\"id\":5,\"name\":\"桐乡\",\"pid\":3}]}]}," +
"{\"id\":8,\"name\":\"云南\",\"pid\":0,\"subCityList\":[{\"id\":9,\"name\":\"昆明\",\"pid\":8},{\"id\":10,\"name\":\"昭通\",\"pid\":8}]}]", CityEntity.class);
} /**
* 1. 依次遍历树形List,当前节点为Cur
* a) 将Cur收集到某个存储结果的List
* b) 如果Cur有子树,压入某个栈中
* 2. 依次弹出栈元素,当前弹出的元素为StackSubTree
* a) 如果StackSubTree还有子树,继续压栈
* b) 如果StackSubTree没有子树,则放入结果List
*/
@Test
public void tree2list() {
List<CityEntity> resList = new ArrayList<>(); Stack<List<CityEntity>> stack = new Stack<>(); for (CityEntity curCity : treeList) {
resList.add(beanCopy(curCity));
if (curCity.getSubCityList() != null && !curCity.getSubCityList().isEmpty()) {
stack.push(curCity.getSubCityList());
}
} while (!stack.isEmpty()) {
List<CityEntity> subTree = stack.pop();
for (CityEntity city : subTree) {
if (city.getSubCityList() != null && !city.getSubCityList().isEmpty()) {
stack.push(city.getSubCityList());
} else {
resList.add(beanCopy(city));
}
}
} System.out.println(JSON.toJSONString(resList));
} private CityEntity beanCopy(CityEntity source) {
CityEntity res = new CityEntity();
res.setId(source.getId());
res.setName(source.getName());
res.setPid(source.getPid());
return res;
}
}

"树形List"与"扁平List"互转(Java实现)的更多相关文章

  1. .net互转java 转行必备

    .net与java其实是差不多的语言,学习起来只需要弄清楚差异及查库的方法,转起来还是很快的 以下列出几点,希望能给正在转行的你一些帮助 1,java与c#语言超详细对比 http://www.har ...

  2. 树形结构数据存储方案的选择和java list转tree

    树形结构数据存储方案 Adjacency List:每一条记录存parent_idPath Enumerations:每一条记录存整个tree path经过的node枚举Nested Sets:每一条 ...

  3. 2019 三七互娱java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.三七互娱等公司offer,岗位是Java后端开发,因为发展原因最终选择去了三七互娱,入职一年时间了,也成为了面 ...

  4. 最新 三七互娱java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.三七互娱等10家互联网公司的校招Offer,因为某些自身原因最终选择了三七互娱.6.7月主要是做系统复习.项目复盘.Leet ...

  5. js树形数据结构的扁平化

    前面我们封装了一维数组(具备树形结构相关属性)处理成树形结构的方法:https://www.cnblogs.com/coder--wang/p/15013664.html 接下来我们来一波反向操作,封 ...

  6. 牛客网程序员面试金典:1.1确定字符互异(java实现)

    问题描述: 请实现一个算法,确定一个字符串的所有字符是否全都不同.这里我们要求不允许使用额外的存储结构. 给定一个string iniString,请返回一个bool值,True代表所有字符全都不同, ...

  7. js格式化树形数据(扁平化数据)

    需求: 1.把如下数据按照parent_id等于id的规则建立父子关系 2.同一层级的数组按照order升序 [ { "id": 1, "name": &quo ...

  8. 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的互转 JAVA

    package com.asiabasehk.cgg.util;   /**火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的互转  * Created by macremote on 1 ...

  9. JSON字符串和java对象的互转【json-lib】

    在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级的数据格式比xml效率要高,XML需要很多的标签,这无疑占据了网络流量,JSON在这方面则做的很好, ...

  10. json字符串与java对象互转

    在开发过程中,经常需要和别的系统交换数据,数据交换的格式有XML.JSON等,JSON作为一个轻量级的数据格式比xml效率要高,XML需要很多的标签,这无疑占据了网络流量,JSON在这方面则做的很好, ...

随机推荐

  1. c输入的缓冲区

    作业题:输入两个整数(12和37),从键盘输入'A'和'a'时,输出两个数中的较大数:从键盘输入'B'和'b'时,输出两个数中的较小数. int a; char c; scanf("%d&q ...

  2. What is Weight Lifting?

    Weight lifting is the process of lifting items of great mass in order to increase the muscle size an ...

  3. 1.3 ODBC 部署监控数据库

    一.安装ODBC 来自为知笔记(Wiz)

  4. burpsuite 设置文字大小、抓取https数据头

    设置文字大小 burpsuite安装好后,有些时候文字非常的小,看的眼睛直接痛死. 找到 User options -> Display 其中 User Interface -> Font ...

  5. return、break与continue的区别

    前言 在上一篇文章中,壹哥给大家介绍了while.do-while两种循环结构,并且给大家总结了两种循环的区别.实际上,我们在利用循环执行重复操作的过程中,还存在着另一个需求:如何中止,或者说提前结束 ...

  6. Java BIO,NIO,AIO

    一丶IO模型&Java IO Unix为程序员提供了以下5种基本的io模型: blocking io: 阻塞io nonblocking io: 非阻塞io I/O multiplexing: ...

  7. 你绝对没想到的GPT的底层意义

    学会说话才是完整的人 有种说法在民间流传已久,在某些非洲部落中,孩子出生后往往会被称作"小人"或者"半个人",直到他们能够进行语言的交流才被认为是完全的人.这是 ...

  8. [Linux]常用命令之【tar/zip/unzip/gzip/gunzip】

    1 tar .tar与.gz有什么联系与区别? .tar 只是进行打包,并没有压缩. 则: 用tar-cvf进行打包 用tar-xvf进行解包. .tar.gz 是既打包又压缩 ,则: tar –cz ...

  9. [Git]解决GIT冲突问题:git pull failed

    1 文由 花了很长时间一次性修改了项目的一大堆文件,准备最后git pull同步一下本地仓库代码,再一次性git commit,git push新代码的. but天不遂人愿,git pull时产生冲突 ...

  10. day05-SpringCloud Eureka-服务注册与发现02

    SpringCloud Eureka-服务注册与发现02 3.搭建EurekaServer集群-实现负载均衡&故障容错 3.1为什么需要集群EurekaServer? 微服务RPC远程服务调用 ...