- 浏览: 93842 次
- 性别:
- 来自: 深圳
文章分类
最新评论
1. 前言
Struts 是目前Java Web MVC框架中不争的王者。经过长达五年的发展,Struts已经逐渐成长为一个稳定、成熟的框架,并且占有了MVC框架中最大的市场份额。但是Struts<!----><!---->某些技术特性上已经落后于新兴的MVC框架。面对Spring MVC、Webwork2 这些设计更精密,扩展性更强的框架,Struts受到了前所未有的挑战。但站在产品开发的角度而言,Struts仍然是最稳妥的选择。本文的原型例子JpetStore 4.0就是基于Struts开发的,但是不拘泥于Struts的传统固定用法,例如只用了一个自定义Action类,并且在form bean类的定义上也是开创性的,令人耳目一新,稍后将具体剖析一下。
Spring Framework 实际上是Expert One-on-One J2EE Design and Development 一书中所阐述的设计思想的具体实现。Spring Framework的功能非常多。包含AOP、ORM、DAO、Context、Web、MVC等几个部分组成。Web、MVC暂不用考虑,JpetStore 4.0用的是更成熟的Struts和JSP;DAO由于目前Hibernate、JDO、ibatis的流行,也不考虑,JpetStore 4.0用的就是ibatis。因此最需要用的是AOP、ORM、Context。Context中,最重要的是Beanfactory,它能将接口与实现分开,非常强大。目前AOP应用最成熟的还是在事务管理上。
ibatis 是一个功能强大实用的SQL Map工具,不同于其他ORM工具(如hibernate),它是将SQL语句映射成Java对象,而对于ORM工具,它的SQL语句是根据映射定义生成的。ibatis 以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。有ibatis代码生成的工具,可以根据DDL自动生成ibatis代码,能减少很多工作量。
2. JpetStore简述
2.1. 背景
最初是Sun公司的J2EE petstore,其最主要目的是用于学习J2EE,但是其缺点也很明显,就是过度设计了。接着Oracle用J2EE petstore来比较各应用服务器的性能。微软推出了基于.Net平台的 Pet shop,用于竞争J2EE petstore。而JpetStore则是经过改良的基于struts的轻便框架J2EE web应用程序,相比来说,JpetStore设计和架构更优良,各层定义清晰,使用了很多最佳实践和模式,避免了很多"反模式",如使用存储过程,在java代码中嵌入SQL语句,把HTML存储在数据库中等等。最新版本是JpetStore 4.0。
2.2. JpetStore开发运行环境的建立
1、开发环境
Java SDK 1.4.2
Apache Tomcat 4.1.31
Eclipse-SDK-3.0.1-win32
HSQLDB 1.7.2
2、Eclipse插件
EMF SDK 2.0.1:Eclipse建模框架,lomboz插件需要,可以使用runtime版本。
lomboz 3.0:J2EE插件,用来在Eclipse中开发J2EE应用程序
Spring IDE 1.0.3:Spring Bean配置管理插件
xmlbuddy_2.0.10:编辑XML,用免费版功能即可
tomcatPluginV3:tomcat管理插件
Properties Editor:编辑java的属性文件,并可以预览以及自动存盘为Unicode格式。免去了手工或者ANT调用native2ascii的麻烦。
2.3. 架构
图1 是JPetStore架构图。参照这个架构图,让我们稍微剖析一下源代码,得出JpetStore 4.0的具体实现图(图2),思路一下子就豁然开朗了。前言中提到的非传统的struts开发模式,关键就在struts Action类和form bean类上。
struts Action类只有一个:BeanAction。没错,确实是一个!与传统的struts编程方式很不同。再仔细研究BeanAction类,发现它其实是一个通用类,利用反射原理,根据URL来决定调用formbean的哪个方法。BeanAction大大简化了struts的编程模式,降低了对struts的依赖(与struts以及WEB容器有关的几个类都放在com.ibatis.struts包下,其它的类都可以直接复用)。利用这种模式,我们会很容易的把它移植到新的框架如JSF,spring。
这样重心就转移到form bean上了,它已经不是普通意义上的form bean了。查看源代码,可以看到它不仅仅有数据和校验/重置方法,而且已经具有了行为,从这个意义上来说,它更像一个BO(Business Object)。这就是前文讲到的,BeanAction类利用反射原理,根据URL来决定调用form bean的哪个方法(行为)。form bean的这些方法的签名很简单,例如:
public String myActionMethod() { //..work return "success"; } |
方法的返回值直接就是字符串,对应的是forward的名称,而不再是ActionForward对象,创建ActionForward对象的任务已经由BeanAction类代劳了。另外,程序还提供了ActionContext工具类,该工具类封装了request 、response、form parameters、request attributes、session attributes和 application attributes中的数据存取操作,简单而线程安全,form bean类使用该工具类可以进一步从表现层框架解耦。在这里需要特别指出的是,BeanAction类是对struts扩展的一个有益尝试,虽然提供了非常好的应用开发模式,但是它还非常新,一直在发展中。
下面就让我们开始进一步分析JpetStore4.0的源代码,为下面的改造铺路。BeanAction.java是唯一一个Struts action类,位于com.ibatis.s<!----><!---->truts包下。正如上文所言,它是一个通用的控制类,利用反射机制,把控制转移到form bean的某个方法来处理。详细处理过程参考其源代码,简单明晰。
Form bean类位于com.ibatis.jpetstore.presentation包下,命名规则为***Bean。Form bean类全部继承于BaseBean类,而BaseBean类实际继承于ActionForm,因此,Form bean类就是Struts的 ActionForm,Form bean类的属性数据就由struts框架自动填充。而实际上,JpetStore4.0扩展了struts中ActionForm的应用: Form bean类还具有行为,更像一个BO,其行为(方法)由BeanAction根据配置(struts-config.xml)的URL来调用。虽然如此,我们还是把Form bean类定位于表现层。Struts-config.xml的配置里有3种映射方式,来告诉BeanAction把控制转到哪个form bean对象的哪个方法来处理。以这个请求连接为例http://localhost/jpetstore4/shop/viewOrder.do
1. URL Pattern
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> |
此种方式表示,控制将被转发到"orderBean"这个form bean对象 的"viewOrder"方法(行为)来处理。方法名取"path"参数的以"/"分隔的最后一部分。
2. Method Parameter
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" parameter="viewOrder" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> |
此种方式表示,控制将被转发到"orderBean"这个form bean对象的"viewOrder"方法(行为)来处理。配置中的"parameter"参数表示form bean类上的方法。"parameter"参数优先于"path"参数。
3. No Method call
<action path="/shop/viewOrder" type="com.ibatis.struts.BeanAction" name="orderBean" parameter="*" scope="session" validate="false"> <forward name="success" path="/order/ViewOrder.jsp"/> </action> |
此种方式表示,form bean上没有任何方法被调用。如果存在"name"属性,则struts把表单参数等数据填充到form bean对象后,把控制转发到"success"。否则,如果name为空,则直接转发控制到"success"。这就相当于struts内置的org.apache.struts.actions.ForwardAction的功能
<action path="/shop/viewOrder" type="org.apache.struts.actions.ForwardAction" parameter="/order/ViewOrder.jsp " scope="session" validate="false"> </action> |
Service类位于com.ibatis.jpetstore.service包下,属于业务层。这些类封装了业务以及相应的事务控制。Service类由form bean类来调用。
com.ibatis.jpetstore.persistence.iface包下的类是DAO接口,属于业务层,其屏蔽了底层的数据库操作,供具体的Service类来调用。DaoConfig类是工具类(DAO工厂类),Service类通过DaoConfig类来获得相应的DAO接口,而不用关心底层的具体数据库操作,实现了如图2中{耦合2}的解耦。
com.ibatis.jpetstore.persistence.sqlmapdao包下的类是对应DAO接口的具体实现,在JpetStore4.0中采用了ibatis来实现ORM。这些实现类继承BaseSqlMapDao类,而BaseSqlMapDao类则继承ibatis DAO 框架中的SqlMapDaoTemplate类。ibatis的配置文件存放在com.ibatis.jpetstore.persistence.sqlmapdao.sql目录下。这些类和配置文件位于数据层
Domain类位于com.ibatis.jpetstore.domain包下,是普通的javabean。在这里用作数据传输对象(DTO),贯穿视图层、业务层和数据层,用于在不同层之间传输数据。剩下的部分就比较简单了,请看具体的源代码,非常清晰。
JpetStore4.0的关键就在struts Action类和form bean类上,这也是其精华之一(虽然该实现方式是试验性,待扩充和验证),在此次改造中我们要保留下<!----><!---->来,即控制层一点不变,表现层获取相应业务类的方式变了(要加载spring环境),其它保持不变。要特别关注的改动是业务层和持久层,幸运的是JpetStore4.0设计非常好,需要改动的地方非常少,而且由模式可循,如下:
1. 业务层和数据层用Spring BeanFactory机制管理。
2. 业务层的事务由spring 的aop通过声明来完成。
3. 表现层(form bean)获取业务类的方法改由自定义工厂类来实现(加载spring环境)。
3. JPetStore的改造
3.1. 改造后的架构
其中红色部分是要增加的部分,蓝色部分是要修改的部分。下面就让我们逐一剖析。
3.2. Spring Context的加载
为了在Struts中加载Spring Context,一般会在struts-config.xml的最后添加如下部分:
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn"> <set-property property="contextConfigLocation" value="/WEB-INF/applicationContext.xml" /> </plug-in> |
Spring在设计时就充分考虑到了与Struts的协同工作,通过内置的Struts Plug-in在两者之间提供了良好的结合点。但是,因为在这里我们一点也不改动JPetStore的控制层(这是JpetStore4.0的精华之一),所以本文不准备采用此方式来加载ApplicationContext。我们利用的是spring framework 的BeanFactory机制,采用自定义的工具类(bean工厂类)来加载spring的配置文件,从中可以看出Spring有多灵活,它提供了各种不同的方式来使用其不同的部分/层次,您只需要用你想用的,不需要的部分可以不用。
具体的来说,就是在com.ibatis.spring包下创建CustomBeanFactory类,spring的配置文件applicationContext.xml也放在这个目录下。以下就是该类的全部代码,很简单:
public final class CustomBeanFactory { static XmlBeanFactory factory = null; static { Resource is = new InputStreamResource( CustomBeanFactory.class.getResourceAsStream("applicationContext.xml")); factory = new XmlBeanFactory(is); } public static Object getBean(String beanName){ return factory.getBean(beanName); } } |
实际上就是封装了Spring 的XMLBeanFactory而已,并且Spring的配置文件只需要加载一次,以后就可以直接用CustomBeanFactory.getBean("someBean")来获得需要的对象了(例如someBean),而不需要知道具体的类。CustomBeanFactory类用于{耦合1}的解耦。CustomBeanFactory类在本文中只用于表现层的form bean对象获得service类的对象,因为我们没有把form bean对象配置在applicationContext.xml中。但是,为什么不把表现层的form bean类也配置起来呢,这样就用不着这CustomBeanFactory个类了,Spring会帮助我们创建需要的一切?问题的答案就在于form bean类是struts的ActionForm类!如果大家熟悉struts,就会知道ActionForm类是struts自动创建的:在一次请求中,struts判断,如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中。因此formbean类的对象就不能由spring来创建,但是service类以及数据层的DAO类可以,所以只有他们在spring中配置。所以,很自然的,我们就创建了CustomBeanFactory类,在表现层来衔接struts和spring。就这么简单,实现了另一种方式的{耦合一}的解耦。
3.3. 表现层
面分析到,struts和spring是在表现层衔接起来的,那么表现层就要做稍微的更改,即所需要的service类的对象创建上。以表现层的AccountBean类为例:原来的源代码如下
private static final AccountService accountService = AccountService.getInstance(); private static final CatalogService catalogService = CatalogService.getInstance(); |
改造后的源代码如下
private static final AccountService accountService = (AccountService)CustomBeanFactory.getBean("AccountService"); private static final CatalogService catalogService = (CatalogService)CustomBeanFactory.getBean("CatalogService"); |
其他的几个presentation类以同样方式改造。这样,表现层就完成了。关于表现层的其它部分如JSP等一概不动。也许您会说,没有看出什么特别之处的好处啊?你还是额外实现了一个工厂类。别着急,帷幕刚刚开启,spring是在表现层引入,但您发没发现:
presentation类仅仅面向service类的接口编程,具体"AccountService"是哪个实现类,presentation类不知道,是在spring的配置文件里配置。(本例中,为了最大限度的保持原来的代码不作变化,没有抽象出接口)。Spring鼓励面向接口编程,因为是如此的方便和自然,当然您也可以不这么做。
CustomBeanFactory这个工厂类为什么会如此简单,因为其直接使用了Spring的BeanFactory。Spring从其核心而言,是一个DI容器,其设计哲学是提供一种无侵入式的高扩展性的框架。为了实现这个目标,Spring 大量引入了Java 的Reflection机制,通过动态调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件BeanFactory,以此作为其依赖注入机制的实现基础。org.springframework.beans包中包括了这些核心组件的实现类,核心中的核心为BeanWrapper和BeanFactory类。
在上文中,我们把iface包下的DAO接口归为业务层,在这里不需要做修改。ibatis的sql配置文件也不需要改。要改的是DAO实现类,并在spring的配置文件中配置起来。
1、修改基类
所有的DAO实现类都继承于BaseSqlMapDao类。修改BaseSqlMapDao类如下:
public class BaseSqlMapDao extends SqlMapClientDaoSupport { protected static final int PAGE_SIZE = 4; protected SqlMapClientTemplate smcTemplate = this.getSqlMapClientTemplate(); public BaseSqlMapDao() { } } |
使BaseSqlMapDao类改为继承于Spring提供的SqlMapClientDaoSupport类,并定义了一个保护属性smcTemplate,其类型为SqlMapClientTemplate。
2、修改DAO实现类
所有的DAO实现类还是继承于BaseSqlMapDao类,实现相应的DAO接口,但其相应的DAO操作委托SqlMapClientTemplate来执行,以AccountSqlMapDao类为例,部分代码如下:
public List getUsernameList() { return smcTemplate.queryForList("getUsernameList", null); } public Account getAccount(String username, String password) { Account account = new Account(); account.setUsername(username); account.setPassword(password); return (Account) smcTemplate.queryForObject ("getAccountByUsernameAndPassword", account); } public void insertAccount(Account account) { smcTemplate.update("insertAccount", account); smcTemplate.update("insertProfile", account); smcTemplate.update("insertSignon", account); } |
就这么简单,所有函数的签名都是一样的,只需要查找替换就可以了!
除去DaoConfig.java这个DAO工厂类和相应的配置文件dao.xml,因为DAO的获取现在要用spring来管理。
4、DAO在Spr<!----><!---->ing中的配置(applicationContext.xml)
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>org.hsqldb.jdbcDriver</value> </property> <property name="url"> <value>jdbc:hsqldb:hsql://localhost/xdb</value> </property> <property name="username"> <value>sa</value> </property> <property name="password"> <value></value> </property> </bean> <!-- ibatis sqlMapClient config --> <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> <property name="configLocation"> <value> classpath:com\ibatis\jpetstore\persistence\sqlmapdao\sql\sql-map-config.xml </value> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!-- Transactions --> <bean id="TransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref bean="dataSource"/> </property> </bean> <!-- persistence layer --> <bean id="AccountDao" class="com.ibatis.jpetstore.persistence.sqlmapdao.AccountSqlMapDao"> <property name="sqlMapClient"> <ref local="sqlMapClient"/> </property> </bean> |
1. 我们首先创建一个数据源dataSource,在这里配置的是hsqldb数据库。如果是ORACLE数据库,driverClassName的值是"oracle.jdbc.driver.OracleDriver",URL的值类似于"jdbc:oracle:thin:@wugfMobile:1521:cdcf"。数据源现在由spring来管理,那么现在我们就可以去掉properties目录下database.properties这个配置文件了;还有不要忘记修改sql-map-config.xml,去掉对它的引用。
2. sqlMapClient节点。这个是针对ibatis SqlMap的SqlMapClientFactoryBean配置。实际上配置了一个sqlMapClient的创建工厂类。configLocation属性配置了ibatis映射文件的名称。dataSource属性指向了使用的数据源,这样所有使用sqlMapClient的DAO都默认使用了该数据源,除非在DAO的配置中另外显式指定。
3. TransactionManager节点。定义了事务,使用的是DataSourceTransactionManager。
4. 下面就可以定义DAO节点了,如AccountDao,它的实现类是com.ibatis.jpetstore.persistence.sqlmapdao.AccountSqlMapDao,使用的SQL配置从sqlMapClient中读取,数据库连接没有特别列出,那么就是默认使用sqlMapClient配置的数据源datasource。
这样,我们就把持久层改造完了,其他的DAO配置类似于AccountDao。怎么样?简单吧。这次有接口了:) AccountDao接口->AccountSqlMapDao实现。
3.5. 业务层
业务层的位置以及相关类,如下图所示:在这个例子中只有3个业务类,我们以OrderService类为例来改造,这个类是最复杂的,其中涉及了事务。
1、在ApplicationContext配置文件中增加bean的配置:
<bean id="OrderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> <property name="transactionManager"> <ref local="TransactionManager"></ref> </property> <property name="target"> <bean class="com.ibatis.jpetstore.service.OrderService"> <property name="itemDao"> <ref bean="ItemDao"/> </property> <property name="orderDao"> <ref bean="OrderDao"/> </property> <property name="sequenceDao"> <ref bean="SequenceDao"/> </property> </bean> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> |
定义了一个OrderService,还是很容易懂的。为了简单起见,使用了嵌套bean,其实现类是com.ibatis.jpetstore.service.OrderService,分别引用了ItemDao,OrderDao,SequenceDao。该bean的insert*实现了事务管理(AOP方式)。TransactionProxyFactoryBean自动创建一个事务advisor, 该advisor包括一个基于事务属性的pointcut,因此只有事务性的方法被拦截。
2、业务类的修改,以OrderService为例:
public class OrderService { /* Private Fields */ private ItemDao itemDao; private OrderDao orderDao; private SequenceDao sequenceDao; /* Constructors */ public OrderService() { } /** * @param itemDao 要设置的 itemDao。 */ public final void setItemDao(ItemDao itemDao) { this.itemDao = itemDao; } /** * @param orderDao 要设置的 orderDao。 */ public final void setOrderDao(OrderDao orderDao) { this.orderDao = orderDao; } /** * @param sequenceDao 要设置的 sequenceDao。 */ public final void setSequenceDao(SequenceDao sequenceDao) { this.sequenceDao = sequenceDao; } //剩下的部分 ……. } |
红色部分为修改部分。Spring采用的是Type2的设置依赖注入,所以我们只需要定义属性和相应的设值函数就可以了,ItemDao,OrderDao,SequenceDao的值由spring在运行期间注入。构造函数就可以为空了,另外也不需要自己编写代码处理事务了(事务在配置中声明),daoManager.startTransaction();等与事务相关的语句也可以去掉了。和原来的代码比较一下,是不是处理精简了很多!可以更关注业务的实现。
4. 结束语
ibatis是一个功能强大实用的SQL Map工具,可以直接控制SQL,为系统设计提供了更大的自由空间。其提供的最新示例程序JpetStore 4.0,设计优雅,应用了迄今为止很多最佳实践和设计模式,非常适于学习以及在此基础上创建轻量级的J2EE WEB应用程序。JpetStore 4.0是基于struts的,本文在此基础上,最大程度保持了原有设计的精华以及最小的代码改动量,在业务层和持久化层引入了Spring。在您阅读了本文以及改造后的源代码后,会深切的感受到Spring带来的种种好处:自然的面向接口的编程,业务对象的依赖注入,一致的数据存取框架和声明式的事务处理,统一的配置文件…更重要的是Spring既是全面的又是模块化的,Spring有分层的体系结构,这意味着您能选择仅仅使用它任何一个独立的部分,就像本文,而它的架构又是内部一致。
相关推荐
基于Struts+Spring+Ibatis的J2EE开发模式就是为了应对这些挑战而诞生的一种解决方案。这个模式结合了Struts的MVC框架、Spring的依赖注入和事务管理以及Ibatis的数据持久层,旨在降低开发复杂性,提高代码的可读性...
这个“基于struts+spring+ibatis的 J2EE 开发.rar”压缩包文件很可能是提供了一个详尽的教程或项目实例,帮助开发者理解和掌握这三个框架的集成应用。 **Struts框架**是MVC(Model-View-Controller)设计模式的实现...
### 基于Struts+Spring+Ibatis的轻量级J2EE开发 #### 1. 前言 随着互联网技术的迅速发展,企业级应用开发面临着日益复杂的挑战。传统的J2EE架构虽然成熟稳定,但在面对敏捷开发的需求时显得力不从心。为了提高开发...
这个压缩包文件"基于struts+spring+ibatis的轻量级J2EE开发.rar"很可能包含了一套完整的示例项目或者教程,用于演示如何整合这三大框架进行开发。 Struts是Apache软件基金会的一个开源项目,主要用于MVC(Model-...
struts+spring+ibatis
Struts 1.2.9 + Spring 2.5.6 + iBATIS 2.3.4 + MySQL 3.1 + Tomcat 5.5.26 > 开发环境: * MyEclipse、JDK1.5、J2EE1.4 > 使用技术: * Struts1、Spring、iBATIS > 运行环境: * Window + Tomcat 5.5.26 + ...
公司让学的 正在学习
Struts、Spring和iBatis是Java开发领域中非常经典的三大框架,它们组合在一起可以构建出高效、可维护的企业级Web应用。这个"Struts+Spring+iBatis项目"很可能是为了演示或教学如何整合这三大框架来实现数据访问、...
Struts+Spring+Ibatis框架是Java Web开发中常见的轻量级组合,它们各自负责不同的职责,协同构建高效、可维护的J2EE应用程序。Struts作为MVC框架,负责控制流程;Spring提供依赖注入和面向切面编程,增强系统的灵活...
Struts、Spring 和 iBatis(SSI)是一个经典的Java企业级开发组合,它们共同构建了一个强大的后端架构。Struts提供了MVC(Model-View-Controller)设计模式的实现,Spring作为容器管理依赖,而iBatis则负责数据库...
Struts2.0+Spring2.5.1+ibatis2.3的整合是一个常见的Java Web应用程序开发模式,主要用于构建高效、可维护性高的企业级系统。这种整合将Struts2作为表现层框架,Spring作为控制层和业务层框架,而iBatis则作为数据...
【Java Web核心框架:Struts 1+Struts 2+Spring+Hibernate+iBATIS】是Java领域中常见的Web应用程序开发框架的组合,用于构建高效、可维护的J2EE应用。这些框架各自承担着不同的职责,共同协作以实现业务逻辑、数据...
### Struts2、Spring与iBatis框架整合开发详解 #### 一、概述 在Java Web开发领域,Struts2、Spring以及iBatis(现称为MyBatis)是三个非常重要的开源框架,它们各自拥有独特的功能,并且可以很好地协同工作以构建...
这个压缩包文件包含了一个基于J2EE架构的高级项目源码,主要采用了Struts2.0、Hibernate、Spring和ExtJS这四大核心技术。下面将详细解释这些技术及其在项目中的应用。 **Struts2.0** 是一个MVC(Model-View-...
Struts2、Spring 2.5 和 iBATIS 是经典的Java Web开发框架组合,它们各自在应用程序架构的不同层面上发挥着关键作用。Struts2 是一个MVC(模型-视图-控制器)框架,用于处理用户请求并组织业务逻辑;Spring 2.5 提供...
在Java企业级开发中,WebWork、Spring和iBatis是三个非常重要的框架。WebWork是一个轻量级的MVC(Model-View-Controller)框架,Spring是一个全面的后端应用框架,而iBatis则是一个优秀的持久层框架,它们的结合使用...