所有的程序集引用,都可以在Nuget中获取,需要注意除了Spring和NHibenate的程序集外,还要引用Spring.Net NHibernate Support。
为了结构清晰,我把各层的配置都放在了Config文件夹下,NH的映射文件存放于Model层中的Mappings文件夹下,如图,额,由于课程题目,这是一个简单的二手车交易系统 。
首先是Car.Web种web.config的配置,除了配置还有MVC5自动给添加的EF的东西,此外添加了log4net,配置很简单,具体的使用可以自定义全局错误过滤器,写日志即可,这里就不贴代码了。
然后是Dao层的SpringNHibernate.xml配置
说明:
(1)我们把数据库的连接信息放在了web.config中,SpringNHibernate的配置中先使用PropertyPlaceholderConfigurer让Spring去读取了web.config中的配置信息,再用${xxx}方式获取Spring中的这些信息,也就是间接从web.config中读取配置,因为Spring.NET的配置文件要求我们需要将xml设置为“嵌入的资源”,如果直接写在Spring相关的配置文件,这样一来在程序编译后就不能够修改,所以配置于web.config可以动态改变
(1)首先从Dao层说起,在Model层的类库中添加一个User实体,并在Mappings文件夹下添加User.hbm.xml,完成NH对实体的映射,这里主要看配置,就不贴User类的代码了,就是几个属性。
在Dao层添加INHibernateSessionFactory接口
public interface INHibernateSessionFactory
{
ISessionFactory SessionFactory { set; get; }
}
以及Dao类,Dao接口的代码我就直接省略了,无非是方法声明,另外我这里命名是BaseDao,不是UserDao,包括下面的Service层,因为封装的是泛型方法,可以供任意实体使用。
另外,实现INHibernateSessionFactory接口是需要让spring帮我们管理SessionFactory对象。
public class BaseDao:IBaseDao,INHibernateSessionFactory
{
///
/// 通过注入
///
public ISessionFactory SessionFactory { get; set; }
public void SaveOrUpdate(Object obj)
{
ISession session = SessionFactory.OpenSession();
ITransaction tran = session.BeginTransaction();
try
{
session.SaveOrUpdate(obj);
tran.Commit();
}
catch (Exception)
{
tran.Rollback();
throw;
}
}
}
最后配置Dao层,在Config文件夹中添加Dao.xml
这里是Dao层的配置
可以看到,这里添加了Dao类的声明,希望由Spring给我们管理它,property还告诉Spring,Dao类需要依赖一个属性,SessionFactory,希望Spring给我们自动注入它。
public class BaseService : IBaseService
{
///
/// 通过注入
///
public IBaseDao BaseDao { get; set; }
public void SaveOrUpdate(Object obj)
{
BaseDao.SaveOrUpdate(obj);
}
}
public class HomeController : Controller
{
///
/// 通过注入
///
public IBaseService BaseService { get; set; }
public ActionResult Index()
{
BaseService.SaveOrUpdate(new User{ Name="ASP.NET" });
return View();
}
}
1、比较原始的,自定义MVC扩展的Contoller工厂,手动的调用Spring上下文根据路由匹配的名称来实例化Controller,首先自定义Contoller工厂SpringControllerFactory
public class SpringControllerFactory : IControllerFactory
{
private static DefaultControllerFactory defalutf = null;
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
//spring context
IApplicationContext ctx = ContextRegistry.GetContext();
string controller = controllerName + "Controller";
//查找是否配置该Controller
if (ctx.ContainsObject(controller))
{
object controllerf = ctx.GetObject(controller);
return (IController)controllerf;
}
else
{
if (defalutf == null)
{
defalutf = new DefaultControllerFactory();
}
return defalutf.CreateController(requestContext, controllerName);
}
}
public void ReleaseController(IController controller)
{
//get spring context
IApplicationContext ctx = ContextRegistry.GetContext();
if (!ctx.ContainsObject(controller.GetType().Name))
{
if (defalutf == null)
{
defalutf = new DefaultControllerFactory();
}
defalutf.ReleaseController(controller);
}
}
public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
{
return SessionStateBehavior.Default;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ControllerBuilder.Current.SetControllerFactory(typeof(SpringControllerFactory));
}
public class MvcApplication : Spring.Web.Mvc.SpringMvcApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//ControllerBuilder.Current.SetControllerFactory(typeof(SpringControllerFactory));
}
}
看到前辈们12年就有这几个框架的整合了,而今MVC6也已全面支持依赖注入,EF也是各种强大,倒是不知道哪个组合更胜一筹。
另外说明一下
1、其实我删去了一些关于事务和AOP的配置,还没理解Spring.Net对NH声明式事务的配置是怎样管理和使用的,上面贴的代码都是手动管理的事务。。,事务配置参考这篇文章。
2、其实还应该让spring来管理Hibernate的Session对象,它会自动的帮我们实现一次请求中Session对象的唯一性,我这个例子也没有实现对Session对象的处理,还不太了解怎么做配置和使用。如果需要手动管理的话,也不是很复杂,因为Hibernate提供了一些这方面的实现,不需要我们手动去搞什么setData,getData了。参考这篇文章。