# 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
8.3? 集成iBATIS
iBATIS是一個半自動化的ORM框架,需要通過配置方式指定映射SQL語句,而不是由框架本身生成(如Hibernate自動生成對應SQL來持久化對象),即Hibernate屬于全自動ORM框架。
Spring提供對iBATIS 2.X的集成,提供一致的異常體系、一致的DAO訪問支持、Spring管理事務支持。
**?????? Spring?2.5.5+版本支持iBATIS 2.3+版本,不支持低版本。**
### 8.3.1? 如何集成
Spring通過使用如下Bean進行集成iBATIS:
* SqlMapClientFactoryBean:用于集成iBATIS。
configLocation和configLocations:用于指定SQL Map XML配置文件,用于指定如數據源等配置信息;
mappingLocations:用于指定SQL Map映射文件,即半自動概念中的SQL語句定義;
sqlMapClientProperties:定義iBATIS 配置文件配置信息;
dataSource:定義數據源。
如果在Spring配置文件中指定了DataSource,就不要在iBATIS配置文件指定了,否則Spring配置文件指定的DataSource將覆蓋iBATIS配置文件中定義的DataSource。
接下來示例一下如何集成iBATIS:
**1、準備需要的jar包,從spring-framework-3.0.5.RELEASE-dependencies.zip中拷貝如下jar包:**
**? **com.springsource.com.ibatis-2.3.4.726.jar
**2、?對象模型定義,此處使用第七章中的UserModel;**
**3、?**iBATIS**映射定義(chapter8/sqlmaps/UserSQL.xml):**
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="UserSQL">
<statement id="createTable">
<!--id自增主鍵從0開始 -->
<![CDATA[
create memory table test(
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name varchar(100))
]]>
</statement>
<statement id="dropTable">
<![CDATA[ drop table test ]]>
</statement>
<insert id="insert" parameterClass="cn.javass.spring.chapter7.UserModel">
<![CDATA[
insert into test(name) values (#myName#)
]]>
<selectKey resultClass="int" keyProperty="id" type="post">
<!-- 獲取hsqldb插入的主鍵 -->
call identity();
<!-- mysql使用select last_insert_id();獲取插入的主鍵 -->
</selectKey>
</insert>
</sqlMap>
```
**4、?iBATIS配置文件(chapter8/sql-map-config.xml)定義:**
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings enhancementEnabled="true" useStatementNamespaces="true"
maxTransactions="20" maxRequests="32" maxSessions="10"/>
<sqlMap resource="chapter8/sqlmaps/UserSQL.xml"/>
</sqlMapConfig>
```
**5、?數據源定義,此處使用第7章的配置文件,即“chapter7/applicationContext-resources.xml”文件。**
**6、?SqlMapClient配置(chapter8/applicationContext-ibatis.xml)定義:**
```
<bean id="sqlMapClient"
class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<!-- 1、指定數據源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 2、指定配置文件 -->
<property name="configLocation" value="chapter8/sql-map-config.xml"/>
</bean>
```
**7、?獲取SqlMapClient:**
```
package cn.javass.spring.chapter8;
//省略import
public class IbatisTest {
private static SqlMapClient sqlMapClient;
@BeforeClass
public static void setUpClass() {
String[] configLocations = new String[] {
"classpath:chapter7/applicationContext-resources.xml",
"classpath:chapter8/applicationContext-ibatis.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
sqlMapClient = ctx.getBean(SqlMapClient.class);
}
}
```
此處我們使用了chapter7/applicationContext-resources.xml定義的“dataSource”數據源,通過ctx.getBean(SqlMapClient.class)獲取SqlMapClient。
**8、?通過SqlMapClient創建和刪除表:**
```
@Before
public void setUp() throws SQLException {
sqlMapClient.update("UserSQL.createTable");
}
@After
public void tearDown() throws SQLException {
sqlMapClient.update("UserSQL.dropTable");
}
```
**9、?使用SqlMapClient進行對象持久化:**
```
@Test
public void testFirst() throws SQLException {
UserModel model = new UserModel();
model.setMyName("test");
SqlMapSession session = null;
try {
session = sqlMapClient.openSession();
beginTransaction(session);
session.insert("UserSQL.insert", model);
commitTransaction(session);
} catch (SQLException e) {
rollbackTransacrion(session);
throw e;
} finally {
closeSession(session);
}
}
private void closeSession(SqlMapSession session) {
session.close();
}
private void rollbackTransacrion(SqlMapSession session) throws SQLException {
if(session != null) {
session.endTransaction();
}
}
private void commitTransaction(SqlMapSession session) throws SQLException {
session.commitTransaction();
}
private void beginTransaction(SqlMapSession session) throws SQLException {
session.startTransaction();
}
```
同樣令人心煩的事務管理和冗長代碼,Spring通用提供了SqlMapClientTemplate模板類來解決這些問題。
### 8.3.2? 使用 SqlMapClientTemplate
SqlMapClientTemplate模板類同樣用于簡化事務管理及常見操作,類似于JdbcTemplate模板類,對于復雜操作通過提供SqlMapClientCallback回調接口來允許更復雜的操作。
接下來示例一下SqlMapClientTemplate的使用:
```
@Test
public void testSqlMapClientTemplate() {
SqlMapClientTemplate sqlMapClientTemplate =
new SqlMapClientTemplate(sqlMapClient);
final UserModel model = new UserModel();
model.setMyName("myName");
sqlMapClientTemplate.insert("UserSQL.insert", model);
//通過回調允許更復雜操作
sqlMapClientTemplate.execute(new SqlMapClientCallback<Void>() {
@Override
public Void doInSqlMapClient(SqlMapExecutor session) throws SQLException {
session.insert("UserSQL.insert", model);
return null;
}});
}
```
通過new SqlMapClientTemplate(sqlMapClient)創建HibernateTemplate模板類對象,通過調用模板類的save方法持久化對象,并且自動享受到Spring管理事務的好處。
而且SqlMapClientTemplate提供使用SqlMapClientCallback回調接口的方法execute用來支持復雜操作,當然也自動享受到Spring管理事務的好處。
### 8.3.3集成iBATIS及最佳實踐
類似于JdbcDaoSupport類,Spring對iBATIS也提供了SqlMapClientDaoSupport類來支持一致的數據庫訪問。SqlMapClientDaoSupport也是DaoSupport實現:
接下來示例一下Spring集成iBATIS的最佳實踐:
**1、?定義Dao接口,此處使用cn.javass.spring.chapter7.dao.IUserDao:**
**2、?定義Dao接口實現,此處是iBATIS實現:**
```
package cn.javass.spring.chapter8.dao.ibatis;
//省略import
public class UserIbatisDaoImpl extends SqlMapClientDaoSupport
implements IUserDao {
@Override
public void save(UserModel model) {
getSqlMapClientTemplate().insert("UserSQL.insert", model);
}
@Override
public int countAll() {
return (Integer) getSqlMapClientTemplate().queryForObject("UserSQL.countAll");
}
}
```
**3、修改iBATS映射文件(chapter8/sqlmaps/UserSQL.xml),添加countAll查詢:**
```
<select id="countAll" resultClass="java.lang.Integer">
<![CDATA[ select count(*) from test ]]>
</select>
```
此處注意首先iBATIS實現放在dao.ibaitis包里,其次實現類命名如UserIbatisDaoImpl,即×××IbatisDaoImpl,當然如果自己有更好的命名規范可以遵循自己的,此處只是提個建議。
**4、進行資源配置,使用resources/chapter7/applicationContext-resources.xml:**
**5、dao定義配置,在chapter8/applicationContext-ibatis.xml中添加如下配置:**
```
<bean id="abstractDao" abstract="true">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
<bean id="userDao"
class="cn.javass.spring.chapter8.dao.ibatis.UserIbatisDaoImpl"
parent="abstractDao"/>
```
首先定義抽象的abstractDao,其有一個sqlMapClient屬性,從而可以讓繼承的子類自動繼承sqlMapClient屬性注入;然后定義userDao,且繼承abstractDao,從而繼承sqlMapClient注入;我們在此給配置文件命名為applicationContext-ibatis.xml表示iBAITIS實現。
**5、?最后測試一下吧(cn.javass.spring.chapter8\. IbatisTest):**
```
@Test
public void testBestPractice() {
String[] configLocations = new String[] {
"classpath:chapter7/applicationContext-resources.xml",
"classpath:chapter8/applicationContext-ibatis.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
IUserDao userDao = ctx.getBean(IUserDao.class);
UserModel model = new UserModel();
model.setMyName("test");
userDao.save(model);
Assert.assertEquals(1, userDao.countAll());
}
```
和Spring JDBC框架的最佳實踐完全一樣,除了使用applicationContext-ibatis.xml代替了applicationContext-jdbc.xml,其他完全一樣。也就是說,DAO層的實現替換可以透明化。
### 8.3.4Spring+iBATIS的CURD
Spring集成iBATIS進行CURD(增刪改查),也非常簡單,首先配置映射文件,然后調用SqlMapClientTemplate相應的函數進行操作即可,此處就不介紹了。
### 8.3.5集成MyBatis及最佳實踐
(本筆記寫于2010年底)
2010年4月份 iBATIS團隊發布iBATIS 3.0的GA版本的候選版本,在iBATIS 3中引入了泛型、注解支持等,因此需要Java5+才能使用,但在2010年6月16日,iBATIS團隊決定從apache遷出并遷移到Google Code,并更名為MyBatis。目前新網站上文檔并不完善。
目前iBATIS 2.x和MyBatis 3不是100%兼容的,如配置文件的DTD變更,SqlMapClient直接由SqlSessionFactory代替了,包名也有com.ibatis變成org.ibatis等等。
ibatis 3.x和MyBatis是兼容的,只需要將DTD變更一下就可以了。
感興趣的朋友可以到http://www.mybatis.org/官網去下載最新的文檔學習,作者只使用過iBATIS2.3.4及以前版本,沒在新項目使用過最新的iBATIS 3.x和Mybatis,因此如果讀者需要在項目中使用最新的MyBatis,請先做好調研再使用。
接下來示例一下Spring集成MyBatis的最佳實踐:
**1、準備需要的jar包,到MyBatis官網下載mybatis?3.0.4版本和mybatis-spring 1.0.0版本,并拷貝如下jar包到類路徑:**
+ **mybatis-3.0.4\mybatis-3.0.4.jar????????????? //核心MyBatis包**
+ **mybatis-spring-1.0.0\mybatis-spring-1.0.0.jar? //集成Spring包**
**2、對象模型定義,此處使用第七章中的UserModel;**
**3、MyBatis映射定義(chapter8/sqlmaps/UserSQL-mybatis.xml):**
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="UserSQL">
<sql id="createTable">
<!--id自增主鍵從0開始 -->
<![CDATA[
create memory table test(
id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name varchar(100))
]]>
</sql>
<sql id="dropTable">
<![CDATA[ drop table test ]]>
</sql>
<insert id="insert" parameterType="cn.javass.spring.chapter7.UserModel">
<![CDATA[ insert into test(name) values (#{myName}) ]]>
<selectKey resultType="int" keyProperty="id" order="AFTER">
<!-- 獲取hsqldb插入的主鍵 -->
call identity();
<!-- mysql使用select last_insert_id();獲取插入的主鍵 -->
</selectKey>
</insert>
<select id="countAll" resultType="java.lang.Integer">
<![CDATA[ select count(*) from test ]]>
</select>
</mapper>
```
從映射定義中可以看出MyBatis與iBATIS2.3.4有如下不同:
* http://ibatis.apache.org/dtd/sql-map-2.dtd 廢棄,而使用[http://mybatis.org/dtd/mybatis-3-mapper.dtd](http://mybatis.org/dtd/mybatis-3-mapper.dtd)。
* <sqlMap>廢棄,而使用<mapper>標簽;
* <statement>廢棄了,而使用<sql>標簽;
* parameterClass屬性廢棄,而使用parameterType屬性;
* resultClass屬性廢棄,而使用resultType屬性;
* #myName#方式指定命名參數廢棄,而使用#{myName}方式。
**3、?MyBatis配置文件(chapter8/sql-map-config-mybatis.xml)定義:**
```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="cacheEnabled" value="false"/>
</settings>
<mappers>
<mapper resource="chapter8/sqlmaps/UserSQL-mybatis.xml"/>
</mappers>
</configuration>
```
從配置定義中可以看出MyBatis與iBATIS2.3.4有如下不同:
* [http://ibatis.apache.org/dtd/sql-map-config-2.dtd](http://ibatis.apache.org/dtd/sql-map-config-2.dtd)廢棄,而使用[http://mybatis.org/dtd/mybatis-3-config.dtd](http://mybatis.org/dtd/mybatis-3-config.dtd);
* < sqlMapConfig >廢棄,而使用<configuration>;
* settings屬性配置方式廢棄,而改用子標簽< setting name=".." value=".."/>方式指定屬性,且一些屬性被廢棄,如maxTransactions;
* < sqlMap>廢棄,而采用<mappers>標簽及其子標簽<mapper>定義。
**4、?定義Dao接口,此處使用cn.javass.spring.chapter7.dao. IUserDao:**
**5、?定義Dao接口實**現,**此處是MyBatis實現:**
```
package cn.javass.spring.chapter8.dao.mybatis;
//省略import
public class UserMybatisDaoImpl extends SqlSessionDaoSupport
implements IUserDao {
@Override
public void save(UserModel model) {
getSqlSession().insert("UserSQL.insert", model);
}
@Override
public int countAll() {
return (Integer) getSqlSession().selectOne("UserSQL.countAll");
}
}
```
和Ibatis集成方式不同的有如下地方:
* 使用SqlSessionDaoSupport來支持一致性的DAO訪問,該類位于org.mybatis.spring.support包中,非Spring提供;
* 使用getSqlSession方法獲取SqlSessionTemplate,在較早版本中是getSqlSessionTemplate方法名,不知為什么改成getSqlSession方法名,因此這個地方在使用時需要注意。
* SqlSessionTemplate是SqlSession接口的實現,并且自動享受Spring管理事務好處,因此從此處可以推斷出為什么把獲取模板類的方法名改為getSqlSession而不是getSqlSessionTemplate。
**6、進行資源配置,使用resources/chapter7/applicationContext-resources.xml:**
**7、dao定義配置,在chapter8/applicationContext-mybatis.xml中添加如下配置:**
```
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/><!-- 1、指定數據源 -->
<property name="configLocation" value="chapter8/sql-map-config-mybatis.xml"/>
</bean>
<bean id="abstractDao" abstract="true">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
<bean id="userDao"
class="cn.javass.spring.chapter8.dao.mybatis.UserMybatisDaoImpl"
parent="abstractDao"/>
```
和Ibatis集成方式不同的有如下地方:
* SqlMapClient類廢棄,而使用SqlSessionFactory代替;
* 使用SqlSessionFactoryBean進行集成MyBatis。
首先定義抽象的abstractDao,其有一個sqlSessionFactory屬性,從而可以讓繼承的子類自動繼承sqlSessionFactory屬性注入;然后定義userDao,且繼承abstractDao,從而繼承sqlSessionFactory注入;我們在此給配置文件命名為applicationContext-mybatis.xml表示MyBatis實現。
**8、最后測試一下吧(cn.javass.spring.chapter8\. IbatisTest):**
```
@Test
public void testMybatisBestPractice() {
String[] configLocations = new String[] {
"classpath:chapter7/applicationContext-resources.xml",
"classpath:chapter8/applicationContext-mybatis.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocations);
IUserDao userDao = ctx.getBean(IUserDao.class);
UserModel model = new UserModel();
model.setMyName("test");
userDao.save(model);
Assert.assertEquals(1, userDao.countAll());
}
```
和Spring 集成Ibatis的最佳實踐完全一樣,除了使用applicationContext-mybatis.xml代替了applicationContext-ibatis.xml,其他完全一樣,且MyBatis 3.x與Spring整合只能運行在Spring3.x。
在寫本書時,MyBatis與Spring集成所定義的API不穩定,且期待Spring能在發布新版本時將加入對MyBatis的支持。
原創內容,轉載請注明出處【[http://sishuok.com/forum/blogPost/list/0/2498.html](http://sishuok.com/forum/blogPost/list/0/2498.html#7216)】
- 跟我學 Spring3
- 【第二章】 IoC 之 2.1 IoC基礎 ——跟我學Spring3
- 【第二章】 IoC 之 2.2 IoC 容器基本原理 ——跟我學Spring3
- 【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3
- 【第三章】 DI 之 3.1 DI的配置使用 ——跟我學spring3
- 【第三章】 DI 之 3.2 循環依賴 ——跟我學spring3
- 【第三章】 DI 之 3.3 更多DI的知識 ——跟我學spring3
- 【第三章】 DI 之 3.4 Bean的作用域 ——跟我學spring3
- 【第四章】 資源 之 4.1 基礎知識 ——跟我學spring3
- 【第四章】 資源 之 4.2 內置Resource實現 ——跟我學spring3
- 【第四章】 資源 之 4.3 訪問Resource ——跟我學spring3
- 【第四章】 資源 之 4.4 Resource通配符路徑 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.1 概述 5.2 SpEL基礎 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.3 SpEL語法 ——跟我學spring3
- 【第五章】Spring表達式語言 之 5.4在Bean定義中使用EL—跟我學spring3
- 【第六章】 AOP 之 6.1 AOP基礎 ——跟我學spring3
- 【第六章】 AOP 之 6.2 AOP的HelloWorld ——跟我學spring3
- 【第六章】 AOP 之 6.3 基于Schema的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.4 基于@AspectJ的AOP ——跟我學spring3
- 【第六章】 AOP 之 6.5 AspectJ切入點語法詳解 ——跟我學spring3
- 【第六章】 AOP 之 6.6 通知參數 ——跟我學spring3
- 【第六章】 AOP 之 6.7 通知順序 ——跟我學spring3
- 【第六章】 AOP 之 6.8 切面實例化模型 ——跟我學spring3
- 【第六章】 AOP 之 6.9 代理機制 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.1 概述 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.2 JDBC模板類 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.3 關系數據庫操作對象化 ——跟我學spring3
- 【第七章】 對JDBC的支持 之 7.4 Spring提供的其它幫助 ——跟我學spring3【私塾在線原創】
- 【第七章】 對JDBC的支持 之 7.5 集成Spring JDBC及最佳實踐 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.1 概述 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.2 集成Hibernate3 ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.3 集成iBATIS ——跟我學spring3
- 【第八章】 對ORM的支持 之 8.4 集成JPA ——跟我學spring3
- 【第九章】 Spring的事務 之 9.1 數據庫事務概述 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.2 事務管理器 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.3 編程式事務 ——跟我學spring3
- 【第九章】 Spring的事務 之 9.4 聲明式事務 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.1 概述 ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.2 集成Struts1.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.3 集成Struts2.x ——跟我學spring3
- 【第十章】集成其它Web框架 之 10.4 集成JSF ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.1 概述 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.2 實現通用層 ——跟我學spring3
- 【第十一章】 SSH集成開發積分商城 之 11.3 實現積分商城層 ——跟我學spring3
- 【第十二章】零配置 之 12.1 概述 ——跟我學spring3
- 【第十二章】零配置 之 12.2 注解實現Bean依賴注入 ——跟我學spring3
- 【第十二章】零配置 之 12.3 注解實現Bean定義 ——跟我學spring3
- 【第十二章】零配置 之 12.4 基于Java類定義Bean配置元數據 ——跟我學spring3
- 【第十二章】零配置 之 12.5 綜合示例-積分商城 ——跟我學spring3
- 【第十三章】 測試 之 13.1 概述 13.2 單元測試 ——跟我學spring3
- 【第十三章】 測試 之 13.3 集成測試 ——跟我學spring3
- 跟我學 Spring MVC
- SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常見問題總結
- Spring Web MVC中的頁面緩存支持 ——跟我學SpringMVC系列
- Spring3 Web MVC下的數據類型轉換(第一篇)——《跟我學Spring3 Web MVC》搶先看
- Spring3 Web MVC下的數據格式化(第二篇)——《跟我學Spring3 Web MVC》搶先看
- 第一章 Web MVC簡介 —— 跟開濤學SpringMVC
- 第二章 Spring MVC入門 —— 跟開濤學SpringMVC
- 第三章 DispatcherServlet詳解 ——跟開濤學SpringMVC
- 第四章 Controller接口控制器詳解(1)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(2)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(3)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解 (4)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(5)——跟著開濤學SpringMVC
- 跟著開濤學SpringMVC 第一章源代碼下載
- 第二章 Spring MVC入門 源代碼下載
- 第四章 Controller接口控制器詳解 源代碼下載
- 第四章 Controller接口控制器詳解(6)——跟著開濤學SpringMVC
- 第四章 Controller接口控制器詳解(7 完)——跟著開濤學SpringMVC
- 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 源代碼下載 第五章 處理器攔截器詳解——跟著開濤學SpringMVC
- 注解式控制器運行流程及處理器定義 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- 源代碼下載 第六章 注解式控制器詳解
- SpringMVC3強大的請求映射規則詳解 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- Spring MVC 3.1新特性 生產者、消費者請求限定 —— 第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(1)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC強大的數據綁定(2)——第六章 注解式控制器詳解——跟著開濤學SpringMVC
- SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據格式化——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
- SpringMVC數據驗證——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC