# SpringMVC數據類型轉換——第七章 注解式控制器的數據驗證、類型轉換及格式化——跟著開濤學SpringMVC
# 7.1、簡介
在編寫可視化界面項目時,我們通常需要對數據進行類型轉換、驗證及格式化。
**一、在Spring3之前,我們使用如下架構進行類型轉換、驗證及格式化:**

**流程:**
①:類型轉換:首先調用PropertyEditor的setAsText(String),內部根據需要調用setValue(Object)方法進行設置轉換后的值;
②:數據驗證:需要顯示調用Spring的Validator接口實現進行數據驗證;
③:格式化顯示:需要調用PropertyEditor的getText進行格式化顯示。
**使用如上架構的缺點是:**
(1、PropertyEditor被設計為只能String<——>Object之間轉換,不能任意對象類型<——>任意類型,如我們常見的Long時間戳到Date類型的轉換是辦不到的;
(2、PropertyEditor是線程不安全的,也就是有狀態的,因此每次使用時都需要創建一個,不可重用;
(3、PropertyEditor不是強類型的,setValue(Object)可以接受任意類型,因此需要我們自己判斷類型是否兼容;
(4、需要自己編程實現驗證,Spring3支持更棒的注解驗證支持;
(5、在使用SpEL表達式語言或DataBinder時,只能進行String<--->Object之間的類型轉換;
`(6`、`不支持細粒度的類型轉換/格式化,如UserModel的registerDate需要轉換/格式化類似“``2012-05-01``”的數據,而OrderModel的orderDate需要轉換/格式化類似“2012-05-01 15:11:13”的數據,因為大家都為java.util.Date類型,因此不太容易進行細粒度轉換/格式化。`
`**在Spring Web MVC環境中,數據類型轉換、驗證及格式化通常是這樣使用的:**`

**流程:**
`①、類型轉換:首先表單數據(全部是字符串)通過WebDataBinder進行綁定到命令對象,內部通過PropertyEditor實現;`
②:數據驗證:在控制器中的功能處理方法中,需要顯示的調用Spring的Validator實現并將錯誤信息添加到BindingResult對象中;
③:格式化顯示:在表單頁面可以通過如下方式展示通過`PropertyEditor`格式化的數據和錯誤信息:
```
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>?
```
首先需要通過如上taglib指令引入spring的兩個標簽庫。
```
//1、格式化單個命令/表單對象的值(好像比較麻煩,真心沒有好辦法)
<spring:bind path="dataBinderTest.phoneNumber">${status.value}</spring:bind>?
```
```
//2、通過form標簽,內部的表單標簽會自動調用命令/表單對象屬性對應的PropertyEditor進行格式化顯示
<form:form commandName="dataBinderTest">
<form:input path="phoneNumber"/><!-- 如果出錯會顯示錯誤之前的數據而不是空 -->
</form:form>?
```
```
//3、顯示驗證失敗后的錯誤信息
<form:errors></form:errors>?
```
如上PropertyEditor和驗證API使用起來比較麻煩,而且有許多缺點,因此Spring3提供了更強大的類型轉換(Type Conversion)支持,它可以在任意對象之間進行類型轉換,不僅僅是String<——>Object;也提供了強大的數據驗證支持;同時提供了強大的數據格式化支持。
**二、從Spring3開始,我們可以使用如下架構進行類型轉換、驗證及格式化:**

**流程:**
①:類型轉換:內部的ConversionService會根據S源類型/T目標類型自動選擇相應的Converter SPI進行類型轉換,而且是強類型的,能在任意類型數據之間進行轉換;
②:數據驗證:支持JSR-303驗證框架,如將@Valid放在需要驗證的目標類型上即可;
③:格式化顯示:其實就是任意目標類型---->String的轉換,完全可以使用Converter SPI完成。
Spring為了更好的詮釋格式化/解析功能提供了Formatter SPI,支持根據Locale信息進行格式化/解析,而且該套SPI可以支持字段/參數級別的細粒度格式化/解析,**流程如下:**
①:類型解析(轉換):String---->T類型目標對象的解析,和PropertyEditor類似;
③:格式化顯示:任意目標類型---->String的轉換,和PropertyEditor類似。
Formatter SPI最大特點是能進行字段/參數級別的細粒度解析/格式化控制,即使是Converter SPI也是粗粒度的(到某個具體類型,而不是其中的某個字段單獨控制),目前Formatter SPI還不是很完善,如果您有好的想法可以到Spring官網提建議。
Formatter SPI內部實現實際委托給Converter SPI進行轉換,即約束為解析/格式化String<---->任意目標類型。
**在Spring Web MVC環境中,數據類型轉換、驗證及格式化通常是這樣使用的:**

`①、類型轉換:首先表單數據(全部是字符串)通過WebDataBinder進行綁定到命令對象,內部通過Converter SPI實現;`
②:數據驗證:使用JSR-303驗證框架進行驗證;
③:格式化顯示:在表單頁面可以通過如下方式展示通過`內部通過Converter SPI`格式化的數據和錯誤信息:
```
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>?
```
首先需要通過如上taglib指令引入spring的兩個標簽庫。
```
//1、格式化單個命令/表單對象的值(好像比較麻煩,真心沒有好辦法)
<spring:bind path="dataBinderTest.phoneNumber">${status.value}</spring:bind>?
```
```
//2、<spring:eval>標簽,自動調用ConversionService并選擇相應的Converter SPI進行格式化展示
<spring:eval expression="dataBinderTest.phoneNumber"></spring:eval>?
```
如上代碼能工作的前提是在RequestMappingHandlerMapping配置了ConversionServiceExposingInterceptor,它的作用是暴露conversionService到請求中以便如<spring:eval>標簽使用。
```
//3、通過form標簽,內部的表單標簽會自動調用命令/表單對象屬性對應的PropertyEditor進行格式化顯示
<form:form commandName="dataBinderTest">
<form:input path="phoneNumber"/><!-- 如果出錯會顯示錯誤之前的數據而不是空 -->
</form:form>?
```
```
//4、顯示驗證失敗后的錯誤信息
<form:errors></form:errors>?
```
接下來我們就詳細學習一下這些知識吧。
# 7.2、數據類型轉換
## 7.2.1、Spring3之前的PropertyEditor
PropertyEditor介紹請參考【4.16.1、數據類型轉換】。
**一、測試之前我們需要準備好測試環境:**
(1、模型對象,和【4.16.1、數據類型轉換】使用的一樣,需要將DataBinderTestModel模型類及相關類拷貝過來放入cn.javass.chapter7.model包中。
(2、控制器定義:?????????
```
package cn.javass.chapter7.web.controller;
//省略import
@Controller
public class DataBinderTestController {
@RequestMapping(value = "/dataBind")
public String test(DataBinderTestModel command) {
//輸出command對象看看是否綁定正確
System.out.println(command);
model.addAttribute("dataBinderTest", command);
return "bind/success";
}
}
```
(3、Spring配置文件定義,請參考chapter7-servlet.xml,并注冊DataBinderTestController:
```
<bean class="cn.javass.chapter7.web.controller.DataBinderTestController"/>?
```
(4、測試的URL:
http://localhost:9080/springmvc-chapter7/dataBind?username=zhang&bool=yes&schooInfo.specialty=computer&hobbyList[0]=program&hobbyList[1]=music&map[key1]=value1&map[key2]=value2&phoneNumber=010-12345678&date=2012-3-18 16:48:48&state=blocked
**二、注解式控制器注冊PropertyEditor:**
**1、使用WebDataBinder進行控制器級別注冊PropertyEditor(控制器獨享)**
```
@InitBinder
//此處的參數也可以是ServletRequestDataBinder類型
public void initBinder(WebDataBinder binder) throws Exception {
//注冊自定義的屬性編輯器
//1、日期
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
CustomDateEditor dateEditor = new CustomDateEditor(df, true);
//表示如果命令對象有Date類型的屬性,將使用該屬性編輯器進行類型轉換
binder.registerCustomEditor(Date.class, dateEditor);
//自定義的電話號碼編輯器(和【4.16.1、數據類型轉換】一樣)
binder.registerCustomEditor(PhoneNumberModel.class, new PhoneNumberEditor());
}?
```
和【4.16.1、數據類型轉換】一節類似,只是此處需要通過@InitBinder來注冊自定義的PropertyEditor。
**2、使用**`**WebBindingInitializer批量注冊**`**PropertyEditor**
和【4.16.1、數據類型轉換】不太一樣,因為我們的注解式控制器是POJO,沒有實現任何東西,因此無法注入WebBindingInitializer,此時我們需要把WebBindingInitializer注入到我們的RequestMappingHandlerAdapter或AnnotationMethodHandlerAdapter,這樣對于所有的注解式控制器都是共享的。
```
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="cn.javass.chapter7.web.controller.support.initializer.MyWebBindingInitializer"/>
</property>
</bean>?
```
此時我們注釋掉控制器級別通過@InitBinder注冊PropertyEditor的方法。
**3、全局級別注冊PropertyEditor(全局共享)**
和【4.16.1、數據類型轉換】一節一樣,此處不再重復。請參考【4.16.1、數據類型轉換】的【全局級別注冊PropertyEditor(全局共享)】。
`接下來我們看一下Spring3提供的更強大的類型轉換支持。`
## 7.2.2、Spring3開始的類型轉換系統
Spring3引入了更加通用的類型轉換系統,其定義了SPI接口(Converter等)和相應的運行時執行類型轉換的API(ConversionService等),在Spring中它和PropertyEditor功能類似,可以替代PropertyEditor來轉換外部Bean屬性的值到Bean屬性需要的類型。
該類型轉換系統是Spring通用的,其定義在org.springframework.core.convert包中,不僅僅在Spring Web MVC場景下。目標是完全替換PropertyEditor,提供無狀態、強類型且可以在任意類型之間轉換的類型轉換系統,可以用于任何需要的地方,如SpEL、數據綁定。
Converter SPI完成通用的類型轉換邏輯,如java.util.Date<---->java.lang.Long或java.lang.String---->PhoneNumberModel等。
### 7.2.2.1、架構
**1、類型轉換器:**提供類型轉換的實現支持。

一個有如下三種接口:
**(1、Converter:**類型轉換器,用于轉換S類型到T類型,此接口的實現必須是線程安全的且可以被共享。
```
package org.springframework.core.convert.converter;
public interface Converter<S, T> { //① S是源類型 T是目標類型
T convert(S source); //② 轉換S類型的source到T目標類型的轉換方法
}?
```
示例:請參考cn.javass.chapter7.converter.support.StringToPhoneNumberConverter轉換器,用于將String--->PhoneNumberModel。
此處我們可以看到Converter接口實現只能轉換一種類型到另一種類型,不能進行多類型轉換,如將一個數組轉換成集合,如(String[] ----> List<String>、String[]----->List<PhoneNumberModel>等)。
**(2、GenericConverter和ConditionalGenericConverter:**GenericConverter接口實現能在多種類型之間進行轉換,ConditionalGenericConverter是有條件的在多種類型之間進行轉換。
```
package org.springframework.core.convert.converter;
public interface GenericConverter {
Set<ConvertiblePair> getConvertibleTypes();
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
```
getConvertibleTypes:指定了可以轉換的目標類型對;
convert:在sourceType和targetType類型之間進行轉換。
```
package org.springframework.core.convert.converter;
public interface ConditionalGenericConverter extends GenericConverter {
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}?
```
matches:用于判斷sourceType和targetType類型之間能否進行類型轉換。
示例:如org.springframework.core.convert.support.ArrayToCollectionConverter和CollectionToArrayConverter用于在數組和集合間進行轉換的ConditionalGenericConverter實現,如在String[]<---->List<String>、String[]<---->List<PhoneNumberModel>等之間進行類型轉換。
對于我們大部分用戶來說一般不需要自定義GenericConverter, 如果需要可以參考內置的GenericConverter來實現自己的。
**(3、ConverterFactory:**工廠模式的實現,用于選擇將一種S源類型轉換為R類型的子類型T的轉換器的工廠接口。
```
package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}?
```
S:源類型;R目標類型的父類型;T:目標類型,且是R類型的子類型;
getConverter:得到目標類型的對應的轉換器。
示例:如org.springframework.core.convert.support.NumberToNumberConverterFactory用于在Number類型子類型之間進行轉換,如Integer--->Double, Byte---->Integer, Float--->Double等。
對于我們大部分用戶來說一般不需要自定義ConverterFactory,如果需要可以參考內置的ConverterFactory來實現自己的。
**2、類型轉換器注冊器、類型轉換服務:**提供類型轉換器注冊支持,運行時類型轉換API支持。

一共有如下兩種接口:
**(1、ConverterRegistry:**類型轉換器注冊支持,可以注冊/刪除相應的類型轉換器。
```
package org.springframework.core.convert.converter;
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
void addConverter(Class<?> sourceType, Class<?> targetType, Converter<?, ?> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> converterFactory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}?
```
可以注冊:Converter實現,GenericConverter實現,ConverterFactory實現。
**(2、ConversionService:**運行時類型轉換服務接口,提供運行期類型轉換的支持。
```
package org.springframework.core.convert;
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}?
```
convert:將源對象轉換為目標類型的目標對象。
Spring提供了兩個默認實現(其都實現了ConverterRegistry**、**ConversionService接口):
DefaultConversionService:默認的類型轉換服務實現;
DefaultFormattingConversionService:帶數據格式化支持的類型轉換服務實現,一般使用該服務實現即可。
### 7.2.2.2、Spring內建的類型轉換器如下所示:
| **類名** | **說明** |
| --- | --- | --- |
| **第一組:標量轉換器** |
| StringToBooleanConverter | String----->Booleantrue:true/on/yes/1; false:false/off/no/0 |
| ObjectToStringConverter | Object----->String調用toString方法轉換 |
| StringToNumberConverterFactory | String----->Number(如Integer、Long等) |
| NumberToNumberConverterFactory | Number子類型(Integer、Long、Double等)<——> Number子類型(Integer、Long、Double等) |
| StringToCharacterConverter | String----->java.lang.Character取字符串第一個字符 |
| NumberToCharacterConverter | Number子類型(Integer、Long、Double等)——> java.lang.Character |
| CharacterToNumberFactory | java.lang.Character ——>Number子類型(Integer、Long、Double等) |
| StringToEnumConverterFactory | String----->enum類型通過Enum.valueOf將字符串轉換為需要的enum類型 |
| EnumToStringConverter | enum類型----->String返回enum對象的name()值 |
| StringToLocaleConverter | String----->java.util.Local |
| PropertiesToStringConverter | java.util.Properties----->String默認通過ISO-8859-1解碼 |
| StringToPropertiesConverter | String----->java.util.Properties默認使用ISO-8859-1編碼 |
| **第二組:集合、數組相關轉換器** |
| ArrayToCollectionConverter | 任意S數組---->任意T集合(List、Set) |
| CollectionToArrayConverter | 任意T集合(List、Set)---->任意S數組 |
| ArrayToArrayConverter | 任意S數組<---->任意T數組 |
| CollectionToCollectionConverter | 任意T集合(List、Set)<---->任意T集合(List、Set)即集合之間的類型轉換 |
| MapToMapConverter | Map<---->Map之間的轉換 |
| ArrayToStringConverter | 任意S數組---->String類型 |
| StringToArrayConverter | String----->數組默認通過“,”分割,且去除字符串的兩邊空格(trim) |
| ArrayToObjectConverter | 任意S數組---->任意Object的轉換(如果目標類型和源類型兼容,直接返回源對象;否則返回S數組的第一個元素并進行類型轉換) |
| ObjectToArrayConverter | Object----->單元素數組 |
| CollectionToStringConverter | 任意T集合(List、Set)---->String類型 |
| StringToCollectionConverter | String----->集合(List、Set)默認通過“,”分割,且去除字符串的兩邊空格(trim) |
| CollectionToObjectConverter | 任意T集合---->任意Object的轉換(如果目標類型和源類型兼容,直接返回源對象;否則返回S數組的第一個元素并進行類型轉換) |
| ObjectToCollectionConverter | Object----->單元素集合 |
| **第三組:默認(fallback)轉換器:**之前的轉換器不能轉換時調用 |
| ObjectToObjectConverter | Object(S)----->Object(T)首先嘗試valueOf進行轉換、沒有則嘗試new 構造器(S) |
| IdToEntityConverter | Id(S)----->Entity(T)查找并調用public static T find[EntityName](S)獲取目標對象,EntityName是T類型的簡單類型 |
| FallbackObjectToStringConverter | Object----->StringConversionService作為恢復使用,即其他轉換器不能轉換時調用(執行對象的toString()方法) |
S:代表源類型,T:代表目標類型
如上的轉換器在使用轉換服務實現DefaultConversionService和DefaultFormattingConversionService時會自動注冊。
### 7.2.2.3、示例
(1、自定義String----->PhoneNumberModel的轉換器
```
package cn.javass.chapter7.web.controller.support.converter;
//省略import
public class StringToPhoneNumberConverter implements Converter<String, PhoneNumberModel> {
Pattern pattern = Pattern.compile("^(\\d{3,4})-(\\d{7,8})$");
@Override
public PhoneNumberModel convert(String source) {
if(!StringUtils.hasLength(source)) {
//①如果source為空 返回null
return null;
}
Matcher matcher = pattern.matcher(source);
if(matcher.matches()) {
//②如果匹配 進行轉換
PhoneNumberModel phoneNumber = new PhoneNumberModel();
phoneNumber.setAreaCode(matcher.group(1));
phoneNumber.setPhoneNumber(matcher.group(2));
return phoneNumber;
} else {
//③如果不匹配 轉換失敗
throw new IllegalArgumentException(String.format("類型轉換失敗,需要格式[010-12345678],但格式是[%s]", source));
}
}
}
```
String轉換為Date的類型轉換器,請參考cn.javass.chapter7.web.controller.support.converter.StringToDateConverter。
(2、測試用例(cn.javass.chapter7.web.controller.support.converter.ConverterTest)
```
@Test
public void testStringToPhoneNumberConvert() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringToPhoneNumberConverter());
String phoneNumberStr = "010-12345678";
PhoneNumberModel phoneNumber = conversionService.convert(phoneNumberStr, PhoneNumberModel.class);
Assert.assertEquals("010", phoneNumber.getAreaCode());
}?
```
類似于PhoneNumberEditor將字符串“010-12345678”轉換為PhoneNumberModel。??
```
@Test
public void testOtherConvert() {
DefaultConversionService conversionService = new DefaultConversionService();
//"1"--->true(字符串“1”可以轉換為布爾值true)
Assert.assertEquals(Boolean.valueOf(true), conversionService.convert("1", Boolean.class));
//"1,2,3,4"--->List(轉換完畢的集合大小為4)
Assert.assertEquals(4, conversionService.convert("1,2,3,4", List.class).size());
}?
```
其他類型轉換器使用也是類似的,此處不再重復。
### 7.2.2.4、集成到Spring Web MVC環境
(1、注冊ConversionService實現和自定義的類型轉換器
```
<!-- ①注冊ConversionService -->
<bean id="conversionService" class="org.springframework.format.support.
FormattingConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="cn.javass.chapter7.web.controller.support.
converter.StringToPhoneNumberConverter"/>
<bean class="cn.javass.chapter7.web.controller.support.
converter.StringToDateConverter">
<constructor-arg value="yyyy-MM-dd"/>
</bean>
</list>
</property>
</bean>?
```
FormattingConversionServiceFactoryBean:是FactoryBean實現,默認使用DefaultFormattingConversionService轉換器服務實現;
converters:注冊我們自定義的類型轉換器,此處注冊了String--->PhoneNumberModel和String--->Date的類型轉換器。
(2、通過ConfigurableWebBindingInitializer注冊ConversionService
```
<!-- ②使用ConfigurableWebBindingInitializer注冊conversionService -->
<bean id="webBindingInitializer" class="org.springframework.web.bind.support.
ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"/>
</bean>?
```
此處我們通過ConfigurableWebBindingInitializer綁定初始化器進行ConversionService的注冊;
3、注冊ConfigurableWebBindingInitializer到RequestMappingHandlerAdapter
```
<bean class="org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter">
<property name="webBindingInitializer" ref="webBindingInitializer"/>
</bean>?
```
通過如上配置,我們就完成了Spring3.0的類型轉換系統與Spring Web MVC的集成。此時可以啟動服務器輸入之前的URL測試了。
此時可能有人會問,如果我同時使用PropertyEditor和ConversionService,執行順序是什么呢?內部首先查找PropertyEditor進行類型轉換,如果沒有找到相應的PropertyEditor再通過ConversionService進行轉換。
如上集成過程看起來比較麻煩,后邊我們會介紹<mvc:annotation-driven>和@EnableWebMvc,ConversionService會自動注冊,后續章節再詳細介紹。
- 跟我學 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