系統操作日誌設計-代碼實現

  通了解《系統操作日誌設計》,已基本明確我們不能通過clone的方式來做日誌的設計,因爲這樣不僅會造成的你數據庫表爆炸的情況,還大大的增加了工作量,減少了系統的可維護性。

      通過思考大概清楚系統操作日誌的設計,以下是其UML圖:

 

通過上圖,我們可以瞭解知道該UML主要由三個表組成,其中一個主表LogSetting和兩個從表分別是LogOperation和LogSettingDetail。

那麼怎麼樣才能通過這樣的設計來現實我們的日誌功能呢?

其實一開始我就覺得通過.net的反射功能可以很簡單、很方便的實現這個功能,所以我就順着一個思路來實現她;通過反射動態的獲取Model實體的屬性,然後再根據LogSettingDetail配置來匹配所要記錄的字段信息。

 

先來主要的代碼吧,發現將思想用文字表達出來還是較困難的,代碼比較直接:

代碼的實現

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

using BLL.Sys;


using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Reflection;
/// 
/// LogManager 的摘要說明
/// 
public class LogManager where T : new() 
{
    #region Constructor
    /// 
    /// 日誌管理構造函數
    /// 
    public LogManager()
    {
        tableName = typeof(T).Name;
        Model.Sys.LogSetting model = GetLogSetting(tableName);
        if (model != null)
        {
            businessName = model.BusinessName;
            logID = model.LogID;
            primaryKey = model.PrimaryKey;
            urlTemplate = model.UrlTemplate;
            deleteScriptTemplate = model.DeleteScriptTemplate;
            updateScriptTemplate = model.UpdateScriptTemplate;
        }
        else
        {
            throw new ArgumentNullException("日誌設置爲空!");
        }
    }
    ///     /// 
    /// 日誌管理構造函數
    /// 
    /// 
    /// 表名
    /// 業務名稱
    public LogManager(string tableName, string businessName)
    {
        this.tableName = tableName;
        this.businessName = businessName;

        Model.Sys.LogSetting model = GetLogSetting(tableName, businessName);
        if (model != null)
        {
            logID = model.LogID;
            primaryKey = model.PrimaryKey;
            urlTemplate = model.UrlTemplate;
            deleteScriptTemplate = model.DeleteScriptTemplate;
            updateScriptTemplate = model.UpdateScriptTemplate;
        }
        else
        {
            throw new ArgumentNullException("日誌設置爲空!");
        }
    }
    #endregion


    #region Properties
    private int logID;
    private string tableName;
    private string businessName;
    private string primaryKey;
    private string urlTemplate;
    private string deleteScriptTemplate;
    private string updateScriptTemplate;


    /// 
    /// 日誌設置實體列表
    /// 
    public List<model.sys.LogSetting> LogSettingList
    {
        get
        {
            System.Web.Caching.Cache cache = HttpRuntime.Cache;
            List<model.sys.LogSetting> list = cache["LogSettingList"] as List<model.sys.LogSetting>;
            if (list != null && list.Count > 0)
            {
                return list;
            }
            else
            {
                LogSetting bll = new LogSetting();
                list = bll.GetModelList(string.Empty);
                cache["LogSettingList"] = list;
                return list;
            }
        }
        set
        {
            System.Web.Caching.Cache cache = HttpRuntime.Cache;
            cache["LogSettingList"] = null;
        }
    }
    /// 
    /// 日誌設置明細
    /// 
    public List<model.sys.LogSettingDetail> LogSettingDetail
    {
        get
        {
            System.Web.Caching.Cache cache = HttpRuntime.Cache;
            List<model.sys.LogSettingDetail> list = cache["LogSettingDetail"] as List<model.sys.LogSettingDetail>;
            if (list != null && list.Count > 0)
            {
                return list;
            }
            else
            {
                LogSettingDetail bll = new LogSettingDetail();
                list = bll.GetModelList(string.Empty);
                cache["LogSettingDetail"] = list;
                return list;
            }
        }
        set
        {
            System.Web.Caching.Cache cache = HttpRuntime.Cache;
            cache["LogSettingDetail"] = null;
        }
    }

    #endregion

