一年又一年成畦,字節(jié)跳動(dòng) Lark(飛書) 研發(fā)團(tuán)隊(duì)又雙叒叕開始招新生啦!
【內(nèi)推碼】:GTPUVBA
【內(nèi)推鏈接】:https://job.toutiao.com/s/JRupWVj
【招生對(duì)象】:20年9月后~21年8月前 畢業(yè)的同學(xué)
【報(bào)名時(shí)間】:6.16-7.16(提前批簡(jiǎn)歷投遞只有一個(gè)月抓住機(jī)會(huì)哦@钥)
【畫重點(diǎn)】:提前批和正式秋招不矛盾循帐!面試成功,提前鎖定Offer忠寻;若有失利惧浴,額外獲得一次面試機(jī)會(huì)存和,正式秋招開啟后還可再次投遞奕剃。
點(diǎn)擊進(jìn)入我的博客
更多章節(jié)
Spring詳解1.概述
Spring詳解2.理解IoC容器
Spring詳解3.Bean的裝配
Spring詳解4.容器內(nèi)幕
Spring詳解5.AOP
Spring詳解6.基于AspectJ的AOP
Spring詳解7.Spring MVC
Spring詳解8.Spring DAO
1 概述
1.1 Spring特點(diǎn)
- 注解驅(qū)動(dòng):Spring MVC通過一套MVC注解,讓POJO成為處理請(qǐng)求的控制器捐腿,無需實(shí)現(xiàn)任何接口
- REST風(fēng)格:Spring MVC支持REST風(fēng)格的URL請(qǐng)求
1.2 核心內(nèi)容
Spring MVC框架圍繞DispatcherServlet這個(gè)核心展開纵朋,它負(fù)責(zé)截獲請(qǐng)求并將其分派給相應(yīng)的處理器處理。Spring MVC框架包括注解驅(qū)動(dòng)控制器茄袖、請(qǐng)求及響應(yīng)的信息處理操软、視圖解析、本地化解析宪祥、上傳文件解析聂薪、異常處理以及表單標(biāo)簽綁定等內(nèi)容家乘。
1.3 體系結(jié)構(gòu)
Spring MVC是基于Model 2實(shí)現(xiàn)的技術(shù)框架。Spring MVC通過一個(gè)DispatcherServlet接收所有請(qǐng)求藏澳,并將具體工作委托給其他組件進(jìn)行處理仁锯。
- 客戶端發(fā)出一個(gè)HTTP請(qǐng)求,Web應(yīng)用服務(wù)器接收到這個(gè)請(qǐng)求翔悠,如果匹配DispatcherServlet的請(qǐng)求映射路徑(在web.xml中指定)业崖,Web容器將該請(qǐng)求轉(zhuǎn)交給DispatcherServlet處理。
- DispatcherServlet接收到這個(gè)請(qǐng)求后蓄愁,將根據(jù)請(qǐng)求的信息(包括URL双炕、HTTP方法、請(qǐng)求報(bào)文頭撮抓、請(qǐng)求參數(shù)妇斤、Cookie等)及HandlerMapping的配置找到處理請(qǐng)求的處理器(Handler)〉ふ可將HandlerMapping看成路由控制器趟济,將Handler看成目標(biāo)主機(jī)。值得注意的是:Spring MVC中并沒有定義一個(gè)Handler接口咽笼,實(shí)際上任何一個(gè)Object都可以成為請(qǐng)求處理器顷编。
- 當(dāng)DispatcherServlet根據(jù)HandlerMapping得到對(duì)應(yīng)當(dāng)前請(qǐng)求的Handler后,通過HandlerAdapter對(duì)Handler進(jìn)行封裝剑刑,再以統(tǒng)一的適配器接口調(diào)用Handler媳纬。 HandlerAdapter是Spring MVC的框架級(jí)接口,顧名思義HandlerAdapter是一個(gè)適配器施掏,它用統(tǒng)一的接口對(duì)各種Handler方法進(jìn)行調(diào)用钮惠。
- 處理器完成業(yè)務(wù)邏輯的處理后將運(yùn)回一個(gè)ModelAndView給DispatcherServlet,ModelAndView包含了視圖邏輯名和模型數(shù)據(jù)信息七芭。
- ModelAndView中包含的是“邏輯視圖名”而非真正的視圖對(duì)象素挽,DispatcherServlet借由ViewResolver完成邏輯視圖名到真實(shí)視圖對(duì)象的解析工作。
- 當(dāng)?shù)玫秸鎸?shí)的視圖對(duì)象View后狸驳,DispatcherServlet就使用這個(gè)View對(duì)象對(duì)ModelAndView中的模型數(shù)據(jù)進(jìn)行視圖渲染预明。
- 最終客戶端得到的響應(yīng)消息,可能是一個(gè)普通的HTML頁而耙箍,也可能是一個(gè)XML或JSON串撰糠, 甚至是一張圖片或一個(gè)PDF文檔等不同的媒體形式。
1.4 配置DispatcherServlet
可以在web.xml中配置一個(gè)Servlet辩昆,并通過<servlet-mapping>指定其處理的URL阅酪。
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<!-- (1)從類路徑下加載Spring配置文件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-context.xml</param-value>
</context-param>
<!-- (2)負(fù)責(zé)啟動(dòng) Spring 容器的監(jiān)聽器,它將引用(1)處的上下文參數(shù)獲得Spring配置文件的地址 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- (3)配置DispatcherServlet -->
<servlet>
<servlet-name>web</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- (4)指定處理的URL路徑 -->
<servlet-mapping>
<servlet-name>web</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
- 在(1)處,通過contextConfigLocation參數(shù)指定業(yè)務(wù)層Spring容器的配置文件(多個(gè)配置文件用
,
分割)术辐。 - 在(2)處砚尽,ContextLoaderListener是一個(gè)ServletLoaderListener,它通過contextConfigLocation指定的Spring配置文件啟動(dòng)業(yè)務(wù)層的Spring容器辉词。
- 在(3)處尉辑,配置了名為web的DispatcherServlet,它默認(rèn)加載/WEB-INF/web-servlet.xml(
<servlet-name>-servlet.xml
)的Spring配置文件较屿,啟動(dòng)Web層的Spring容器隧魄。Web層容器將作為業(yè)務(wù)層容器的子容器,Web層容器可以訪問業(yè)務(wù)層容器的Bean隘蝎,而業(yè)務(wù)層容器訪問不了Web層容器的Bean购啄。 - 在(4)處,通過<servlet-mapping>指定DispatcherServlet處理
/*
全部的HTTP請(qǐng)求嘱么。一個(gè)web.xml可以配置多個(gè)DispatcherServlet狮含,通過其對(duì)應(yīng)的<servlet-mapping>配置,讓每個(gè)DispatcherServlet處理不同的請(qǐng)求曼振。
DispatcherServlet 的配置參數(shù)
可以通過<servlet>的<init-param>屬性指定配置參數(shù):
- namespace參數(shù):DispatcherServlet對(duì)應(yīng)的命名空間几迄,默認(rèn)是
WEB-INF/<servlet-name>-servlet.xml
。在顯式配置該參數(shù)后冰评,新的配置文件對(duì)應(yīng)的路徑是WEB-INF/<namespace>.xml
映胁,例如如果將namespace設(shè)置為sample,則對(duì)應(yīng)的Spring配置文件為WEB-INF/sample.xml甲雅。 - contextConfigLocation:如果DispatcherServlet上下文對(duì)應(yīng)的Spring配置文件有多個(gè)解孙,則可以使用該屬性按照Spring資源路徑的方式指定,如
classpath:sample1.xml,classpath:sample2.xml
抛人。 - publishContext:默認(rèn)為true弛姜。DispatcherServlet根據(jù)該屬性決定是否將WebApplicationContext發(fā)布到ServletContext的屬性列表中,方便調(diào)用者可借由ServletContext找到WebApplicationContext實(shí)例妖枚,對(duì)應(yīng)的屬性名為
DispatcherServlet#getServletContextAttributeName()
的返回值廷臼。 - publishEvents:默認(rèn)為true。當(dāng)DispatcherServlet處理完一個(gè)請(qǐng)求后绝页,是否需要向容器發(fā)布一個(gè)ServletRequestHandleEvent事件荠商。
Spring容器配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">
<context:component-scan base-package="com.ankeetc.web"/>
<!-- 會(huì)自動(dòng)注冊(cè)RequestMappingHandlerMapping與RequestMappingHandlerAdapter兩個(gè)Bean,這是SpringMVC為@Controllers分發(fā)請(qǐng)求所必需的 -->
<!-- 并提供了數(shù)據(jù)綁定支持抒寂、@NumberFormatannotation支持结啼、 @DateTimeFormat支持掠剑、@Valid支持屈芜、讀寫XML的支持和讀寫JSON的支持等功能属铁。 -->
<mvc:annotation-driven />
</beans>
1.5 基于編程的配置
Spring 4.0已經(jīng)全面支持Servlet 3.0例嘱,可以使用編程的方式配置Servlet容器腋腮。在Servlet 3.0環(huán)境中袜刷,容器會(huì)在類路徑中查找實(shí)現(xiàn)javax.servlet.ServletContainerInitializer
接口的類钢拧,如果發(fā)現(xiàn)實(shí)現(xiàn)類膜钓,就會(huì)用它來配置Servlet容器沃疮。Spring提供了這個(gè)接口的實(shí)現(xiàn)肺缕,名為SpringServletContainerInitializer泉手,這個(gè)類反過來又查找實(shí)現(xiàn)WebApplicationInitializer的類并將配置的任務(wù)交給它們來完成。Spring還提供了一個(gè)WebApplicationInitializer基礎(chǔ)實(shí)現(xiàn)類AbstractAnnotationConfigDispatcherServletInitializer内狸,使得它在注冊(cè)DispatcherServlet時(shí)只需要簡(jiǎn)單地指定它的Servlet映射即可。
public class WebApplicationInitilalizer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
ServletRegistration.Dynamic registration = servletContext.addServlet("web", new DispatcherServlet());
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
1.6 DispatcherServlet的內(nèi)部邏輯
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
DispatcherServlet#initStrategies()方法將在WebApplicationContext初始化后執(zhí)行,此時(shí)Spring上下文中的Bean已經(jīng)初始化完畢安皱,該方法通過反射查找并裝配Spring容器中用戶自定義的Bean居砖,如果找不到就裝配默認(rèn)的組件實(shí)例。
默認(rèn)組件
在DispatcherServlet.properties配置文件里邊唇敞,指定了DispatcherServlet所使用的默認(rèn)組件蔗草。如果用戶希望采用非默認(rèn)的組件,只需在Spring配置文件中配置自定義的組件Bean即可疆柔。
# 本地化解析器
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
# 主題解析器
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
# 處理器解析器
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
# 處理器適配器
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
# 異常處理器
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
# 視圖名稱處理器
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
# 視圖解析器
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
2 注解驅(qū)動(dòng)的控制器
2.1 @RequestMapping映射請(qǐng)求
- 在POJO類上標(biāo)注@Controller咒精,再通過<context:component-scan>掃描到該類,可以是POJO成為一個(gè)能處理HTTP請(qǐng)求的控制器旷档。
- 在控制器的類定義和方法定義處都可以使用@RequestMapping映射對(duì)應(yīng)的處理方法模叙。
- @RequestMapping不但支持標(biāo)準(zhǔn)的URL,還支持Ant風(fēng)格和{XXX}占位符的URL鞋屈。
- @RequestMapping和value范咨、method、params及headers分別表示請(qǐng)求路徑厂庇、請(qǐng)求方法渠啊、請(qǐng)求參數(shù)及報(bào)文頭的映射條件。
2.2 獲取請(qǐng)求內(nèi)容
- 可以通過@RequestParam权旷、@RequestHeader昭抒、@PathVariable獲取HTTP請(qǐng)求信息。
- 可以使用@CookieValue讓方法入?yún)⒔壎硞€(gè)Cookie值
- 可以使用@MatrixVariable注解將請(qǐng)求中的矩陣變量綁定到處理器的方法參數(shù)中炼杖。
- 可以使用命令/表單對(duì)象(就是一個(gè)POJO)綁定請(qǐng)求參數(shù)值灭返,Spring會(huì)按照請(qǐng)求參數(shù)名和對(duì)象屬性名匹配的方式,自動(dòng)為該對(duì)象填充屬性坤邪。
- 可以使用Servlet API的類作為處理方法的入?yún)⑽鹾鏗ttpServletRequest、HttpServletResponse艇纺、HttpSession怎静;如果使用HttpServletResponse返回相應(yīng)邮弹,則處理方法返回著設(shè)置成void即可;在
org.springframework.web.context.request
定義了若干個(gè)可代理Servlet原生API類的接口蚓聘,如WebRequest和NativeWebRequest腌乡。 - 可以使用java.io中的InputStream、Reader夜牡、OutputStream与纽、Writer作為方法的入?yún)ⅰ?/li>
- 還可以使用java.util.Locale、java.security.Principal作為入?yún)ⅰ?/li>
2.3 使用HttpMessageConverter
HttpMessageConverter接口可以將請(qǐng)求信息轉(zhuǎn)換為一個(gè)對(duì)象(類型為T)塘装,并將對(duì)象(類型為T)綁定到請(qǐng)求方法的參數(shù)中或輸出為響應(yīng)信息急迂。DispatcherServlet默認(rèn)已經(jīng)安裝了RequestMethodHandlerAdapter作為HandlerAdapter組件的實(shí)現(xiàn)類,HttpMessageConverter即由RequestMethodHandlerAdapter使用蹦肴,將請(qǐng)求信息轉(zhuǎn)換為對(duì)象僚碎,或?qū)?duì)象轉(zhuǎn)換為響應(yīng)信息。
HttpMessageConverter的實(shí)現(xiàn)類
Spring為HttpMessageConverter提供了眾多的實(shí)現(xiàn)類:
默認(rèn)的HttpMessageConverter
RequestMappingHandlerAdapter已經(jīng)默認(rèn)裝配了以下的HttpMessageConverter:
- StringHttpMessageConverter
- ByteArrayHttpMessageConverter
- SourceHttpMessageConverter
- AllEncompassingFormHttpMessageConverter
裝配其他類型的HttpMessageConverter
如果需要裝配其他類型的HttpMessageConverter阴幌,可以在Spring的Web容器上下文中自行定義一個(gè)RequestMappingHandlerAdapter勺阐,注冊(cè)若干HttpMessageConverter。如果在Spring web容器中顯式定義了一個(gè)RequestMappingHandlerAdapter矛双,則Spring MVC將使用它覆蓋默認(rèn)的RequestMappingHandlerAdapter渊抽。
使用HttpMessageConverter
- 可以使用@RequestBody、@ResponseBody對(duì)處理方法進(jìn)行標(biāo)注
- 可以使用HttpEntity<T>背零、ResponseEntity<T>作為處理方法的入?yún)⒒蚍祷刂?/li>
RestTemplate是Spring的模板類腰吟,可以使用該類調(diào)用Web服務(wù)端的服務(wù),它支持Rest風(fēng)格的URL徙瓶。
結(jié)論
- 當(dāng)控制器處理方法使用到@RequestBody毛雇、@ResponseBody 或 HttpEntity<T>、ResponseEntity<T> 時(shí)侦镇,Spring MVC才會(huì)使用注冊(cè)的HttpMessageConvertor對(duì)請(qǐng)求灵疮、相應(yīng)消息進(jìn)行處理。
- 當(dāng)控制器處理方法使用到@RequestBody壳繁、@ResponseBody 或 HttpEntity<T>震捣、ResponseEntity<T>時(shí),Spring 首先根據(jù)請(qǐng)求頭或響應(yīng)的Accept屬性選擇匹配的 HttpMessageConverter闹炉,進(jìn)而根據(jù)參數(shù)類型或泛型類型的過濾得到匹配的 HttpMessageConverter蒿赢,若找不到可用的 HttpMessageConverter 將報(bào)錯(cuò)。
- @RequestBody渣触、@ResponseBody不需要成對(duì)出現(xiàn)羡棵。
處理XML和JSON
Spring MVC提供了幾個(gè)處理XML和JSON格式的請(qǐng)求、響應(yīng)消息的HttpMessageConverter:
- MarshallingHttpMessageConverter:處理XML
- Jaxb2RootElementHttpMessageConverter:處理XML嗅钻,底層使用JAXB
- MappingJackson2HttpMessageConverter:處理JSON格式
只要在Spring Web容器中為RequestMappingHandlerAdapter裝配好相應(yīng)的HttpMessageConverter皂冰,并在交互中通過請(qǐng)求的Accept指定MIME類型店展,Spring MVC就可以是服務(wù)器段的處理方法和客戶端透明的通過XML或JSON格式進(jìn)行通信。
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
</list>
</property>
</bean>
2.4 使用@RestController
@RestController已經(jīng)標(biāo)注了@ResponseBody和@Controller秃流,可以直接在控制器上標(biāo)注該注解赂蕴,就不用在每個(gè)@RequestMapping方法上添加@ResponseBody了。
2.5 AsyncRestTemplate
Spring 4.0提供了AsyncRestTemplate用于以異步無阻塞的方式進(jìn)行服務(wù)訪問舶胀。
public class WebApplicationInitilalizer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
ServletRegistration.Dynamic registration = servletContext.addServlet("web", new DispatcherServlet());
registration.setLoadOnStartup(1);
// 此處要設(shè)置為true
registration.setAsyncSupported(true);
registration.addMapping("/");
}
}
@RestController
public class AsyncController {
@RequestMapping(value = "/async", method = RequestMethod.GET)
public Callable<String> async() {
System.out.println("hello!");
return new Callable<String>() {
@Override
public String call() throws Exception {
TimeUnit.SECONDS.sleep(5);
return "ASYNC";
}
};
}
}
public class Main {
public static void main(String[] args) {
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate();
ListenableFuture<ResponseEntity<String>> future = asyncRestTemplate.getForEntity("http://localhost:8080/async", String.class);
System.out.println("return");
future.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onFailure(Throwable ex) {
System.out.println("Failure");
}
@Override
public void onSuccess(ResponseEntity<String> result) {
System.out.println("Success");
}
});
}
}
2.6 處理模型數(shù)據(jù)
Spring MVC提供了多種途徑輸出模型數(shù)據(jù):
- ModelAndView:當(dāng)處理方法返回值類型為ModelAndView時(shí)概说,方法體即可通過該對(duì)象添加模型數(shù)據(jù);
- @ModelAttribute:在方法入?yún)?biāo)注該注解后峻贮,入?yún)⒌膶?duì)象就會(huì)放到數(shù)據(jù)模型中席怪;
- Map和Model:如果方法入?yún)閛rg.framework.ui.Model应闯、org.framework.ui.ModelMap纤控、java.util.Map,當(dāng)處理方法返回時(shí)碉纺,Map中的數(shù)據(jù)會(huì)自動(dòng)添加到模型中船万;
- @SessionAttributes:將模型中的某個(gè)屬性暫存到HttpSession中,以便多個(gè)請(qǐng)求之間可以共享這個(gè)屬性骨田。
3 處理方法的數(shù)據(jù)綁定
Spring會(huì)根據(jù)請(qǐng)求方法簽名的不同耿导,將請(qǐng)求中的信息以一定方式轉(zhuǎn)換并綁定到請(qǐng)求方法的入?yún)⒅校€會(huì)進(jìn)行數(shù)據(jù)轉(zhuǎn)換态贤、數(shù)據(jù)格式化及數(shù)據(jù)校驗(yàn)等舱呻。
3.1 數(shù)據(jù)綁定流程
Spring MVC通過反射對(duì)目標(biāo)簽名進(jìn)行分析,將請(qǐng)求消息綁定到處理方法的入?yún)⒅杏破?shù)據(jù)綁定的核心部件是DataBinder箱吕。Spring MVC主框架將ServletRequest對(duì)象及處理方法的入?yún)?duì)象實(shí)例傳遞給 DataBinder,DataBinder 首先調(diào)用裝配在 Spring Web 上下文中的 ConversionService 組件進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換柿冲、數(shù)據(jù)格式化等工作茬高,將ServletRequest中的消息填充到入?yún)?duì)象中, 然后調(diào)用Validator組件對(duì)己經(jīng)綁定了請(qǐng)求消息數(shù)據(jù)的入?yún)?duì)象進(jìn)行數(shù)據(jù)合法性校驗(yàn)假抄,最 終生成數(shù)據(jù)綁定結(jié)果BindingResult對(duì)象怎栽。BindingResult包含了已完成數(shù)據(jù)綁定的入?yún)?對(duì)象,還包含相應(yīng)的校驗(yàn)錯(cuò)誤對(duì)象宿饱。Spring MVC抽取BindingResult中的入?yún)?duì)象及校驗(yàn)錯(cuò)誤對(duì)象熏瞄,將它們賦給處理方法的相應(yīng)入?yún)ⅰ?/p>
3.2 數(shù)據(jù)轉(zhuǎn)換
類型轉(zhuǎn)換模塊位于org.framework.core.convert包中,同時(shí)由于歷史原因谬以,Spring還支持JDK的PropertyEditor强饮。
ConversionService簡(jiǎn)介
ConversionService 是 Spring 類型轉(zhuǎn)換體系的核心接口,它定義了以下4個(gè)方法:
- boolean canConvert(Class<?> sourceType, Class<?> targetType):判斷是否可以將一個(gè)Java類轉(zhuǎn)換為另一個(gè)Java類蛉签。
- Boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType):需轉(zhuǎn)換的類將以成員變量的方式出現(xiàn)在宿主類中胡陪。TypeDescriptor不但描述了需轉(zhuǎn)換類的信息沥寥,還描述了從宿主類的上下文信息,如成員變量上的注解柠座,成員變量是否以數(shù)組邑雅、集合或Map的方式呈現(xiàn)等。類型轉(zhuǎn)換邏輯可以利用這些信息做出 各種靈活的控制妈经。
- <T> T convert(Object source, Class<T> targetType):將原類型對(duì)象轉(zhuǎn)換為目標(biāo)類型對(duì)象淮野。
- Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType):
將對(duì)象從原類型對(duì)象轉(zhuǎn)換為目標(biāo)類型對(duì)象,此時(shí)往往會(huì)用到所在宿主類的上下 文信息吹泡。
第一個(gè)和第三個(gè)接口方法類似于PmpertyEditor骤星,它們不關(guān)注類型對(duì)象所在的上下文 信息,只簡(jiǎn)單地完成兩個(gè)類型對(duì)象的轉(zhuǎn)換爆哑,唯一的區(qū)別在于這兩個(gè)方法支持任意兩個(gè)類型的轉(zhuǎn)換洞难。而第二個(gè)和第四個(gè)接口方法會(huì)參考類型對(duì)象所在宿主類的上下文信息,并利用這些信息進(jìn)行類型轉(zhuǎn)換揭朝。
使用ConversionService
可以利用 org.springframework.context.support.ConversionServiceFactoryBean
在 Spring 的 上下文中定義一個(gè)ConversionService队贱。Spring將自動(dòng)識(shí)別出上下文中的ConversionService, 并在Bean屬性配置及Spring MVC處理方法入?yún)⒔壎ǖ葓?chǎng)合使用它進(jìn)行數(shù)據(jù)轉(zhuǎn)換潭袱。該FactoryBean創(chuàng)建ConversionService內(nèi)建了很多轉(zhuǎn)換器柱嫌,可完成大多數(shù)Java類型的轉(zhuǎn)換工作。除了包括將String對(duì)象轉(zhuǎn)換為各種基礎(chǔ)類型的對(duì)象外屯换,還包括String编丘、 Number、Array彤悔、Collection嘉抓、Map、Properties 及 Object 之間的轉(zhuǎn)換器蜗巧≌泼撸可通過ConversionServiceFactoryBean的converters屬性注冊(cè)自定義的類型轉(zhuǎn)換器:
<bean class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="com.ankeetc.MyConverter"/>
</list>
</property>
</bean>
Spring支持的轉(zhuǎn)換器
Spring 在 org.springframework.core.convert.converter 包中定義了3種類型的轉(zhuǎn)換器接口,實(shí)現(xiàn)任意一個(gè)轉(zhuǎn)換器接口都可以作為自定義轉(zhuǎn)換器注冊(cè)到ConversionServiceFactoryBean中幕屹。這3種類型的轉(zhuǎn)換器接口分別為:
- Converter<S, T>:將S類型的對(duì)象轉(zhuǎn)換為T類型的對(duì)象
- GenericConverter:根據(jù)源類對(duì)象及目標(biāo)類對(duì)象所在的宿主類的上下文信息進(jìn)行類型轉(zhuǎn)換工作蓝丙。該類還有一個(gè)子接口ConditionalGenericConverter,它添加了一個(gè)接口方法根據(jù)源類型及目標(biāo)類型所在宿主類的上下文信息決定是否要進(jìn)行類型轉(zhuǎn)換望拖。
- ConverterFactory:
ConversionServiceFactoryBean 的 converters 屬性可接受 Converter渺尘、ConverterFactory、 GenericConverter或ConditionalGenericConverter接口的實(shí)現(xiàn)類说敏,并把這些轉(zhuǎn)換器的轉(zhuǎn)換邏輯統(tǒng)一封裝到一個(gè) ConversionService 實(shí)例對(duì)象中(GenericConversionService)鸥跟。Spring 在Bean屬性配置及Spring MVC請(qǐng)求消息綁定時(shí)將利用這個(gè)ConversionService實(shí)例完成類型轉(zhuǎn)換工作。
在Spring中使用@lnitBinder 和 WebBindingInitializer裝配自定義編輯器
Spring也支持JavaBeans的PropertyEditor∫阶桑可以在控制器中使用@InitBinder添加自定義的編輯器枫匾,也可以通過 WebBindingInitializer 裝配在全局范圍內(nèi)使用的編輯器。
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(User.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws IllegalArgumentException {
User user = new User();
user.setName(text);
this.setValue(user);
}
});
}
如果希望在全局范圍內(nèi)使用拟淮,則可實(shí)現(xiàn)WebBindingInitializer接口并在該實(shí)現(xiàn)類中注冊(cè)干茉。
- 實(shí)現(xiàn)WebBindingInitializer接口并在initBinder接口方法中注冊(cè)了自定義的編輯器。
- 在 Spring 上下文中通過 RequestMappingHandlerAdapter 裝配自定義的Initializer很泊。
順序
對(duì)于同一個(gè)類型對(duì)象來說角虫,如果既在ConversionService中裝配了自定義轉(zhuǎn)換器,又通過WebBindinglnitializer裝配了自定義編輯器委造,同時(shí)還在控制器中通過@InitBinder裝 配了自定義編輯器戳鹅,那么Spring MVC將按以下優(yōu)先順序查找對(duì)應(yīng)類型的編輯器:
- 查詢通過@InitBinder裝配的自定義編輯器。
- 查詢通過ConversionService裝配的自定義轉(zhuǎn)換器昏兆。
- 查詢通過WebBindingInitializer裝配的自定義編輯器枫虏。
3.3 數(shù)據(jù)格式化
Spring的轉(zhuǎn)換器并不提供輸入及輸出信息格式化的工作,一般需要轉(zhuǎn)換的源類型數(shù)據(jù)(一般是字符串)都是具有一定格式的亮垫,在不同的本地化環(huán)境中模软, 同一類型的數(shù)據(jù)還會(huì)相應(yīng)地呈現(xiàn)不同的顯示格式伟骨。Spring引入了一個(gè)新的格式化框架饮潦,這個(gè)框架位于org.springframework.format類包中。
最重要的 Formatter<T>接口
注解驅(qū)動(dòng)格式化AnnotationFormatterFactory
為了讓注解和格式化的屬性類型關(guān)聯(lián)起來携狭,Spring在Formatter<T>所在的包中還提供了一個(gè) AnnotationFormatterFactory<A extends Annotation>接口继蜡。
啟用注解驅(qū)動(dòng)格式化功能
對(duì)屬性對(duì)象的輸入/輸出進(jìn)行格式化,從本質(zhì)上講依然屬于“類型轉(zhuǎn)換”的范疇逛腿。 Spring就是基于對(duì)象轉(zhuǎn)換框架植入“格式化”功能的稀并。Spring 在格式化模塊中定義了一個(gè)實(shí)現(xiàn) ConversionService 接口的 FormattingConversionService實(shí)現(xiàn)類,該實(shí)現(xiàn)類擴(kuò)展了 GenericConversionService单默,因此它既具有類型轉(zhuǎn)換功能碘举,又具有格式化功能。
FormattingConversionService 也擁有一個(gè)對(duì)應(yīng)的 FormattingConversionServiceFactoryBean 工廠類搁廓,后者用于在Spring上下文中構(gòu)造一個(gè)FormattingConversionService引颈。通過這個(gè)工廠類,既可以注冊(cè)自定義的轉(zhuǎn)換器境蜕,還可以注冊(cè)自定義的注解驅(qū)動(dòng)邏輯蝙场。由于 FormattingConversionServiceFactoryBean 在內(nèi)部會(huì)自動(dòng)注冊(cè) NumberFormatAnnotationFormatterFactory 和 JodaDateTimeFormatAnnotationFormatterFactory,因此裝配了 FormattingConversionServiceFactoryBean 后粱年,就可以在 Spring MVC 入?yún)⒔壎澳P蛿?shù)據(jù)輸出時(shí)使用注解驅(qū)動(dòng)的格式化功能售滤。
值得注意的是,<mvc:annotation-driven/>
標(biāo)簽內(nèi)部默認(rèn)創(chuàng)建的ConversionService實(shí)例就是一個(gè) FormattingConversionServiceFactoryBean。
3.4 數(shù)據(jù)校驗(yàn)
Spring擁有自己獨(dú)立的數(shù)據(jù)校驗(yàn)框架完箩,同時(shí)支持JSR-303標(biāo)準(zhǔn)的校驗(yàn)框架赐俗。Spring 的DataBinder在進(jìn)行數(shù)據(jù)綁定時(shí),可同時(shí)調(diào)用校驗(yàn)框架完成數(shù)據(jù)校驗(yàn)工作弊知。在Spring MVC中秃励,則可直接通過注解驅(qū)動(dòng)的方式進(jìn)行數(shù)據(jù)校驗(yàn)。
LocalValidatorFactoryBean 既實(shí)現(xiàn)了 Spring 的 Validator 接口吉捶,又實(shí)現(xiàn)了 JSR-303 的 Validator 接口夺鲜。只要在 Spring 容器中定義了一個(gè) LocalValidatorFactoryBean,即可將其注入需要數(shù)據(jù)校驗(yàn)的Bean中呐舔。值得注意的是币励,Spring本身沒有提供JSR-303的實(shí)現(xiàn),所以必須將JSR-303的實(shí)現(xiàn) 者(如Hibernate Validator)的JAR文件放到類路徑下珊拼,Spring將自動(dòng)加載并裝配好 JSR-303的實(shí)現(xiàn)者食呻。
<mvc:annotation-driven/>會(huì)默認(rèn)裝配一個(gè) LocalValidatorFactoryBean,通過在處理方法的入?yún)⑸蠘?biāo)注@Valid注解澎现,即可讓Spring MVC在完成數(shù)據(jù)綁定后執(zhí)行數(shù)據(jù)校驗(yàn)工作仅胞。
4 視圖和視圖解析器
5 本地化
Spring提供了以下4個(gè)本地化解析器。
- AcceptHeaderLocaleResolver:根據(jù) HTTP 報(bào)文頭的 Accept-Language 參數(shù)確定本 地化類型剑辫。如果沒有顯式定義本地化解析器干旧,則Spring MVC默認(rèn)采用 AcceptHeaderLocaleResolver。
- CookieLocaleResolver:根據(jù)指定的Cookie值確定本地化類型妹蔽。
- SessionLocaleResolver:根據(jù)Session中特定的屬性值確定本地化類型椎眯。
- LocaleChangeInterceptor:從請(qǐng)求參數(shù)中獲取本次請(qǐng)求對(duì)應(yīng)的本地化類型。
6 文件上傳
Spring MVC為文件上傳提供了直接支持胳岂,這種支持是通過即插即用的MultipartResolver 實(shí)現(xiàn)的编整。Spring 使用 Jakarta Commons FileUpload 技術(shù)實(shí)現(xiàn)了一個(gè) MultipartResolver 實(shí)現(xiàn) 類:CommonsMultipartResolver。
在Spring MVC上下文中默認(rèn)沒有裝配MultipartResolver,因此默認(rèn)情況下不能 處理文件的上傳工作乳丰。如果想使用Spring的文件上傳功能掌测,則需要先在上下文中配置 MultipartResolver。
7 WebSocket
8 靜態(tài)資源處理
-
<mvc:default-servlet-handler/>
:在 smart-servlet.xml 中配置<mvc:default-servlet-handler/>后产园,會(huì)在 Spring MVC 上下文中定義一個(gè) org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler汞斧,它將充當(dāng)一個(gè)檢查員的角色,對(duì)進(jìn)入DispatcherServlet的URL進(jìn)行篩查淆两。如果發(fā)現(xiàn)是靜態(tài)資源的請(qǐng)求断箫,就將該請(qǐng)求轉(zhuǎn)由Web應(yīng)用服務(wù)器默認(rèn)的Servlet處理;如果不是靜態(tài)資源 的請(qǐng)求秋冰,則由DispatcherServlet繼續(xù)處理仲义。 -
<mvc:resources/>
:<mvc:default-servlet-handler/>
將靜態(tài)資源的處理經(jīng)由Spring MVC框架交回Web應(yīng) 用服務(wù)器。而<mvc:resources/>
更進(jìn)一步,由SpringMVC框架自己處理靜態(tài)資源埃撵,并添 加一些有用的附加功能赵颅。
9 攔截器
當(dāng)收到請(qǐng)求時(shí),DispatcherServlet將請(qǐng)求交給處理器映射(HandlerMapping)暂刘,讓它找出對(duì)應(yīng)該請(qǐng)求的HandlerExecutionChain對(duì)象饺谬。在講解HandlerMapping之前,有必要 認(rèn)識(shí)一下這個(gè) HandlerExecutionChain 對(duì)象谣拣。
HandlerExecutionChain負(fù)責(zé)處理請(qǐng)求并返回ModelAndView的處理執(zhí)行鏈募寨,它包含一個(gè)處理該請(qǐng)求的處理器 (Handler),同時(shí)包括若干個(gè)對(duì)該請(qǐng)求實(shí)施攔截的攔截器(HandlerInterceptor)森缠。當(dāng) HandlerMapping 返回 HandlerExecutionChain 后拔鹰,DispatcherServlet 將請(qǐng)求交給定義在 HandlerExecutionChain中的攔截器和處理器一并處理。
位于處理器鏈末端的是一個(gè) Handler贵涵,DispatcherServlet通過 Handler Adapter適配器對(duì) Handler進(jìn)行封裝列肢,并按統(tǒng)一的適配器接口對(duì) Handler處理方法進(jìn)行調(diào)用”雒可以在
web-servlet.xml
中配置多個(gè)攔截器,每個(gè)攔截器都可以指定一個(gè)匹配的映射路徑瓷马,以限制攔截器的作用范圍。
10 異常處理
Spring MVC通過 HandlerExceptionResolver處理程序的異常跨晴,包括處理器映射欧聘、數(shù)據(jù)綁定及處理器執(zhí)行時(shí)發(fā)生的異常。 HandlerExceptionResolver僅有一個(gè)接口方法:Modelandview resolveException(HttpServletRequest request HttpServletResponse response Object handler, Exception ex)
坟奥。當(dāng)發(fā)生異常時(shí)树瞭,Spring MVC將調(diào)用 resolveException方法,并轉(zhuǎn)到 ModelAndView 對(duì)應(yīng)的視圖中爱谁,作為一個(gè)異常報(bào)告頁面反饋給用戶。
實(shí)現(xiàn)類
HandlerExceptionResolver擁有4個(gè)實(shí)現(xiàn)類
- DefaultHandlerExceptionResolver:默認(rèn)裝配了該類孝偎,將對(duì)應(yīng)異常轉(zhuǎn)換為錯(cuò)誤碼
- SimpleMappingExceptionResolver:對(duì)所有異常進(jìn)行統(tǒng)一處理
- AnnotationMethodHandlerExceptionResolver:默認(rèn)注冊(cè)了該類访敌,允許通過@ExceptionHandler注解指定處理特定的異常
- ResponseStatusExceptionResolver