项目总结- 架构及代码样例

曾在公司参与过Extjs 4.2的项目开发,因为觉得在项目中学到了很多知识,特此记录一下。

首先介绍系统项目架构如下:(AAA是化名)

  • AAA.Mvc.Web:所有页面UI纯Extjs,Extjs内部又包含(controller, model, store, view)
  • AAA.Mvc.Controllers:这次包含所有的Web页面的请求,会去调用IBll中的handler (引用IBll, entities, model),返回类型为JsonResult。 所有的 try catch将只出现在这层,但是log对象可以出现在Controller/BLL/DAL中,可以记录数据访问的详细信息。

 

    public ICompanyHandler CompanyHandler { get; set; }
    Logger log = new  Logger(MethodBase.GetCurrentMethod().DeclaringType);

         [HttpGet]
        public JsonResult SearchCompany(Guid id, int CType, int limit, int start)
        {
            try
            {
                CommonTResult<Company> result = CompanyHandler.Search(id, CType, limit, start);
                List<CompanyView> viewList = new List<CompanyView>();
                if (result == null)
                {
                    return Json(new { data = viewList, total = 0, message = StringResources.NODATA, success = true },
                       JsonRequestBehavior.AllowGet);
                }
                foreach (Company entity in result.ResultList)
                {
                    viewList.Add(CompanyViewMapper.MapToView(entity));
                }

                return Json(new { data = viewList, total = result.ResultCount, success = true, message = StringResources.GETDATA_SUCCESS }, JsonRequestBehavior.AllowGet);
            }
            catch (Exception ex)
            {
                log.ErrorLog(ex, MethodBase.GetCurrentMethod().Name);
                return Json(new { success = false, message = StringResources.GETDATA_FAILED }, JsonRequestBehavior.AllowGet);
            }
        }
Controlller

 

  • AAA.Mvc.Models: 定义前台数据操作的模型,但是这里的数据类型和Entity中有一些不一样,比如日期,在entity是datetime,但是在我们前台按照string来处理。所以此处的Models里面也存在Entity-model Mapping的逻辑。
public class CriticalField_LogViewMapper
   {
       public static CriticalField_LogView MapToView(CriticalField_Log entity)
       {
           CriticalField_LogView view = new CriticalField_LogView();
           view.LogId = entity.LogId;
           view.Operation = entity.Operation;
           view.OperationStatus = entity.OperationStatus;
           view.OperationLog = entity.OperationLog;
           view.ReferenceTable = entity.ReferenceTable;
           view.ReferenceNumber = entity.ReferenceNumber;
           view.LogXml = entity.LogXml;
           view.ProcessBy = entity.ProcessBy;
           view.ProcessDate = entity.ProcessDate;
           view.AppID = entity.AppID;
           view.AppNo = entity.AppNo;
           return view;
       }

       public static CriticalField_Log MapFromView(CriticalField_LogView view)
       {
           CriticalField_Log entity = new CriticalField_Log();
           entity.LogId = view.LogId;
           entity.Operation = view.Operation;
           entity.OperationStatus = view.OperationStatus;
           entity.OperationLog = view.OperationLog;
           entity.ReferenceTable = view.ReferenceTable;
           entity.ReferenceNumber = view.ReferenceNumber;
           entity.LogXml = view.LogXml;
           entity.ProcessBy = view.ProcessBy;
           entity.ProcessDate = view.ProcessDate;
           entity.AppID = view.AppID;
           entity.AppNo = view.AppNo;

           return entity;
       }
   }
EntityViewMapper
  • AAA.Entities:此处的entity基本和后台数据库表一一对应,也可以根据需要创建,比如有很多页面的查询条件类似,就对应建立了Query的Entity,传值到后台SP进行查询
  • AAA.Bll:定义handler,
public class CompanyHandler : ICompanyHandler
{
    public ICompanyDao CompanyDao { get; set; }
    public CommonTResult<Company> Search(Guid appID, int CType, int limit, int start)
        {
            return CompanyDao.Search(appID, CType, limit, start);
        }
}
CompanyHandler
  • AAA.IBll:定义handler接口
  • AAA.Dal:定义Dao,并包含Mapper,负责将数据从datareader转成对应的Entity,这里的数据库联接以及execute是直接使用了Spring.Data.Generic, 每个Dao类,都继承AdoDaoSupport类,并实现对应的IDao接口。