    #region Method
    /// 
    /// 通過logId獲取日誌設置明細
    /// 
    /// 日誌設置編號
    /// 
    private List<model.sys.LogSettingDetail> GetLogSettingDetails(int logId)
    {
        if (logId == 0)
            throw new ArgumentNullException("LogID爲空");

        List<model.sys.LogSettingDetail> list = new List<model.sys.LogSettingDetail>();
        foreach (Model.Sys.LogSettingDetail var in LogSettingDetail)
        {
            if (var.LogID == logId)
                list.Add(var);
        }
        return list;
    }
    /// 
    /// 通過tableName和businessName來獲取日誌設置對象
    /// 
    /// 
    /// 
    /// 
    private Model.Sys.LogSetting GetLogSetting(string tableName, string businessName)
    {
        foreach (Model.Sys.LogSetting var in LogSettingList)
        {
            if (var.TableName.Equals(tableName, StringComparison.InvariantCultureIgnoreCase) && var.BusinessName.Equals(businessName, StringComparison.InvariantCultureIgnoreCase))
                return var;
        }
        return null;
    }
    private Model.Sys.LogSetting GetLogSetting(string tableName)
    {
        foreach (Model.Sys.LogSetting var in LogSettingList)
        {
            if (var.TableName.Equals(tableName, StringComparison.InvariantCultureIgnoreCase))
                return var;
        }
        return null;
    }


