C#之组织树生成之道
最近公司来了一个小的项目。项目组成员就六个。几个新人,项目经理也不知道看没有看式样。就把一个权限设置页面分给了一个新人来做。那个新人能力不是太好,项目经理也不管。分Task,也不管别人会不会。二话不说,上来就开工。
这个新人做了两天都没有做出来。于是来求助我。花了一个多小时,总算搞定了。看了看代码,有些地方还是很值得对C#和JSON不了解的童鞋们借鉴的。今天把代码分享出来。
先说说这个权限生成的几个需求。
数据源是从数据库读出来的。数据的结构是这样的。有个treePath,里面的存的数据是这样的。
通过“/”表明数据的组织层次结构,也就是说如果没有“/”就表明是根节点,如果有一个“/”就表明是第二层结构。这样以此类推。每一个“/”前数据表明其父节点是哪一个。就好比这样的一对数据:
10001
10001/10002
10001/10002/1003
10001/10003/1003
20001
20001/20002
组织结构就如下了:
相信大家都明白了,接下来看看我们最后要生成的结果图:
好了生成的图大家也明白了。就是这样的树状图。
下面我来说说我们实现的代码思路。首先把数据从库里面读出来。然后分析数据,最后生成JOSN对象文件,然后前台进行分析这个JSON对象数据。最后生成我们的树状图。
我们直接来看看代码:
代码中我定义了一个两个类,用来存储数据的。请看这两个类:
1 /// <summary> 2 /// 组织数据 3 /// </summary> 4 public class Organization 5 { 6 public string OrganKey { get; set; } 7 8 public string OrganName { get; set; } 9 10 public string TreePath { get; set; } 11 12 public Organization(string organKey, string organName, string treePath) 13 { 14 this.OrganKey = organKey; 15 this.OrganName = organName; 16 this.TreePath = treePath; 17 } 18 } 19 20 /// <summary> 21 /// 最终的数据结构类型 22 /// </summary> 23 public class OrganizationResult 24 { 25 26 private List<OrganizationResult> lstChildren = new List<OrganizationResult>(); 27 28 /// <summary> 29 /// 主键KEY 30 /// </summary> 31 public string Key { get; set; } 32 33 /// <summary> 34 /// 主键Name 35 /// </summary> 36 public string Name { get; set; } 37 38 /// <summary> 39 /// 获取字节点的个数 40 /// </summary> 41 /// <returns></returns> 42 public int GetChildNodesCount() 43 { 44 return lstChildren.Count; 45 } 46 47 public string levelKey { get; set; } 48 49 /// <summary> 50 /// 构造初始化 51 /// </summary> 52 /// <param name="key"></param> 53 /// <param name="name"></param> 54 /// <param name="levelKey"></param> 55 public OrganizationResult(string key, string name, string levelKey) 56 { 57 this.Key = key; 58 this.Name = name; 59 this.levelKey = levelKey; 60 } 61 62 /// <summary> 63 /// 添加子节点 64 /// </summary> 65 /// <param name="child"></param> 66 public void AddChildNodes(OrganizationResult child) 67 { 68 this.lstChildren.Add(child); 69 } 70 71 /// <summary> 72 /// 根据路径获取节点 73 /// </summary> 74 /// <param name="index"></param> 75 /// <returns></returns> 76 public OrganizationResult GetChildNodesByIndex(int index) 77 { 78 if (this.GetChildNodesCount() < index) 79 { 80 return null; 81 } 82 else 83 { 84 return lstChildren[index]; 85 } 86 } 87 88 /// <summary> 89 /// 获取所有的子节点 90 /// </summary> 91 /// <returns></returns> 92 public List<OrganizationResult> GetChildNodes() 93 { 94 return lstChildren; 95 } 96 }
这个OrganizationResult是最终存放我们要的数据类。
下面是我们的数据处理方法:(请看代码)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public partial class Index : System.Web.UI.Page 2 { 3 /// <summary> 4 /// 数据集合 5 /// </summary> 6 private List<Organization> lstData; 7 8 protected void Page_Load(object sender, EventArgs e) 9 { 10 if (!IsPostBack) 11 { 12 this.SetOrganziationData(); 13 14 List<OrganizationResult> lstResult = this.ResolveOrganization(lstData); 15 16 this.CreateJsonFile(this.CreateJson(lstResult)); 17 } 18 } 19 20 #region 组织架构的分析 21 /// <summary> 22 /// 解析组织架构 23 /// </summary> 24 /// <param name="lstData"></param> 25 /// <returns></returns> 26 private List<OrganizationResult> ResolveOrganization(List<Organization> lstData) 27 { 28 List<OrganizationResult> lstOrganizationResult = new List<OrganizationResult>(); 29 30 Dictionary<int, List<Organization>> dicLevelData = new Dictionary<int, List<Organization>>(); 31 32 foreach (Organization item in lstData) 33 { 34 int level = item.TreePath.Split('/').Length; 35 36 if (dicLevelData.ContainsKey(level)) 37 { 38 dicLevelData[level].Add(item); 39 } 40 else 41 { 42 dicLevelData.Add(level, new List<Organization>() { item }); 43 } 44 } 45 46 // 根据键值排序 47 dicLevelData = dicLevelData.OrderBy(c => c.Key).ToDictionary(k => k.Key, k => k.Value); 48 49 foreach (int key in dicLevelData.Keys) 50 { 51 foreach (Organization item in dicLevelData[key]) 52 { 53 this.InsertOrganizationResult(key, item, lstOrganizationResult); 54 } 55 } 56 57 return lstOrganizationResult; 58 } 59 60 /// <summary> 61 /// 设置组织结构 62 /// </summary> 63 /// <param name="organizationLevel"></param> 64 /// <param name="item"></param> 65 /// <param name="lstOrganizaitonResult"></param> 66 private void InsertOrganizationResult(int organizationLevel, Organization item, List<OrganizationResult> lstOrganizaitonResult) 67 { 68 // 如果属于根目录 69 if (organizationLevel == 1) 70 { 71 lstOrganizaitonResult.Add(this.InitOrganizationResult(item)); 72 return; 73 } 74 75 // 如果不属于根目录 76 string[] treePath = item.TreePath.Split('/'); 77 List<int> lstLevel = new List<int>(); 78 this.FindParentPath(lstOrganizaitonResult, lstLevel, treePath); 79 List<OrganizationResult> lstChildrenTemp = lstOrganizaitonResult; 80 foreach (int level in lstLevel) 81 { 82 if (lstOrganizaitonResult[level].GetChildNodesCount() == 0) 83 { 84 lstChildrenTemp = lstOrganizaitonResult[level].GetChildNodes(); 85 } 86 else 87 { 88 lstChildrenTemp = lstChildrenTemp[level].GetChildNodes(); 89 } 90 } 91 92 lstChildrenTemp.Add(this.InitOrganizationResult(item)); 93 } 94 95 /// <summary> 96 /// 获取根目录父节点和父节点的位置 97 /// </summary> 98 /// <param name="lstOrganizaitonResult"></param> 99 /// <param name="parentIndex"></param> 100 /// <param name="childIndex"></param> 101 /// <param name="treePath"></param> 102 private void FindParentPath(List<OrganizationResult> lstOrganizaitonResult, List<int> lstLevel, string[] treePath) 103 { 104 for (int rootIndex = 0; rootIndex < lstOrganizaitonResult.Count; rootIndex++) 105 { 106 string levelKey = lstOrganizaitonResult[rootIndex].levelKey; 107 108 // 找到第一任父节点继续往下找 109 if (treePath[0] == levelKey) 110 { 111 lstLevel.Add(rootIndex); 112 113 if (treePath.Length == 1) 114 { 115 return; 116 } 117 118 // 如果不存在子节点,则直接添加 119 if (lstOrganizaitonResult[rootIndex].GetChildNodesCount() == 0) 120 { 121 return; 122 } 123 124 string[] tempLevel = new string[treePath.Length - 1]; 125 Array.Copy(treePath, 1, tempLevel, 0, tempLevel.Length); 126 this.FindParentPath(lstOrganizaitonResult[rootIndex].GetChildNodes(), lstLevel, tempLevel); 127 return; 128 } 129 else 130 { 131 continue; 132 } 133 } 134 } 135 136 /// <summary> 137 /// 初始化一个组织结果数据 138 /// </summary> 139 /// <param name="key"></param> 140 /// <param name="name"></param> 141 /// <returns></returns> 142 private OrganizationResult InitOrganizationResult(string key, string name, string parentKey) 143 { 144 return new OrganizationResult(key, name, parentKey); 145 } 146 147 /// <summary> 148 /// 初始化一个组织结果数据 149 /// </summary> 150 /// <param name="key"></param> 151 /// <param name="name"></param> 152 /// <returns></returns> 153 private OrganizationResult InitOrganizationResult(Organization organ) 154 { 155 string levelKey = null; 156 string[] tempArr = organ.TreePath.Split('/'); 157 158 // 设置自己属于哪一个节点 159 if (tempArr.Length == 1) 160 { 161 levelKey = tempArr[0]; 162 } 163 else 164 { 165 levelKey = tempArr[tempArr.Length - 1]; 166 } 167 168 return new OrganizationResult(organ.OrganKey, organ.OrganName, levelKey); 169 } 170 171 /// <summary> 172 /// 初始化数据信息 173 /// </summary> 174 private void SetOrganziationData() 175 { 176 if (lstData == null) 177 { 178 lstData = new List<Organization>(); 179 } 180 181 lstData.AddRange( 182 new Organization[]{ 183 184 new Organization("001","年级一","00001"), 185 186 // 班级一的学生信息(年级一) 187 new Organization("002","班级一","00001/10001"), 188 new Organization("003","学生A","00001/10001/11001"), 189 new Organization("004","学生B","00001/10001/11002"), 190 191 // 班级二的学生信息(年级一) 192 new Organization("005","班级二","00001/10002"), 193 new Organization("006","学生C", "00001/10002/12001"), 194 195 new Organization("007","年级二","00002"), 196 197 // 班级一的学生信息(年级二) 198 new Organization("008","班级一","00002/20001"), 199 new Organization("009","学生D","00002/20001/12001"), 200 new Organization("010","学生E","00002/20001/12002"), 201 202 // 班级二的学生信息(年级二) 203 new Organization("011","班级二","00002/20002"), 204 new Organization("012","学生F","00002/20002/20001") 205 } 206 ); 207 } 208 #endregion 组织架构的分析 209 210 #region 生成JSON对象 211 212 /// <summary> 213 /// 生成JSON对象 214 /// </summary> 215 /// <param name="lstResult"></param> 216 /// <returns></returns> 217 private string CreateJson(List<OrganizationResult> lstResult) 218 { 219 StringBuilder strBuild = new StringBuilder("["); 220 221 int index = 0; 222 223 foreach (OrganizationResult item in lstResult) 224 { 225 if (index == 0) 226 { 227 strBuild.Append(this.CreateElement(item)); 228 strBuild.Append("\r\n"); 229 } 230 else { 231 strBuild.Append(","+this.CreateElement(item)); 232 strBuild.AppendLine("\r\n"); 233 } 234 index++; 235 236 } 237 strBuild.AppendLine("]"); 238 return strBuild.ToString(); 239 } 240 241 /// <summary> 242 /// 创建一个对象 243 /// </summary> 244 /// <param name="item"></param> 245 /// <returns></returns> 246 private string CreateElement(OrganizationResult item) 247 { 248 StringBuilder strBuild = new StringBuilder(""); 249 250 if (item.GetChildNodesCount() != 0) 251 { 252 strBuild.AppendLine("{\"id\":" + "\"" + item.Key + "\","); 253 strBuild.AppendLine("\"text\":" + "\"" + item.Name + "\","); 254 strBuild.AppendLine("\"children\":["); 255 bool isFirst = true; 256 257 foreach (OrganizationResult element in item.GetChildNodes()) 258 { 259 if (isFirst) 260 { 261 strBuild.Append(this.CreateElement(element)); 262 263 isFirst = false; 264 } 265 else 266 { 267 strBuild.AppendLine("," + this.CreateElement(element)); 268 } 269 } 270 271 strBuild.AppendLine("]}"); 272 } 273 else 274 { 275 strBuild.AppendLine("{\"text\":" + "\"" + item.Name + "\"}"); 276 277 return strBuild.ToString(); 278 } 279 280 return strBuild.ToString(); 281 } 282 #endregion 283 284 #region 创建JSON文件 285 /// <summary> 286 /// 创建JSON文件 287 /// </summary> 288 /// <param name="fileData"></param> 289 private void CreateJsonFile(String fileData) 290 { 291 string filePath = System.AppDomain.CurrentDomain.BaseDirectory + "data/tree_data.json"; 292 293 if (File.Exists(filePath)) 294 { 295 File.Delete(filePath); 296 } 297 298 using (StreamWriter sw = new StreamWriter(new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write), System.Text.Encoding.UTF8)) 299 { 300 sw.WriteLine(fileData); 301 } 302 } 303 #endregion 304 } 305 306 /// <summary> 307 /// 组织数据 308 /// </summary> 309 public class Organization 310 { 311 public string OrganKey { get; set; } 312 313 public string OrganName { get; set; } 314 315 public string TreePath { get; set; } 316 317 public Organization(string organKey, string organName, string treePath) 318 { 319 this.OrganKey = organKey; 320 this.OrganName = organName; 321 this.TreePath = treePath; 322 } 323 }
上面的代码就是我们主要的逻辑代码。在上面代码中采用了Linq数据排序,函数递归等一些常用的开发技巧。相信大家看看注释应该就明白了。如果有不明白的地方,可以来拍砖,我会给大家解释。
关于前台部分就是利用JQuery进行分析JSON,大家可以按照自己的想法去实现。
好了,今晚就到这里,还有其他的东西要弄。下次见,我的朋友。