系统操作日志设计-代码实现

     

      上一篇《系统操作日志设计》,已基本介绍了为什么要系统操作日志和设计系统操作日志部分内容,如不清楚系统操作日志的请点这里。 :)

      通了解《系统操作日志设计》,已基本明确我们不能通过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;
/// <summary>
/// LogManager 的摘要说明
/// </summary>
public class LogManager<T> where T : new() 
{
    #region Constructor
    /// <summary>
    /// 日志管理构造函数
    /// </summary>
    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("日志设置为空!");
        }
    }
    /// <summary>    /// 
    /// 日志管理构造函数
    /// </summary>
    /// </summary>
    /// <param name="tableName">表名</param>
    /// <param name="businessName">业务名称</param>
    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;


    /// <summary>
    /// 日志设置实体列表
    /// </summary>
    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;
        }
    }
    /// <summary>
    /// 日志设置明细
    /// </summary>
    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
    /// <summary>
    /// 通过logId获取日志设置明细
    /// </summary>
    /// <param name="logId">日志设置编号</param>
    /// <returns></returns>
    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;
    }
    /// <summary>
    /// 通过tableName和businessName来获取日志设置对象
    /// </summary>
    /// <param name="tableName"></param>
    /// <param name="businessName"></param>
    /// <returns></returns>
    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;
    }


    /// <summary>
    /// 比较两个实体,然后返回实体中每个属性值不同的内容
    /// </summary>
    /// <param name="oldObj"></param>
    /// <param name="newObj"></param>
    /// <returns></returns>
    public string Compare(T oldObj, T newObj)
    {
        Type objTye = typeof(T);

        StringBuilder sbResult = new StringBuilder();
        string tableHeader = "<table class=\"GridView\" cellspacing=\"0\" rules=\"all\" border=\"1\" id=\"gv\" style=\"border-collapse:collapse;\">";
        tableHeader += "<tr><th scope=\"col\">序号</th><th scope=\"col\">字段</th><th scope=\"col\">名称</th><th scope=\"col\">旧值</th><th scope=\"col\">新值</th></tr>";

        string tableRow = "<tr class='{0}'><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td></tr>";

        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("</table>");

        #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();

    }
    /// <summary>
    /// 删除实体操作,这里并不是真的删除该实体,而是将删除的操作记录在日志中
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public string Delete(T obj)
    {
        Type objTye = typeof(T);


        StringBuilder sbResult = new StringBuilder();
        string tableHeader = "<table class=\"GridView\" cellspacing=\"0\" rules=\"all\" border=\"1\" id=\"gv\" style=\"border-collapse:collapse;\">";
        tableHeader += "<tr><th scope=\"col\">序号</th><th scope=\"col\">字段</th><th scope=\"col\">名称</th><th scope=\"col\">值</th></tr>";

        string tableRow = "<tr class='{0}'><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>";

        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("</table>");


        #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;
    }
    /// <summary>
    /// 添加实体,将添加的操作记录在日志中
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public string Add(T obj)
    {
        Type objTye = typeof(T);


        StringBuilder sbResult = new StringBuilder();
        string tableHeader = "<table class=\"GridView\" cellspacing=\"0\" rules=\"all\" border=\"1\" id=\"gv\" style=\"border-collapse:collapse;\">";
        tableHeader += "<tr><th scope=\"col\">序号</th><th scope=\"col\">字段</th><th scope=\"col\">名称</th><th scope=\"col\">值</th></tr>";

        string tableRow = "<tr class='{0}'><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td></tr>";

        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("</table>");


        #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;
    }
    /// <summary>
    /// 复制一个对象
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    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<EmployeeModel> log = new LogManager<EmployeeModel>();
log.Add(model);
 
更新操作:
EmployeeBll bll = new EmployeeBll();
EmployeeModel model = bll.GetModel(employeeID);
LogManager<EmployeeModel> log = new LogManager<EmployeeModel>();
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<EmployeeModel> log = new LogManager<EmployeeModel>();
log.Delete(model);       //实体的内容记录到日志中
 

 

总结:

大家可以看到代码还是比较粗糙的,有不少的重复的代码,下一节将会讨论如何进行系统操作日志管理

另外如何大家有什么意见或想法请分享提出。

 

本节用到的知识点

1、泛型

2、反射

3、缓存

 

优点:

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

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

 

缺点:

1、代码有待优化;

2、可扩展性较差

posted @ 2010-04-23 12:59  Sam Lin  阅读(11770)  评论(16编辑  收藏  举报