上一次我们完成了数据访问层的接口和实现,这次我们按部就班的完成业务层接口及实现,并采用spring.net声明式事务.另外,采用nunit对业务实现进行单元测试.
象petshop框架一样,我们先定义业务层接口,这里只和实体有有耦合.我们拿用户User为例:
IUserManager
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->using DirectCenter.Model;
namespace DirectCenter.IBLL
{
/// <summary>
/// 用户管理
/// </summary>
public interface IUserManager
{
/// <summary>
/// 创建一个用户(返回包含默认值)
/// </summary>
/// <returns></returns>
User NewUser();
/// <summary>
/// 保存用户
/// </summary>
/// <param name="user">用户实体</param>
/// <returns></returns>
User SaveUser(User user);
/// <summary>
/// 获取用户
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
User GetUser(string userId);
/// <summary>
/// 删除用户
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
void DeleteUser(string userId);
/// <summary>
/// 更新用户
/// </summary>
/// <param name="user">用户实体</param>
/// <returns></returns>
User UpdateUser(User user);
}
}
同理,这里也是简单使出了几个通常的增删改查的接口,其它的业务接口我们在接下来的前台实现中,再来添加.
UserManager
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->#region Imports
using System;
using System.Collections;
using System.Text;
using DirectCenter.IBLL;
using DirectCenter.IDAL;
using DirectCenter.Model;
#endregion
namespace DirectCenter.BLL
{
public class UserManager:IUserManager
{
#region Properties
public IUserDao UserDao { get; set; }
#endregion
/// <summary>
/// 创建一个用户(返回包含默认值)
/// </summary>
/// <returns></returns>
public User NewUser()
{
var user = new User();
//可以采用系统配置
user.CreateTime = DateTime.Now;
user.ValidFrom = DateTime.Now;
user.ValidTo = Convert.ToDateTime("2999-12-31");
return user;
}
/// <summary>
/// 保存用户
/// </summary>
/// <param name="user">用户实体</param>
/// <returns></returns>
public User SaveUser(User user)
{
Validate(user);
if (GetUser(user.UserID) != null)
throw new Exception("已经存在的用户");
return UserDao.Save(user);
}
/// <summary>
/// 获取用户
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public User GetUser(string userId)
{
return UserDao.FindById(userId);
}
/// <summary>
/// 删除用户
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
public void DeleteUser(string userId)
{
var user = new User();
user.UserID = userId;
UserDao.Delete(user);
}
/// <summary>
/// 更新用户
/// </summary>
/// <param name="user">用户实体</param>
/// <returns></returns>
public User UpdateUser(User user)
{
return UserDao.SaveOrUpdate(user);
}
private void Validate(User user)
{
//TODO throw exception on error.
}
}
}
UserManager
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> <object id="UserManager" type="DirectCenter.BLL.UserManager,DirectCenter.BLL">
<property name="UserDao" ref="UserDao"/>
</object>
UserDao这个对象在上一次的Dao.xml中已经定义过了.
接下来我们来实现声明式事务,在Services.xml中添加:
transactionManager
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> <object id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate20">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="NHibernateSessionFactory"/>
</object>
<object id="TransactionInterceptor" type="Spring.Transaction.Interceptor.TransactionInterceptor, Spring.Data">
<property name="TransactionManager" ref="transactionManager"/>
<property name="TransactionAttributeSource">
<object type="Spring.Transaction.Interceptor.AttributesTransactionAttributeSource, Spring.Data"/>
</property>
</object>
<object id="BaseTransactionManager" type="Spring.Transaction.Interceptor.TransactionProxyFactoryObject" abstract="true">
<property name="PlatformTransactionManager" ref="transactionManager"/>
<property name="TransactionAttributes">
<name-values>
<add key="Save*" value="PROPAGATION_REQUIRED"/>
<add key="Set*" value="PROPAGATION_REQUIRED"/>
<add key="Finish*" value="PROPAGATION_REQUIRED"/>
<add key="Update*" value="PROPAGATION_REQUIRED"/>
<add key="Delete*" value="PROPAGATION_REQUIRED"/>
<add key="Add*" value="PROPAGATION_REQUIRED"/>
<add key="Get*" value="PROPAGATION_REQUIRED,readOnly"/>
<add key="Find*" value="PROPAGATION_REQUIRED,readOnly"/>
<add key="Load*" value="PROPAGATION_REQUIRED,readOnly"/>
<add key="*" value="PROPAGATION_REQUIRED"/>
</name-values>
</property>
</object>
TransactionAttributes中的列出的值表示对对应的方法采用事务,比如对Save开头的方法支持事务.(*是通配符),其中value的值可以有以下几种:
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作.
readOnly表示此方法只读的,不能够修改数据
关于声明式事务的一些细节在下面的两个文章中可以了解详细些:
http://javabrain.javaeye.com/blog/106391
http://caterpillar.onlyfun.net/GossipCN/SpringGossip/TransactionAttributeSource.html
接着,我们再添加采用了事务的业务对象,继承于我们声明的事务基类.
UserManagerTrans
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> <object id="UserManagerTrans" parent="BaseTransactionManager">
<property name="Target" ref="UserManager"/>
</object>
这样就完成了业务部分,让我们测试一下吧.首先添加Services.xml到objects.xml中.接下来就添加UserManagerTest.cs来完成对用户保存的测试:
UserManagerTest.cs
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->using System;
using NUnit.Framework;
using Spring.Testing.NUnit;
using DirectCenter.Model;
using DirectCenter.IBLL;
namespace DirectCenter.UnitTest
{
[TestFixture]
public class UserManagerTest :AbstractTransactionalDbProviderSpringContextTests
{
protected override string[] ConfigLocations
{
get
{
return new String[] { "objects.xml" };
}
}
protected IUserManager UserManager
{
get
{
return applicationContext.GetObject("UserManagerTrans") as IUserManager;
}
}
[Test]
public void SaveUserTest()
{
User user = UserManager.NewUser();
user.UserID = "buyer0p";
user.Password = "admin";
user.UserName = "刘翔";
UserManager.SaveUser(user);
transactionManager.Commit(transactionStatus);
}
}
}
采用声明式事务的好处就是把事务的操作和数据访问的限制从具体的业务层中解耦出来,在实际写业务层的时候,不用关心事务的操作,同样,在这里也可以采用aop的方式实现日志,异常,权限.
本次代码下载