namespace Spring.Data.Generic
{
    public class AdoDaoSupport : DaoSupport
    {
        public AdoDaoSupport();

        public AdoTemplate AdoTemplate { get; set; }
        protected IDbConnection Connection { get; }
        public IDbProvider DbProvider { get; set; }
        protected IAdoExceptionTranslator ExceptionTranslator { get; }

        protected override void CheckDaoConfig();
        protected virtual AdoTemplate CreateAdoTemplate(IDbProvider dbProvider);
        protected virtual IDbParameters CreateDbParameters();
        protected virtual IDbParametersBuilder CreateDbParametersBuilder();
        protected void DisposeConnection(IDbConnection conn, IDbProvider dbProvider);
    }
}
AdoDaoSupport
public class CompanyDao : AdoDaoSupport, ICompanyDao
{
    public CommonTResult<Company> Search(Guid appID, int limit, int start)
        {
            CommonTResult<Company> result = new CommonTResult<Company>();

            IDbParameters parameters = AdoTemplate.CreateDbParameters();
            parameters.AddWithValue("AppID", appID);
            parameters.AddWithValue("Limit", limit);
            parameters.AddWithValue("Start", start);
            parameters.AddOut("Count", DbType.Int32);
            result.ResultList = AdoTemplate.QueryWithRowMapper<Company>(CommandType.StoredProcedure, GET_COMPANYLIST, new CompanyMapper<Company>(), parameters);
            result.ResultCount = (int)parameters["@Count"].Value;
            return result;
        }
}

   public class CommonTResult<T>
    {
        public IList<T> ResultList { get; set; }

        public int ResultCount { get; set; }

        public T ResultT { get; set; }

        public bool IsSuccess { get; set; }

        public string Message { get; set; }
    }
CompanyDao
    public class CriticalField_LogMapper<T> : IRowMapper<T> where T : CriticalField_Log, new()
    {
        T IRowMapper<T>.MapRow(IDataReader dataReader, int rowNum)
        {
            T view = new T();
            if (DataReaderRowFilter.RowFilter(dataReader, "LogId"))
                view.LogId = dataReader.GetValueOrDefault<Guid>("LogId");
            if (DataReaderRowFilter.RowFilter(dataReader, "AppID"))
                view.AppID = dataReader.GetValueOrDefault<Guid>("AppID");
            if (DataReaderRowFilter.RowFilter(dataReader, "Operation"))
                view.Operation = dataReader.GetValueOrDefault<string>("Operation");
            if (DataReaderRowFilter.RowFilter(dataReader, "OperationStatus"))
                view.OperationStatus = dataReader.GetValueOrDefault<string>("OperationStatus");
            if (DataReaderRowFilter.RowFilter(dataReader, "OperationLog"))
                view.OperationLog = dataReader.GetValueOrDefault<string>("OperationLog");
            if (DataReaderRowFilter.RowFilter(dataReader, "ReferenceTable"))
                view.ReferenceTable = dataReader.GetValueOrDefault<string>("ReferenceTable");
            if (DataReaderRowFilter.RowFilter(dataReader, "ReferenceNumber"))
                view.ReferenceNumber = dataReader.GetValueOrDefault<string>("ReferenceNumber");
            if (DataReaderRowFilter.RowFilter(dataReader, "LogXml"))
                view.LogXml = dataReader.GetValueOrDefault<string>("LogXml");
            if (DataReaderRowFilter.RowFilter(dataReader, "ProcessBy"))
                view.ProcessBy = dataReader.GetValueOrDefault<string>("ProcessBy");
            if (DataReaderRowFilter.RowFilter(dataReader, "ProcessDate"))
                view.ProcessDate = dataReader.GetValueOrDefault<DateTime>("ProcessDate");
            if (DataReaderRowFilter.RowFilter(dataReader, "AppNo"))
                view.AppNo = dataReader.GetValueOrDefault<string>("AppNo");
            return view;
        }
    }
