list轉(zhuǎn)tree和list中查找某節(jié)點(diǎn)下的所有數(shù)據(jù)操作
類(lèi)的實(shí)例化順序
父類(lèi)靜態(tài)變量、 父類(lèi)靜態(tài)代碼塊、 子類(lèi)靜態(tài)變量、 子類(lèi)靜態(tài)代碼塊、
父類(lèi)非靜態(tài)變量(父類(lèi)實(shí)例成員變量)、 父類(lèi)構(gòu)造函數(shù)、 子類(lèi)非靜態(tài)變量(子類(lèi)實(shí)例成員變量)、 子類(lèi)構(gòu)造函數(shù)。
已知組織類(lèi)Org{String id,String name,String parentId},現(xiàn)在一List<Org>中存放無(wú)序的Org數(shù)據(jù),求一個(gè)組織id下的所有組織。
public static List<Org> childList=new ArrayList<>();
public static List<Org> findChild(List<Org> list,String id){
for (Org org:list){
if(org.getParentId().equals(id)){
childList.add(org);
findChild(list,org.getId()); //遞歸實(shí)現(xiàn)
}
}
return childList;
}
list轉(zhuǎn)tree:
// node一開(kāi)始為根節(jié)點(diǎn)
public static TreeNode listToTree(TreeNode node, List<TreeNode> sourceLit){
// 重根節(jié)點(diǎn)開(kāi)始
for (TreeNode sourceNode : sourceLit){
if (sourceNode.getpId() == node.getId()){
if(node.getChildrenList() == null){
node.setChildrenList(new ArrayList<TreeNode>());
}
node.getChildrenList().add(listToTree(sourceNode, sourceLit));
}
}
return node;
}
補(bǔ)充知識(shí):Java實(shí)現(xiàn)樹(shù)數(shù)據(jù)Tree與List互轉(zhuǎn)并逐級(jí)匯總節(jié)點(diǎn)的值(支持樹(shù)節(jié)點(diǎn)多列統(tǒng)計(jì))
主要需求:a.實(shí)現(xiàn)樹(shù)Tree與List互轉(zhuǎn) b.Tree實(shí)現(xiàn)多列統(tǒng)計(jì)數(shù)據(jù)匯總。前度采用MiniUI。
逐級(jí)匯總數(shù)據(jù):找到最小節(jié)點(diǎn),然后回溯其所有父節(jié)點(diǎn),注意值的重復(fù)計(jì)算問(wèn)題。


