系統操作日誌表單形式構建
阿新 • • 發佈:2018-12-02
1.概述
所謂操作日誌,就是某人對指定模組的指定物件進行操作的記錄,在某種情況下,可能會有顯示本次操作對哪些資料欄位進行啦了動,或者是操作前後該模型的資料比對情況。針對於這類需求,想要檢視某條操作記錄具體改動項資訊的時候,對於前端來講,他不需要知道這個物件的具體型別及各個欄位的意義的漢字描述,他們只需要迴圈遍歷,將所有的資料拼到一個div容器裡即可。後臺該如何去設計才能做到最簡化的操作那?第一種情況可以用列舉的形式,來標記每種模型的型別,在每次記錄日誌的時候,可以將當前列舉也記錄進去(資料庫/nosql),這樣的話,在檢視每種記錄變動的詳情時,就可以根據每種型別封裝不同的拼接資料的策略,最終以統一的格式返回給前端。但是,這種操作起來並不是很理想,沒實現一種模組的操作都要實現對應的表單項拼接策略,顯然以後維護起來並不是十分的完美。那麼,能不能通過反射的形式來根絕具體的模型名稱動態的獲取模型型別,並根據具體的型別和json資料來形成物件,從而完成表單項的構建那??答案是:可以的(c#中可以根據Type type = Type.GetType(FullTypeName);類實現)。下面我們就先實現一下獲取當前操作模型具體操作操作記錄。
2.需求分析及實現
1.前端需要展示成這樣:
2.後臺程式碼設定
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ConsoleApp1.OpearorLog.EntityView Code9 { 10 public class ColumnRenark : Attribute 11 { 12 /// <summary> 13 /// 欄位名稱 14 /// </summary> 15 public string ColumnName { get; set; } 16 /// <summary> 17 /// 欄位型別 18 /// </summary> 19 public ColumnType ColumnType { get; set; } 20 21 22 public ColumnRenark() { } 23 } 24 public enum ColumnType 25 { 26 [Description("基礎型別(int/string...)")] 27 Basic = 0, 28 [Description("類型別")] 29 Class = 1, 30 [Description("字典型別")] 31 Dic = 2, 32 [Description("列表型別")] 33 Lst = 3, 34 35 36 } 37 }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp1.OpearorLog.Entity { /// <summary> ///行記錄 /// </summary> public class RowRecord { /// <summary> /// 欄位語義 /// </summary> public string Key { get; set; } /// <summary> /// 欄位對應值 /// </summary> public string Value { get; set; } /// <summary> /// 所屬層級 /// </summary> public int Lev { get; set; } /// <summary> /// 包含的子項 /// </summary> public List<List<RowRecord>> Child { get; set; } public RowRecord() { Child = new List<List<RowRecord>>(); } } }View Code
1 using Newtonsoft.Json; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Runtime.InteropServices; 6 using System.Text; 7 using System.Threading.Tasks; 8 9 namespace ConsoleApp1 10 { 11 public class OperatorLogContext 12 { 13 #region attr 14 private List<RowRecord> RowRecords { get; set; } 15 private object Obj { get; set; } 16 public string FullTypeName { get; set; } 17 public string JsonStr { get; set; } 18 #endregion 19 20 public OperatorLogContext(string fullTypeName,string jsonStr) 21 { 22 FullTypeName = fullTypeName; 23 JsonStr = jsonStr; 24 RowRecords = new List<RowRecord>(); 25 Type type = Type.GetType(FullTypeName); 26 Obj = JsonConvert.DeserializeObject(JsonStr,type); 27 } 28 public OperatorLogContext() 29 { 30 Type type = Type.GetType(FullTypeName); 31 Obj = JsonConvert.DeserializeObject(JsonStr, type); 32 } 33 /// <summary> 34 /// 構建表單項 35 /// </summary> 36 /// <returns></returns> 37 public List<RowRecord> BuildForm() 38 { 39 return Build(Obj); 40 } 41 #region private 42 private List<RowRecord> Build(object obj, RowRecord parentRow = null, List<RowRecord> childRow = null, int lev = 0) 43 { 44 //1.當前型別 45 Type currentType = obj.GetType(); 46 //2.獲取當下模型的所有屬性欄位 47 var props = currentType.GetProperties(); 48 foreach (var prop in props) 49 { 50 RowRecord rowRecord = new RowRecord(); 51 rowRecord.Lev = lev; //設定當前樹形級別 52 //3.獲取當下屬性欄位下的所有自定義屬性 53 var attr = prop.CustomAttributes.FirstOrDefault(o => o.AttributeType == typeof(ColumnRenark)); 54 if (attr == null) 55 { 56 continue; 57 } 58 else 59 { 60 foreach (var named in attr.NamedArguments) 61 { 62 if (named.MemberName == "ColumnName") 63 { 64 rowRecord.Key = named.TypedValue.Value.ToString(); 65 } 66 else if (named.MemberName == "ColumnType") 67 { 68 ColumnType columnType = (ColumnType)Enum.Parse(typeof(ColumnType), named.TypedValue.Value.ToString()); 69 switch (columnType) 70 { 71 case ColumnType.Basic: 72 rowRecord.Value = prop.GetValue(obj).ToString(); 73 break; 74 case ColumnType.Class: 75 Build(prop.GetValue(obj), rowRecord, new List<RowRecord>()); 76 break; 77 case ColumnType.Lst: 78 var currentLst = (IEnumerable<object>)prop.GetValue(obj); 79 80 foreach (var opt in currentLst) 81 { 82 83 Build(opt, rowRecord, new List<RowRecord>()); 84 } 85 break; 86 } 87 } 88 } 89 } 90 91 if (parentRow != null) 92 { 93 rowRecord.Lev = parentRow.Lev + 1; 94 childRow.Add(rowRecord); 95 } 96 else 97 { 98 RowRecords.Add(rowRecord); 99 } 100 } 101 if (childRow != null) 102 { 103 parentRow.Child.Add(childRow); 104 } 105 return RowRecords; 106 } 107 #endregion 108 109 } 110 }View Code
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Text; namespace ConsoleApp1 { class Program { static void Main(string[] args) { User user = new User(); user.Age = 20; user.Name = "lsh"; user.Book = new Book() { Name = "c#從入門指南", Desc = "書籍描述" }; user.Hobby = new List<Hobby>() { new Hobby() { Name = "讀書", Rate = "89%" }, new Hobby() { Name = "旅遊", Rate = "33%" } }; string json = JsonConvert.SerializeObject(user); var lst = new OperatorLogContext("ConsoleApp1.User", json).BuildForm(); Console.ReadKey(); } } public class User { [ColumnRenark(ColumnName = "姓名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "年齡", ColumnType = ColumnType.Basic)] public int Age { get; set; } [ColumnRenark(ColumnName = "書籍", ColumnType = ColumnType.Class)] public Book Book { get; set; } [ColumnRenark(ColumnName = "愛好", ColumnType = ColumnType.Lst)] public List<Hobby> Hobby { get; set; } } public class Hobby { [ColumnRenark(ColumnName = "愛好名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "比率", ColumnType = ColumnType.Basic)] public string Rate { get; set; } } /// <summary> /// 行元素 /// </summary> public class RowRecord { public string Key { get; set; } public string Value { get; set; } public int Lev { get; set; } public List<List<RowRecord>> Child { get; set; } public RowRecord() { Child = new List<List<RowRecord>>(); } } public class Book { [ColumnRenark(ColumnName = "書名", ColumnType = ColumnType.Basic)] public string Name { get; set; } [ColumnRenark(ColumnName = "書描述", ColumnType = ColumnType.Basic)] public string Desc { get; set; } } /// <summary> /// 欄位標記屬性 /// </summary> public class ColumnRenark : Attribute { /// <summary> /// 欄位名稱 /// </summary> public string ColumnName { get; set; } /// <summary> /// 欄位型別 /// </summary> public ColumnType ColumnType { get; set; } public ColumnRenark() { } } public enum ColumnType { [Description("基礎型別(int/string...)")] Basic = 0, [Description("類型別")] Class = 1, [Description("字典型別")] Dic = 2, [Description("列表型別")] Lst = 3, } }View Code
3.測試結果