DaoMapper
  • AAA.IDal:定义Dao接口
  • AAA.Framework:包含很多工具类,比如Logger,MaillSend,OpenXML,Convert等。另外,本系统以MVC来做页面交互,而页面后台则以三层架构来做数据交互,而在三层这里,我们使用Spring.net的IoC做依赖注入,控制这里的Bll,Dao,Controller的实例,对应的bll-objects.xml和dal-objects.xml也放在此处
public class Logger
    {
        public Logger(Type Class)
        {
            this.classname = Class.Name;
        }

        private string classname;

        public string ClassName
        {
            get
            {
                return this.classname;
            }
            set
            {
                this.classname = value;
            }
        }

        public void SystemLog(string Message, string Method) { WriteLogInTxtFile(1, Message, Method); }

        public void InfoLog(string Message, string Method) { WriteLogInTxtFile(2, Message, Method); }

        public void DebugLog(string Message, string Method) { WriteLogInTxtFile(3, Message, Method); }

        public void ErrorLog(string Message, string Method) { WriteLogInTxtFile(4, Message, Method); }

        public void ErrorLog(Exception Ex, string Method)
        {
            string Message = String.Format("异常信息: {0}, 异常堆栈信息: {1} ", Ex.Message, Ex.StackTrace);
            ErrorLog(Message, Method);
        }

        private void WriteLogInTxtFile(Int16 LogType, string Message, string Method)
        {
            string Path = AppDomain.CurrentDomain.BaseDirectory;

            string LogFolder = "Logs";

            if (!String.IsNullOrEmpty(ConfigurationManager.AppSettings["LogFolder"]))
            {
                LogFolder = ConfigurationManager.AppSettings["LogFolder"];
            }

            string LogPathType = String.Empty;

            switch (LogType)
            {
                case 1:
                    Path += String.Format("{0}\\System\\", LogFolder);
                    LogPathType = "System";
                    break;
                case 2:
                    Path += String.Format("{0}\\Info\\", LogFolder);
                    LogPathType = "Info";
                    break;
                case 3:
                    Path += String.Format("{0}\\Debug\\", LogFolder);
                    LogPathType = "Debug";
                    break;
                case 4:
                    Path += String.Format("{0}\\Error\\", LogFolder);
                    LogPathType = "Error";
                    break;
            }

            if (!Directory.Exists(Path))
            {
                Directory.CreateDirectory(Path);
            }

            //日志文件是以当天时间命名
            string FileName = String.Format("{0}{1}", Path, "Log" + DateTime.Now.ToString("yyyyMMdd") + ".txt");

            if (!File.Exists(FileName))
            {
                File.Create(FileName).Close();
            }

            //日志格式
            string LogFormat = String.Format("Start   时间:{0}   日志类型:{1}   类名:{2}   方法名称:{3}   日志内容:{4}   End;", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), LogPathType, ClassName, Method, Message);

            using (StreamWriter writer = File.AppendText(FileName))
            {
                writer.WriteLine(LogFormat);
            }
        }
    }
