Spring.Net中的IOC,DI相关配置以及实现,Spring.Net在MVC中的运用,队列的初次使用,Log4Net日志处理完善错误处理
OA项目第三天 Spring.Net中的IOC实现 首先我们先下载最新版本(貌似不会再更新了), https://blog.csdn.net/cctvcqupt/article/details/18600091
中文手册:http://vdisk.weibo.com/s/EzlFk3ZRCmti
然后我们在工程文件下创建一个lib文件夹,把需要的dll拷贝进去,添加引用
1 2 3 4 Common .Logging . dllSpring .Core . dllSpring .Core . pdb Spring.Core
根据文档的IoC快速入门,我们开始以下操作,配置config(自动排序下)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <?xml version="1.0" encoding="utf-8" ?> <configuration > <configSections > <sectionGroup name ="spring" > <section name ="context" type ="Spring.Context.Support.ContextHandler, Spring.Core" /> <section name ="objects" type ="Spring.Context.Support.DefaultSectionHandler, Spring.Core" /> </sectionGroup > </configSections > <spring > <context > <resource uri ="config://spring/objects" /> </context > <objects xmlns ="http://www.springframework.net" > <description > An example that demonstrates simple IoC features.</description > <object name ="UserInfoServer" type ="SpringNetDemo.UserInfoServer, SpringNetDemo" > </object > </objects > </spring > </configuration >
在配置文件中,通过 节点的 子节点来配置程序中用到的对象。 我们定义了UserInfoServer和IUserInfoServer,里面一个简单的ShowMsg方法
1 2 3 IApplicationContext ctx = ContextRegistry.GetContext(); IUserInfoServer lister = (IUserInfoServer)ctx.GetObject("UserInfoServer" ); MessageBox.Show(lister.ShowMsg());
Spring.Net中的DI操作 首先我们前面的每定义一个Object,都得在Objects节点下添加,现在我们有一个更加便捷的方法,那就是新建一个xml文件,然后右键属性-复制到输出目录-这里选始终复制或者较新复制都可以,因为Spring.NETd的做法是在bin debug目录下去读取文件。 然后我们可以把object节点放在这个xml文件下
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="utf-8" ?> <objects xmlns ="http://www.springframework.net" > <description > An example that demonstrates simple IoC features.</description > <object name ="UserInfoServer" type ="SpringNetDemo.UserInfoServer, SpringNetDemo" > <property name ="Name" value ="龙龟纹" /> <property name ="Person" ref ="Person" /> </object > <object name ="Person" type ="SpringNetDemo.Person, SpringNetDemo" > <property name ="Age" value ="12" /> </object > </objects >
在context节点下引用上面的xml
1 2 3 4 <context > <resource uri ="config://spring/objects" /> <resource uri ="file://server.xml" /> </context >
然后我们修改下user infoserver类
1 2 3 4 5 6 public interface IUserInfoServer { string Name { get ; set ; } Person Person { get ; set ; } string ShowMsg ( ) ; }
1 2 3 4 5 6 7 public string Name { get ; set ; } public Person Person { get ; set ; } public string ShowMsg ( ) { return "我是Ioc," +Name+"年龄是:" +Person.Age; }
输出
1 2 3 我是Ioc,龙龟纹年龄是:12 --------------------------- 确定
Spring.Net在MVC的应用 在Asp.net MVC中应该怎样使用Spring.Net?
先导入dll文件。
将案例中的Config文件夹拷贝到项目中。
修改Config文件夹中的相关的配置信息。参考上面的IOC和DI操作
修改Web.config文件中的配置。
可以将Config/controllers.xml文件中的配置信息分离(可以将控制器的配置与业务类的配置分离。)注意web.config文件中也要修改一下。
修改Global文件.继承SpringMvcApplication
记住,要是报错,安装negut包,webapi。
异常处理 mvc中有一个异常处理过滤器。我们可以自己写一个过滤器然后继承它,重写OnException方法,只要我们程序某一个控制器下某一个方法出错,都可以触发。当然现在的这个队列是在我们这台服务器上,后面我们还要做成分布式的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class MyExceptionAttribute :HandleErrorAttribute { public static Queue <Exception > ExecptionQueue = new Queue<Exception>(); public override void OnException (ExceptionContext filterContext ) { base .OnException(filterContext); Exception ex = filterContext.Exception; ExecptionQueue.Enqueue(ex); filterContext.HttpContext.Response.Redirect("/Error.html" ); } }
必须还要注册一下(App_Start文件夹下)
1 2 3 4 5 6 7 8 public class FilterConfig { public static void RegisterGlobalFilters (GlobalFilterCollection filters ) { filters.Add(new MyExceptionAttribute()); } }
按照流程,我们是要开启一个线程去处理队列中的错误日志,那么线程在哪开启呢?我们可以在Application_Start方法中开启,当然这里的线程需要一个死循环去一直查看队列中的错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 protected void Application_Start ( ) { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); string filepath = Server.MapPath("/Log/" ); ThreadPool.QueueUserWorkItem((a) => { while (true ) { if (MyExceptionAttribute.ExecptionQueue.Count > 0 ) { Exception ex = MyExceptionAttribute.ExecptionQueue.Dequeue(); if (ex != null ) { string fileName = DateTime.Now.ToString("yyyy-MM-dd" ); File.AppendAllText(filepath + fileName + ".txt" , ex.ToString(), Encoding.UTF8); } else { Thread.Sleep(3000 ); } } else { Thread.Sleep(3000 ); } } }, filepath); }
当然这种做法其实不是很好,如果要是需要我们把日志写到其他地方,数据库之类的就不太方便了。至少要修改代码。因此我们需要下面的解决办法
Log4Net日志处理
具体配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <section name ="log4net" type ="log4net.Config.Log4NetConfigurationSectionHandler, log4net" /> <log4net > <root > <level value ="ERROR" /> <appender-ref ref ="SysAppender" /> </root > <logger name ="WebLogger" > <level value ="ERROR" /> </logger > <appender name ="SysAppender" type ="log4net.Appender.RollingFileAppender,log4net" > <param name ="File" value ="App_Data/" /> <param name ="AppendToFile" value ="true" /> <param name ="RollingStyle" value ="Date" /> <param name ="DatePattern" value ="" Logs_" yyyyMMdd" .txt" " /> <param name ="StaticLogFileName" value ="false" /> <layout type ="log4net.Layout.PatternLayout,log4net" > <param name ="ConversionPattern" value ="%d [%t] %-5p %c - %m%n" /> <param name ="Header" value =" ----------------------header-------------------------- " /> <param name ="Footer" value =" ----------------------footer-------------------------- " /> </layout > </appender > <appender name ="consoleApp" type ="log4net.Appender.ConsoleAppender,log4net" > <layout type ="log4net.Layout.PatternLayout,log4net" > <param name ="ConversionPattern" value ="%d [%t] %-5p %c - %m%n" /> </layout > </appender > </log4net >
怎么用(web应用)?在程序入口处也就是global下的Application_Start方法添加
1 2 3 4 log4net.Config.XmlConfigurator.Configure(); ILog logger = LogManager.GetLogger("errorMsg" ); logger.Error(ex.ToString());
完成登陆 这里的素材用的是网上的,先把图片放在Content文件夹,前端直接复制到Index视图,做好jq,ajax,以及表单的js引用。
表单
1 2 3 4 5 6 7 8 @using (Ajax.BeginForm("UserLogin", "Login", new { }, new AjaxOptions() { HttpMethod = "post", OnSuccess = "afterLogin", LoadingElementId = "div1" }, new { id = "loginForm" })) { <table cellpadding ="0" cellspacing ="0" > ......//前面的省略 <input type ="button" id ="btnLogin" value ="登录" class ="login-btn" /> <span id ="errorMsg" style ="font-size: 14px; color: red; display: none" > </span > <div id ="div1" style ="display: none" > 正在登录,请稍后....</div > </table > }
1 2 3 4 5 6 $(function () { $("#btnLogin" ).click(function () { validateInfo($("#loginForm" )); $("#loginForm" ).submit(); }); });
ajax回调函数
1 2 3 4 5 6 7 8 9 10 function afterLogin (data ) { var serverDate = data.split(":" ); if (serverDate[0 ] == "OK" ) { location.href = "/Home/Index" ; } else { $("#errorMsg" ).css("display" , "block" ); $("#errorMsg" ).text(serverDate[1 ]); changeCheckCode(); } }
验证码函数(就是给看不清楚重新点击的a标签更改src属性)
1 2 3 function changeCheckCode ( ) { $("#img" ).attr("src" , $("#img" ).attr("src" ) + 1 ); }
统一Sesson校验(我们后面用的是memcached进行校验) APS.NET MVC中的每一个请求,都会分配给相应的控制器和对应的行为方法去处理,而在这些处理的前前后后如果想再加一些额外的逻辑处理。这时候就用到了过滤器。具体的可以看这里:https://blog.csdn.net/heyangyi_19940703/article/details/51259684,其实我们上面的处理日志的OnException重写方法,也可以是继承Controller
1 2 3 4 5 6 7 8 9 protected override void OnActionExecuting (ActionExecutingContext filterContext ) { base .OnActionExecuting(filterContext); if (Session["userinfo" ]==null ) { filterContext.Result = Redirect("/Login/Index" ); } }
然后让我们的UserInfoController : BaseController
**但是这样一来,我们的流程是这样的,浏览器请求UserInfoController,然后走到Sesson校验,然后它还是会继续往下走的,因为我们没有返回一个ActionResult,不像WebForm.因此还是会继续执行控制器下的方法。因此我们在过滤器那里返回一个。filterContext.Result = Redirect(“/Login/Index”); **
现在我们把登陆信息放在session,其实是有问题的。要是我们部署之后用户访问量大,那么效果久不太好。当我们的服务器有多台构建了一个集群的时候,我们先向A服务器请求,然后session赋值,然后跳转到B,但是B中没有session值,这时候久出现问题了。我们可以把缓存数据放到一台装有Memcache服务的机器上,存到内存里,这就是分布式缓存。这是共享的,而我们的session是每个人都专门在服务器内存上开辟储存的,因此我们在Memcache上必须解决这存的信息到底是谁是谁的。键值对,键不一样就行