構(gòu)造一棵樹(shù)的基本節(jié)點(diǎn):
package com.example.demo.tree;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: TreeNode
* @Description: TODO(樹(shù)的節(jié)點(diǎn)對(duì)象)
* @author: pengjunlin
* @motto: 學(xué)習(xí)需要毅力,那就秀毅力
* @date 2019-06-18 23:35
*/
public class TreeNode {
/**
* 節(jié)點(diǎn)ID
*/
private long id;
/**
* 顯示名稱
*/
private String label;
/**
* 當(dāng)前節(jié)點(diǎn)的唯一值
*/
private double value;
/**
* 當(dāng)前節(jié)點(diǎn)的多個(gè)值的表達(dá)方式
*/
private double[] multiValues=new double[]{};
/**
* 匯總單個(gè)節(jié)點(diǎn)的多個(gè)值
*/
private List<Double> values=new ArrayList<Double>();
/**
* 當(dāng)前節(jié)點(diǎn)所有子節(jié)點(diǎn)的值集合
*/
private List<double []> childrenMultiValues=new ArrayList<double []>();
/**
* 父節(jié)點(diǎn)ID
*/
private long pid;
/**
* 子節(jié)點(diǎn)集合對(duì)象
*/
private List<TreeNode> children=new ArrayList<TreeNode>();
/**
* 是否計(jì)算本身
*/
private boolean addSelf=false;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public double[] getMultiValues() {
return multiValues;
}
public void setMultiValues(double[] multiValues) {
this.multiValues = multiValues;
}
public List<Double> getValues() {
return values;
}
public void setValues(List<Double> values) {
this.values = values;
}
public List<double[]> getChildrenMultiValues() {
return childrenMultiValues;
}
public void setChildrenMultiValues(List<double[]> childrenMultiValues) {
this.childrenMultiValues = childrenMultiValues;
}
public long getPid() {
return pid;
}
public void setPid(long pid) {
this.pid = pid;
}
public List<TreeNode> getChildren() {
return children;
}
public void setChildren(List<TreeNode> children) {
this.children = children;
}
public boolean isAddSelf() {
return addSelf;
}
public void setAddSelf(boolean addSelf) {
this.addSelf = addSelf;
}
}
構(gòu)造樹(shù)管理工具:
package com.example.demo.tree;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName: TreeManager
* @Description: TODO(樹(shù)結(jié)構(gòu)數(shù)據(jù)管理-實(shí)踐驗(yàn)證)
* @author: pengjunlin
* @motto: 學(xué)習(xí)需要毅力,那就秀毅力
* @date 2019-06-18 23:47
*/
public class TreeManager {
/**
* 將List轉(zhuǎn)成tree結(jié)構(gòu)數(shù)據(jù)
* @param list
* @param rootId 默認(rèn)頂級(jí)節(jié)點(diǎn)ID
* @return
*/
public static List<TreeNode> listToTree(List<TreeNode> list,long rootId){
List<TreeNode> tree=new ArrayList<TreeNode>();
Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
// 將所有的數(shù)據(jù),以鍵值對(duì)的形式裝入map中
for (TreeNode node : list) {
// 去除冗余的子節(jié)點(diǎn)
node.setChildren(new ArrayList<TreeNode>());
map.put(node.getId(), node);
}
for (TreeNode node : list) {
// 如果id是父級(jí)的話就放入tree中
if (node.getId() == rootId) {
tree.add(node);
} else {
// 子級(jí)通過(guò)父id獲取到父級(jí)的類(lèi)型
TreeNode parent = map.get(node.getPid());
// 父級(jí)獲得子級(jí),再將子級(jí)放到對(duì)應(yīng)的父級(jí)中
if(parent!=null){
parent.getChildren().add(node);
}
}
}
return tree;
}
/**
* 將tree結(jié)構(gòu)數(shù)據(jù)轉(zhuǎn)成List結(jié)構(gòu)
* @param list
* @return
*/
public static void treeToList(TreeNode node,List<TreeNode> list){
if(list==null){
list=new ArrayList<TreeNode>();
}
//設(shè)置當(dāng)前節(jié)點(diǎn)的必要數(shù)據(jù)
TreeNode nodeValue=new TreeNode();
nodeValue.setId(node.getId());
nodeValue.setLabel(node.getLabel());
nodeValue.setValue(node.getValue());
nodeValue.setMultiValues(node.getMultiValues());
nodeValue.setChildrenMultiValues(node.getChildrenMultiValues());
nodeValue.setPid(node.getPid());
nodeValue.setChildren(new ArrayList<TreeNode>());
list.add(nodeValue);
//遍歷遞歸子節(jié)點(diǎn)
if(node.getChildren().size()>0){
for (int i = 0; i < node.getChildren().size(); i++) {
TreeNode node_= node.getChildren().get(i);
treeToList(node_,list);
}
}
}
/**
* 轉(zhuǎn)換數(shù)據(jù)格式并設(shè)置對(duì)應(yīng)節(jié)點(diǎn)的值匯總到根節(jié)點(diǎn)
* @param list
* @param rootId
* @return
*/
public static List<TreeNode> listToTreeWithSingleValue(List<TreeNode> list,long rootId){
Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
// 將所有的數(shù)據(jù),以鍵值對(duì)的形式裝入map中
for (TreeNode node : list) {
// 去除冗余的子節(jié)點(diǎn)
node.setChildren(new ArrayList<TreeNode>());
map.put(node.getId(), node);
}
List<TreeNode> tree=listToTree(list,rootId);
/* // 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leafList=new HashMap<Long,Object>();
findMinNodes(tree.get(0),leafList,0);
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leafList.keySet()) {
// 內(nèi)部遞歸樹(shù)的父節(jié)點(diǎn)層級(jí)多于2會(huì)存在重復(fù)計(jì)算
setParentNodeValue(map,id_);
}*/
// 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leaf=new HashMap<Long,Object>();
findMinNodes(tree.get(0),leaf);
// 逐級(jí)設(shè)置父節(jié)點(diǎn)的值
setValuesToParentNode(leaf, map);
// 匯總所有節(jié)點(diǎn)的值
double total=0;
for (TreeNode node:map.values() ) {
total=0;
for (double value: node.getValues() ) {
total+=value;
}
node.setValue(total);
map.put(node.getId(),node);
}
List<TreeNode> result=new ArrayList<TreeNode>();
for (TreeNode node:map.values()) {
result.add(node);
}
return listToTree(result,rootId);
}
/**
* 轉(zhuǎn)換數(shù)據(jù)格式并設(shè)置對(duì)應(yīng)節(jié)點(diǎn)的值匯總到根節(jié)點(diǎn)
* @param tree
* @return
*/
public static List<TreeNode> treeToListWithSingleValue(TreeNode tree){
List<TreeNode> list=new ArrayList<TreeNode>();
// 獲取到List
treeToList(tree,list);
Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
// 將所有的數(shù)據(jù),以鍵值對(duì)的形式裝入map中
for (TreeNode node : list) {
// 去除冗余的子節(jié)點(diǎn)
node.setChildren(new ArrayList<TreeNode>());
map.put(node.getId(), node);
}
/* // 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leafList=new HashMap<Long,Object>();
findMinNodes(tree,leafList,0);
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leafList.keySet()) {
// 內(nèi)部遞歸樹(shù)的父節(jié)點(diǎn)層級(jí)多于2會(huì)存在重復(fù)計(jì)算
setParentNodeValue(map,id_);
}*/
// 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leaf=new HashMap<Long,Object>();
findMinNodes(tree,leaf);
// 逐級(jí)設(shè)置父節(jié)點(diǎn)的值
setValuesToParentNode(leaf, map);
// 匯總所有節(jié)點(diǎn)的值
double total=0;
for (TreeNode node:map.values() ) {
total=0;
for (double value: node.getValues() ) {
total+=value;
}
node.setValue(total);
map.put(node.getId(),node);
}
List<TreeNode> result=new ArrayList<TreeNode>();
for (TreeNode node:map.values()) {
result.add(node);
}
return result;
}
/**
* 轉(zhuǎn)換數(shù)據(jù)格式并設(shè)置對(duì)應(yīng)節(jié)點(diǎn)的值匯總到根節(jié)點(diǎn)
* @param list
* @param rootId
* @param columns
* @return
*/
public static List<TreeNode> listToTreeWithMultiValues(List<TreeNode> list,long rootId,int columns){
Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
// 將所有的數(shù)據(jù),以鍵值對(duì)的形式裝入map中
for (TreeNode node : list) {
// 去除冗余的子節(jié)點(diǎn)
node.setChildren(new ArrayList<TreeNode>());
map.put(node.getId(), node);
}
List<TreeNode> tree=listToTree(list,rootId);
/* // 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leafList=new HashMap<Long,Object>();
findMinNodes(tree.get(0),leafList,0);
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leafList.keySet()) {
// 內(nèi)部遞歸樹(shù)的父節(jié)點(diǎn)層級(jí)多于2會(huì)存在重復(fù)計(jì)算
setParentNodeMultiValues(map,id_);
}*/
// 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leaf=new HashMap<Long,Object>();
findMinNodes(tree.get(0),leaf);
// 逐級(jí)追加父節(jié)點(diǎn)的值
setMultiValuesToParentNode(leaf, map);
// 匯總所有節(jié)點(diǎn)的值
double [] valueColumns=null;
for (TreeNode node:map.values() ) {
valueColumns=new double[columns];
for (double [] values: node.getChildrenMultiValues() ) {
for (int i = 0,j=values.length; i < j; i++) {
valueColumns[i]+=values[i];
}
}
node.setMultiValues(valueColumns);
map.put(node.getId(),node);
}
List<TreeNode> result=new ArrayList<TreeNode>();
for (TreeNode node:map.values()) {
result.add(node);
}
return listToTree(result,rootId);
}
/**
* 轉(zhuǎn)換數(shù)據(jù)格式并設(shè)置對(duì)應(yīng)節(jié)點(diǎn)的值匯總到根節(jié)點(diǎn)
* @param tree
* @param columns
* @return
*/
public static List<TreeNode> treeToListWithMultiValues(TreeNode tree,int columns){
List<TreeNode> list=new ArrayList<TreeNode>();
// 獲取到List
treeToList(tree,list);
Map<Long, TreeNode> map = new HashMap<Long, TreeNode>();
// 將所有的數(shù)據(jù),以鍵值對(duì)的形式裝入map中
for (TreeNode node : list) {
// 去除冗余的子節(jié)點(diǎn)
node.setChildren(new ArrayList<TreeNode>());
map.put(node.getId(), node);
}
/*
// 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leafList=new HashMap<Long,Object>();
findMinNodes(tree,leafList,0);
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leafList.keySet()) {
// 內(nèi)部遞歸樹(shù)的父節(jié)點(diǎn)層級(jí)多于2會(huì)存在重復(fù)計(jì)算
setParentNodeMultiValues(map,id_);
}*/
// 存儲(chǔ)最小子節(jié)點(diǎn)ID
Map<Long,Object> leaf=new HashMap<Long,Object>();
findMinNodes(tree,leaf);
// 逐級(jí)追加父節(jié)點(diǎn)的值
setMultiValuesToParentNode(leaf, map);
// 匯總所有節(jié)點(diǎn)的值
double [] valueColumns=null;
for (TreeNode node:map.values() ) {
valueColumns=new double[columns];
for (double [] values: node.getChildrenMultiValues() ) {
for (int i = 0,j=values.length; i < j; i++) {
valueColumns[i]+=values[i];
}
}
node.setMultiValues(valueColumns);
map.put(node.getId(),node);
}
List<TreeNode> result=new ArrayList<TreeNode>();
for (TreeNode node:map.values()) {
result.add(node);
}
return result;
}
/**
* 逐級(jí)追加設(shè)置節(jié)點(diǎn)的值(單個(gè)值)
* @param leaf
* @param map
*/
public static void setValuesToParentNode(Map<Long,Object> leaf,Map<Long, TreeNode> map){
Map<Long,Object> newLeaf=new HashMap<Long,Object>();
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leaf.keySet()) {
setParentNodeValue(newLeaf,map,id_);
}
if(newLeaf.size()>1){
setValuesToParentNode(newLeaf, map);
}
}
/**
* 逐級(jí)追加設(shè)置節(jié)點(diǎn)的值(多個(gè)值)
* @param leaf
* @param map
*/
public static void setMultiValuesToParentNode( Map<Long,Object> leaf,Map<Long, TreeNode> map){
Map<Long,Object> newLeaf=new HashMap<Long,Object>();
// 設(shè)置每個(gè)節(jié)點(diǎn)的值
for (Long id_: leaf.keySet()) {
setParentNodeMultiValues(newLeaf,map,id_);
}
if(newLeaf.size()>1){
setMultiValuesToParentNode(newLeaf, map);
}
}
/**
* 數(shù)學(xué)運(yùn)算
* @param mathChar
* @param dest
* @param newValue
*/
public static void mathHandle(String mathChar,double dest,double newValue){
switch (mathChar) {
case "+":
dest+=newValue;
break;
case "-":
dest-=newValue;
break;
case "*":
dest*=newValue;
break;
case "/":
dest/=newValue;
break;
default:
break;
}
}
/**
* 查找最小子葉節(jié)點(diǎn)(沒(méi)有子節(jié)點(diǎn)的節(jié)點(diǎn))
* @param node
* @param leafList
*/
private static void findMinNodes(TreeNode node,Map<Long,Object> leafList){
if(node.getChildren().size()>0){
TreeNode nodeTmp=null;
for (int i = 0; i < node.getChildren().size(); i++) {
nodeTmp= node.getChildren().get(i);
findMinNodes(nodeTmp,leafList);
}
}else{
leafList.put(node.getId(),node.getId());
}
}
/**
* 根據(jù)ID逐級(jí)查找父節(jié)點(diǎn)并設(shè)置值(設(shè)置單個(gè)值逐級(jí)遞歸)
* @param map
* @param id
*/
private static void setParentNodeValue(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
TreeNode node=map.get(id);
// 設(shè)置自身節(jié)點(diǎn)的值
if(!node.isAddSelf()){
node.setAddSelf(true);
node.getValues().add(node.getValue());
// 更新節(jié)點(diǎn)數(shù)據(jù)
map.put(node.getId(),node);
}
TreeNode pNode=map.get(node.getPid());
if(pNode!=null){
// 將子節(jié)點(diǎn)的值賦給父節(jié)點(diǎn)
pNode.getValues().addAll(node.getValues());
// 設(shè)置自身節(jié)點(diǎn)的值
if(!pNode.isAddSelf()){
pNode.setAddSelf(true);
pNode.getValues().add(pNode.getValue());
}
// 更新節(jié)點(diǎn)數(shù)據(jù)
map.put(pNode.getId(),pNode);
//setParentNodeValue(map,pNode.getId());
newLeaf.put(pNode.getId(), pNode.getId());
}
}
/**
* 根據(jù)ID逐級(jí)查找父節(jié)點(diǎn)并設(shè)置值(設(shè)置多個(gè)值逐級(jí)遞歸)
* @param map
* @param id
*/
private static void setParentNodeMultiValues(Map<Long,Object> newLeaf,Map<Long, TreeNode> map,long id){
TreeNode node=map.get(id);
// 設(shè)置自身節(jié)點(diǎn)的值
if(!node.isAddSelf()){
node.setAddSelf(true);
node.getChildrenMultiValues().add(node.getMultiValues());
// 更新節(jié)點(diǎn)數(shù)據(jù)
map.put(node.getId(),node);
}
TreeNode pNode=map.get(node.getPid());
if(pNode!=null){
// 將子節(jié)點(diǎn)的值賦給父節(jié)點(diǎn)
pNode.getChildrenMultiValues().addAll(node.getChildrenMultiValues());
// 設(shè)置自身節(jié)點(diǎn)的值
if(!pNode.isAddSelf()){
pNode.setAddSelf(true);
pNode.getChildrenMultiValues().add(pNode.getMultiValues());
}
// 更新節(jié)點(diǎn)數(shù)據(jù)
map.put(pNode.getId(),pNode);
//setParentNodeMultiValues(map,pNode.getId());
newLeaf.put(pNode.getId(), pNode.getId());
}
}
@SuppressWarnings("unused")
public static void main(String[] args) {
TreeNode tree=new TreeNode();
tree.setId(1);
tree.setLabel("頂層節(jié)點(diǎn)");
tree.setValue(1);
tree.setChildrenMultiValues(new ArrayList<double []>());
tree.setPid(0);
List<TreeNode> list =new ArrayList<TreeNode>();
TreeNode node1=new TreeNode();
node1.setId(2);
node1.setLabel("子節(jié)點(diǎn)1");
node1.setValue(100);
node1.setMultiValues(new double[]{5,7,3});
node1.setChildrenMultiValues(new ArrayList<double []>());
node1.setPid(1);
list.add(node1);
TreeNode node2=new TreeNode();
node2.setId(3);
node2.setLabel("子節(jié)點(diǎn)2");
node2.setValue(10);
node2.setMultiValues(new double[]{2,5,8});
node2.setChildrenMultiValues(new ArrayList<double []>());
node2.setPid(1);
list.add(node2);
tree.setChildren(list);
List<TreeNode> destList=new ArrayList<TreeNode>();
TreeManager.treeToList(tree,destList);
System.out.println("tree轉(zhuǎn)list完成");
List<TreeNode> treeList=TreeManager.listToTree(destList,1);
System.out.println("List轉(zhuǎn)tree完成");
/*******************注意單個(gè)值計(jì)算結(jié)果會(huì)影響多個(gè)值計(jì)算結(jié)果**************/
List<TreeNode> treeListSingleValue=TreeManager.listToTreeWithSingleValue(destList,1);
System.out.println("List轉(zhuǎn)tree 匯總唯一值value完成");
List<TreeNode> treeListSingleValue2=TreeManager.treeToListWithSingleValue(tree);
System.out.println("tree轉(zhuǎn)List 匯總唯一值value完成");
// List<TreeNode> treeListMultiValues=TreeManager.listToTreeWithMultiValues(destList,1,3);
// System.out.println("List轉(zhuǎn)tree 匯總多個(gè)值values完成");
//
// List<TreeNode> treeListMultiValues2=TreeManager.treeToListWithMultiValues(tree,3);
// System.out.println("tree轉(zhuǎn)List 匯總多個(gè)值values完成");
}
}
注:如果數(shù)據(jù)字段跟工具樹(shù)的不一致可以使用Map轉(zhuǎn)對(duì)象來(lái)實(shí)現(xiàn)。
Github源碼:點(diǎn)擊進(jìn)入
以上這篇list轉(zhuǎn)tree和list中查找某節(jié)點(diǎn)下的所有數(shù)據(jù)操作就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot實(shí)戰(zhàn)之SSL配置詳解
今天小編就為大家分享一篇關(guān)于SpringBoot實(shí)戰(zhàn)之SSL配置詳解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02
java線程中synchronized和Lock區(qū)別及介紹
這篇文章主要為大家介紹了java線程中synchronized和Lock區(qū)別及介紹,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
springboot整合apache ftpserver詳細(xì)教程(推薦)
這篇文章主要介紹了springboot整合apache ftpserver詳細(xì)教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題
這篇文章主要介紹了SpringBootTest測(cè)試時(shí)不啟動(dòng)程序的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-01-01
解決jar包rar壓縮后無(wú)法運(yùn)行問(wèn)題
這篇文章主要介紹了解決jar包rar壓縮后無(wú)法運(yùn)行問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
SpringCloud Gateway跨域配置代碼實(shí)例
這篇文章主要介紹了SpringCloud Gateway跨域配置代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-11-11