Logger
private static void SendMailBySMTP(string smtpServer, string from, string to, string subject, string message, string emailCC, string emailBcc)
        {
            try
            {
                System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage();
                if (to.Contains(";"))
                {
                    string[] mails = to.Split(';');
                    foreach (string v in mails)
                    {
                        if (!String.IsNullOrEmpty(v.Trim()))
                            msg.To.Add(v);
                    }
                }
                else
                {
                    msg.To.Add(to.Trim());
                }
                if (emailCC.Contains(";"))
                {
                    if (emailCC.Substring(emailCC.Length - 1, 1) == ";")
                        emailCC = emailCC.Substring(0, emailCC.Length - 1);
                    emailCC = emailCC.Replace(';', ',');
                    msg.CC.Add(emailCC);
                }
                else
                {
                    if (!String.IsNullOrEmpty(emailCC))
                    {
                        msg.CC.Add(emailCC.Trim());
                    }
                }
                if (emailBcc.Contains(";"))
                {
                    if (emailBcc.Substring(emailBcc.Length - 1, 1) == ";")
                        emailBcc = emailBcc.Substring(0, emailBcc.Length - 1);
                    emailBcc = emailBcc.Replace(';', ',');
                    msg.Bcc.Add(emailBcc);
                }
                else
                {
                    if (!String.IsNullOrEmpty(emailBcc))
                    {
                        msg.Bcc.Add(emailBcc.Trim());
                    }
                }
                msg.From = new System.Net.Mail.MailAddress(from);
                msg.Subject = subject;
                msg.SubjectEncoding = System.Text.Encoding.UTF8;
                msg.Body = message;
                msg.BodyEncoding = System.Text.Encoding.UTF8;
                msg.IsBodyHtml = true;
                msg.Priority = System.Net.Mail.MailPriority.High;
                System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
                client.Host = smtpServer;

                Log.DebugLog(" msg.To:" + msg.To, MethodBase.GetCurrentMethod().Name);
                Log.DebugLog(" msg.CC:" + msg.CC, MethodBase.GetCurrentMethod().Name);
                Log.DebugLog(" msg.Bcc:" + msg.Bcc, MethodBase.GetCurrentMethod().Name);
                Log.DebugLog(" smtpServer:" + smtpServer, MethodBase.GetCurrentMethod().Name);
                client.Send(msg);
            }
            catch (Exception ex)
            {
                Log.ErrorLog(ex, MethodBase.GetCurrentMethod().Name);
            }
        }