    /// 
    /// 比較兩個實體,然後返回實體中每個屬性值不同的內容
    /// 
    /// 
    /// 
    /// 
    public string Compare(T oldObj, T newObj)
    {
        Type objTye = typeof(T);

        StringBuilder sbResult = new StringBuilder();
        string tableHeader = "";
        tableHeader += "";

        string tableRow = "";

        List<model.sys.LogSettingDetail> list = GetLogSettingDetails(logID);
        int i = 1;

        foreach (Model.Sys.LogSettingDetail var in list)
        {
            PropertyInfo property = objTye.GetProperty(var.ColumnName);
            if (property != null && !property.IsSpecialName)
            {
                object o = property.GetValue(oldObj, null);
                object n = property.GetValue(newObj, null);
                if (!IsEqual(property.PropertyType, o, n))
                {
                    sbResult.AppendFormat(tableRow, i % 2 == 0 ? "odd" : "even", i, var.ColumnName, var.ColumnText, o, n);
                    i++;
                }

            }
        }

        sbResult.Append("
序號字段名稱舊值新值
{1}{2}{3}{4}{5}
"); #region Add Log Record if (i > 1) { Model.Sys.LogOperation operModel = new Model.Sys.LogOperation(); operModel.LogID = logID; operModel.OperationType = (int)OperationType.Update; operModel.Content = tableHeader + sbResult.ToString(); operModel.CreateTime = DateTime.Now; if (HttpContext.Current != null) operModel.CreateUser = HttpContext.Current.User.Identity.Name; if (!string.IsNullOrEmpty(primaryKey)) { PropertyInfo p = objTye.GetProperty(primaryKey); object o = p.GetValue(newObj, null); if (o != null) { operModel.PrimaryKeyValue = o.ToString(); if (urlTemplate.Contains("{0}")) operModel.Url = string.Format(urlTemplate, o.ToString()); } } LogOperation operBll = new LogOperation(); operBll.Add(operModel); } #endregion return tableHeader + sbResult.ToString(); } /// /// 刪除實體操作,這裏並不是真的刪除該實體,而是將刪除的操作記錄在日誌中 /// /// /// public string Delete(T obj) { Type objTye = typeof(T); StringBuilder sbResult = new StringBuilder(); string tableHeader = ""; tableHeader += ""; string tableRow = ""; List<model.sys.LogSettingDetail> list = GetLogSettingDetails(logID); int i = 1; foreach (Model.Sys.LogSettingDetail var in list) { PropertyInfo property = objTye.GetProperty(var.ColumnName); if (property != null && !property.IsSpecialName) { object o = property.GetValue(obj, null); sbResult.AppendFormat(tableRow, i % 2 == 0 ? "odd" : "even", i, var.ColumnName, var.ColumnText, o); i++; } } sbResult.Append("
序號字段名稱
{1}{2}{3}{4}
"); #region Add Log Record Model.Sys.LogOperation operModel = new Model.Sys.LogOperation(); operModel.LogID = logID; operModel.OperationType = (int)OperationType.Delete; operModel.Content = tableHeader + sbResult.ToString(); operModel.CreateTime = DateTime.Now; if (!string.IsNullOrEmpty(primaryKey)) { PropertyInfo p = objTye.GetProperty(primaryKey); object o = p.GetValue(obj, null); if (o != null) { operModel.PrimaryKeyValue = o.ToString(); if (urlTemplate.Contains("{0}")) operModel.Url = string.Format(urlTemplate, o.ToString()); } } if (HttpContext.Current != null) operModel.CreateUser = HttpContext.Current.User.Identity.Name; LogOperation operBll = new LogOperation(); operBll.Add(operModel); #endregion return string.Empty; } /// /// 添加實體,將添加的操作記錄在日誌中 /// /// /// public string Add(T obj) { Type objTye = typeof(T); StringBuilder sbResult = new StringBuilder(); string tableHeader = ""; tableHeader += ""; string tableRow = ""; List<model.sys.LogSettingDetail> list = GetLogSettingDetails(logID); int i = 1; foreach (Model.Sys.LogSettingDetail var in list) { PropertyInfo property = objTye.GetProperty(var.ColumnName); if (property != null && !property.IsSpecialName) { object o = property.GetValue(obj, null); sbResult.AppendFormat(tableRow, i % 2 == 0 ? "odd" : "even", i, var.ColumnName, var.ColumnText, o); i++; } } sbResult.Append("
序號字段名稱
{1}{2}{3}{4}
"); #region Add Log Record Model.Sys.LogOperation operModel = new Model.Sys.LogOperation(); operModel.LogID = logID; operModel.OperationType = (int)OperationType.Add; operModel.Content = tableHeader + sbResult.ToString(); operModel.CreateTime = DateTime.Now; if (!string.IsNullOrEmpty(primaryKey)) { PropertyInfo p = objTye.GetProperty(primaryKey); object o = p.GetValue(obj, null); if (o != null) { operModel.PrimaryKeyValue = o.ToString(); if (urlTemplate.Contains("{0}")) operModel.Url = string.Format(urlTemplate, o.ToString()); } } if (HttpContext.Current != null) operModel.CreateUser = HttpContext.Current.User.Identity.Name; LogOperation operBll = new LogOperation(); operBll.Add(operModel); #endregion return string.Empty; } /// /// 複製一個對象 /// /// /// public T Clone(T obj) { Type objTye = typeof(T); T model = new T(); PropertyInfo[] properties = objTye.GetProperties(); foreach (PropertyInfo property in properties) { if(!property.IsSpecialName) { object o = property.GetValue(obj, null); property.SetValue(model, o, null); } } return model; } private bool IsEqual(Type dataType, object oldObj, object newObj) { if (oldObj == null && newObj == null) return true; if (dataType == typeof(int)) { return (int)oldObj == (int)newObj; } else if (dataType == typeof(decimal)) { return (decimal)oldObj == (decimal)newObj; } else if (dataType == typeof(double)) { return (double)oldObj == (double)newObj; } else if (dataType == typeof(Guid)) { return (Guid)oldObj == (Guid)newObj; } else if (dataType == typeof(DateTime)) { return (DateTime)oldObj == (DateTime)newObj; } else return oldObj.Equals(newObj); } #region Script. Excute //public int DeleteBusRecode(string primaryKeyValue) //{ // if (string.IsNullOrEmpty(tableName)) // throw new ArgumentException("tableName爲空"); // if(string.IsNullOrEmpty(primaryKey)) // throw new ArgumentException("primaryKey爲空"); // if (string.IsNullOrEmpty(deleteScriptTemplate)) // throw new ArgumentException("deleteScriptTemplate爲空"); // string strSql = string.Format(deleteScriptTemplate, primaryKeyValue); // Database db = DatabaseFactory.CreateDatabase(); // return 0; //} #endregion #endregion } public enum OperationType { Select = 0, Add = 1, Update = 2, Delete = 3 }

 

使用的場景

Model文件:

public class EmployeeModel

{

public int ID{get;set;}

public string Name{get;set;}

…

}
下面介紹如何將系統操作日誌集成到你的業務系統中
添加操作:
EmployeeBll bll = new EmployeeBll();
EmployeeModel model = new EmployeeModel();
/* model 實體經過漫長的 賦值 後… */
bll.Add(model);    //添加實體
//添加系統操作記錄
//日誌
LogManager log = new LogManager();
log.Add(model);
 
更新操作:
EmployeeBll bll = new EmployeeBll();
EmployeeModel model = bll.GetModel(employeeID);
LogManager log = new LogManager();
EmployeeModel modelOld = log.Clone(model);   //克隆EmployeeModel實體對象,這個主要是在系統操作日誌記錄時使用的
 
/* model 實體又經過漫長的 賦值 後… */
bll.Update(model);     //更新實體
//將更新的內容寫入系統操作日誌中
log.Compare(modelOld, model);    //原來的實體和賦值後的實體對比,並將更新的內容寫入系統操作日誌中
 
刪除操作:
在GridView的RowDeleting事件中獲取要刪除的實體
EmployeeBll bll = new EmployeeBll();
EmployeeModel model = bll.GetModel(employeeID);
bll.Delete(employeeID);
LogManager log = new LogManager();
log.Delete(model);       //實體的內容記錄到日誌中
 
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }  

總結:

大家可以看到代碼還是比較粗糙的,有不少的重複的代碼,下一節將會討論如何進行系統操作日誌管理

另外如何大家有什麼意見或想法請分享提出。

 

本節用到的知識點

1、泛型

2、反射

3、緩存

 

優點:

1、使用和集成方便,代碼量小;

2、大大提高工作效率,避免表爆炸;

 

缺點:

1、代碼有待優化;

2、可擴展性較差

轉載請註明出處[http://samlin.cnblogs.com/] 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章