MailSend
public string MailMerge(string docFileName, string dataFileName, string outFileName)
        {
            object oFileName = docFileName;
            object oOutFileName = outFileName;
            //Word.Application wordApp = new Word.Application();
            object missing = System.Reflection.Missing.Value;
            object oTrue = true;
            object oFalse = false;
            object password = string.Format("MLES_{0}", DateTime.Now.ToString("yyyyMMdd"));
            Application app = new Application();

            try
            {
                app.Documents.Open(ref oFileName, ref oFalse, ref oTrue,
ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
app.ActiveDocument.MailMerge.OpenDataSource(dataFileName, ref missing, ref oFalse, ref oTrue, ref oTrue, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
                app.ActiveDocument.MailMerge.SuppressBlankLines = false;
                app.ActiveDocument.MailMerge.Destination = WdMailMergeDestination.wdSendToNewDocument;
                app.ActiveDocument.MailMerge.Execute(ref oFalse);
                app.ActiveDocument.SaveAs(ref oOutFileName, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,  ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
                app.ActiveDocument.Saved = true;

                return "Created Document: " + outFileName;
            }
            catch (Exception ex)
            {
                return "";
            }

            finally
            {
                app.ActiveDocument.Close(ref oFalse, ref missing, ref missing);
                app.Quit(ref missing, ref missing, ref missing);

            }
        }
MailMerge
public DataTable PriovetTableData(DataTable dt)
        {
            DataTable dtNew = new DataTable();
            dtNew.Columns.Add("ColumnName", typeof(string));
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                dtNew.Columns.Add("Value" + i.ToString(), typeof(string));
            }

            foreach (DataColumn dc in dt.Columns)
            {
                DataRow drNew = dtNew.NewRow();
                drNew["ColumnName"] = dc.ColumnName;
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    drNew[i + 1] = dt.Rows[i][dc].ToString();
                }
                dtNew.Rows.Add(drNew);
            }
            return dtNew;
        }
PriovetTableData

在DAL配置中,我们加入了Transaction 和 AOP

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
         xmlns:db="http://www.springframework.net/database"
         xmlns:tx="http://www.springframework.net/tx">

    <object id="dbProvider" type="Spring.Data.Common.UserCredentialsDbProvider, Spring.Data">
        <property name="TargetDbProvider" ref="targetDbProvider"/>
    </object>

    <db:provider id="targetDbProvider" provider="System.Data.SqlClient"
        connectionString=""/>

    <object id="adoTemplateT" type="Spring.Data.Generic.AdoTemplate, Spring.Data">
        <property name="DbProvider" ref="dbProvider"/>
        <property name="DataReaderWrapperType" value="Spring.Data.Support.NullMappingDataReader, Spring.Data"/>
    </object>

    <object id="companyDao" type="AAA.Dal.application.CompanyDao, AAA.Dal">
        <property name="AdoTemplate" ref="adoTemplateT"/>
    </object>

.......

<!--事务管理器-->
<!--
  <object id="transactionManager"
         type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
    <property name="DbProvider" ref="DbProvider"/>
  </object> 
-->
<!--事务切面-->
<!--<tx:attribute-driven/>-->
  <object id="transactionManager"
        type="Spring.Data.Core.AdoPlatformTransactionManager, Spring.Data">
    <property name="DbProvider" ref="dbProvider"/>
  </object>

  <object id="proxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxyCreator, Spring.Aop">
    <property name="ObjectNames">
      <list>
        <value>*Handler</value>
        <!--<value>*Controller</value>-->
        <!--<value>loanApprovalLetterHandler</value>-->
      </list>
    </property>
    <property name="InterceptorNames" >
      <list>
        <value>throwsAdvice</value>
        <!--<value>transactionInterceptor</value>-->
        <!--<value>aroundAdvisor</value>-->
      </list>
    </property>
  </object>

  <!-- Transaction Interceptor -->
  <object id="transactionInterceptor"
          type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
    <property name="TransactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
      <name-values>
        <add key="Save*" value="PROPAGATION_NESTED"/>
        <add key="Add*" value="PROPAGATION_REQUIRED,timeout_1"/>
        <add key="Delete*" value="PROPAGATION_REQUIRED"/>
        <add key="Update*" value="PROPAGATION_REQUIRED"/>
        <add key="Get*" value="PROPAGATION_REQUIRED,readOnly"/>
        <!--<add key="Load*" value="PROPAGATION_REQUIRED,readOnly"/>
        <add key="Query*" value="PROPAGATION_REQUIRED,readOnly"/>
        <add key="Search*" value="PROPAGATION_REQUIRED,readOnly"/>-->
      </name-values>
    </property>
  </object>
  <!-- Throws Advice to log exception-->
  <object id="throwsAdvice"  type="AAA.Framework.ThrowsAdvice, AAA.Framework" />

  <!--Around Advisor -->
  <object id="aroundAdvisor" type="Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop">
    <property name="Advice" ref="aroundAdvice"/>
    <property name="MappedNames">
      <list>
        <value>*</value>
      </list>
    </property>
  </object>
  <object id="aroundAdvice" type="AAA.Framework.AroundAdvice,AAA.Framework"/>

</objects>
dal-objects
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">

    <object id="CompanyController" singleton="false"  type="AAA.Mvc.Controllers.CompanyController,AAA.Mvc.Controllers">
        <property name="CompanyHandler" ref="companyHandler"/>
    </object>
    <object id="companyHandler" singleton="false"  type="AAA.BLL.CompanyHandler,AAA.BLL">
        <property name="CompanyDao" ref="companyDao"/>
    </object>
.......
</objects>
bll-objects
public class AroundAdvice : IMethodInterceptor
    {
        public object Invoke(IMethodInvocation invocation)
        {
            Logger log = new Logger(MethodBase.GetCurrentMethod().DeclaringType);

            log.DebugLog(string.Format("Before: invocation=[{0}]", invocation), "Invoke");
            object result = invocation.Proceed();
            log.DebugLog(string.Format("After : invocation=[{0}]", invocation), "Invoke");
            return result;
        }
    }

public class ThrowsAdvice : IThrowsAdvice
    {
        public void AfterThrowing(Exception ex)
        {
            Logger log = new Logger(MethodBase.GetCurrentMethod().DeclaringType);
            log.DebugLog(ex.ToString(), "AfterThrowing");
        }
    }
AOP

此处将每个部分的摘录部分代码供参考。

 

posted @ 2015-07-15 17:04  Ying8972  阅读(395)  评论(0编辑  收藏  举报