Spring MVC

Spring MVC一、什么是 Spring MVC
Spring MVC 屬于 SpringFrameWork 的后續產品,已經融合在 Spring Web Flow 里面,是一個強大靈活的 Web 框架。Spring MVC 提供了一個 DispatcherServlet 作為前端控制器來分配請求。通過策略接口,Spring 框架是高度可配置的。Spring MVC 還包含多種視圖技術,如 Java Server Pages(JSP)、Velocity、Tiles、iText 和 POI 等。Spring MVC 分離了控制器、模型對象、分派器以及處理程序對象的角色,這種分離讓它們更容易進行定制。
Spring MVC 框架主要由 DispatcherServlet、處理器映射器、處理器適配器、處理器(控制器)、視圖解析器、視圖組成。
二.Spring MVC 相較于S2SH框架的優勢1、配置簡化
Spring MVC引入Schema Based XML,在其默認必要配置之后,可以靈活的進行2次配置,2次配置的內容大大減少。
2、MVC設計思想的領先
在Spring MVC中,model這層被抽象的更加靈活,他以方法輸入參數為表現形式,具體的行為靈活多樣,可以是基本類型,可以是POJO,也可以是request衍生出的各種對象。與之相比,struts2的model定義為controller的一個屬性,導致模型層與控制層之間的關系模糊不清。
3、對REST的支持性
Spring MVC對REST架構的支持是比較好的的MVC框架,與之相比strtus2雖然也提供了相關插件實現,但是相對于Spring MVC來可以說不是很高級,這是由于Struts2對于請求映射設計的天生缺陷導致。Struts2對于請求的映射最終以一個叫做ActionMapping的類來表述,而構造這個ActionMapping的實現卻只是一個非常簡單的接口ActionMapper。這個類天然就沒有考慮到許多Restful的需求。
相對于Spring MVC來說,struts2的最基本的問題是響應變化太慢,特別是對Java標準響應太慢。
比如:直到最近 2.3.1 才支持 JSR330,而Spring 已經支持兩年多了。目前還不支持JSR 303,雖然有第三方,但不是Out of box的,Spring MVC支持得很好。

三.淺析Spring MVC的工作原理及其與Spring的關系
Spring MVC屬于SpringFrameWork的后續產品,已經融合在Spring Web Flow里面。Spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構,從而在使用Spring進行WEB開發時,可以選擇使用Spring的SpringMVC框架或集成其他MVC開發框架,如Struts1,Struts2等。
Spring MVC的整個工作過程是從一個HTTP請求開始:
1)DispatcherServlet接收到請求后,根據對應配置文件中配置的處理器映射,找到對應的處理器映射項(HandlerMapping),根據配置的映射規則,找到對應的處理器(Handler)。
2)調用相應處理器中的處理方法,處理該請求,處理器處理結束后會將一個ModelAndView類型的數據傳給DispatcherServlet,這其中包含了處理結果的視圖和視圖中要使用的數據。
3)DispatcherServlet根據得到的ModelAndView中的視圖對象,找到一個合適的ViewResolver(視圖解析器),根據視圖解析器的配置,DispatcherServlet將視圖要顯示的數據傳給對應的視圖,最后給瀏覽器構造一個HTTP響應。 DispatcherServlet是整個Spring MVC的核心。


image.png

DispatcherServlet負責接收HTTP請求組織協調Spring MVC的各個組成部分。其主要工作有以下三項:
1)截獲符合特定格式的URL請求。
2)初始化DispatcherServlet上下文對應的WebApplicationContext,并將其與業務層、持久化層的WebApplicationContext建立關聯。
3)初始化Spring MVC的各個組成組件,并裝配到DispatcherServlet中。
然后簡單說一下Spring MVC與Spring的關系。Spring可以說是一個管理bean的容器,也可以說是包括很多開源項目的總稱,而Spring MVC是其中一個開源項目。如果簡單進行一個流程,當http請求一到,由容器(如:Tomcat)解析http形成一個request,通過映射關系(比如路徑,方法,參數)被Spring MVC一個分發器去找到可以處理這個請求的bean,在Tomcat里面就由Spring管理bean的一個池子(bean容器)里面找到。處理完了就把響應返回。
基于Spring實現的MVC框架是不能不使用Spring的。單獨使用Spring MVC,因為其需要依賴IOC容器。但是如果單獨為了更好的理解SpringMVC這種MVC框架,就把它和Struts2等一系列的MVC框架對比理解,理解其只是基于DispatcherServlet或者Filter做一個前端分發器,最終把這個框架引導起來,進行其自己的邏輯處理。
面試常考問題
四.Spring和Spring MVC的區別1.Spring的功能
Spring架構最核心的功能就是依賴注入。
所有Spring模塊的核心都是依賴注入。如果合理使用依賴注入,我們可以構建低耦合的應用,而且應用更容易進行單元測試。


image.png

減少重復代碼
Spring提供了很多模塊比如Spring JDBC,Spring MVC,Spring Test。這些功能可以自己實現,但是借助這些封裝的模塊就能減少代碼量,代碼越少bug就越少。
很好的集成其他框架
Spring架構從不解決已經被解決的問題,而且和這些解決問題的框架能夠很好的集成。比如Hibernate。
2.Spring MVC的功能
Spring MVC提供了一種輕度耦合的方式來開發web應用。
Spring MVC是Spring的一個模塊式一個web框架。通過Dispatcher Servlet, ModelAndView 和 View Resolver,開發web應用變得很容易。解決的問題領域是網站應用程序或者服務開發——URL路由、Session、模板引擎、靜態Web資源等等。
五.SpringMVC與struts2的區別
1、Struts2是類級別的攔截, 一個類對應一個request上下文,SpringMVC是方法級別的攔截,一個方法對應一個request上下文,而方法同時又跟一個url對應,所以說從架構本身上SpringMVC就容易實現restful url,而struts2的架構實現起來要費勁,因為Struts2中Action的一個方法可以對應一個url,而其類屬性卻被所有方法共享,這也就無法用注解或其他方式標識其所屬方法了。

2、由上邊原因,SpringMVC的方法之間基本上獨立的,獨享request response數據,請求數據通過參數獲取,處理結果通過ModelMap交回給框架,方法之間不共享變量,而Struts2搞的就比較亂,雖然方法之間也是獨立的,但其所有Action變量是共享的,這不會影響程序運行,卻給我們編碼 讀程序時帶來麻煩,每次來了請求就創建一個Action,一個Action對象對應一個request上下文。3、由于Struts2需要針對每個request進行封裝,把request,session等servlet生命周期的變量封裝成一個一個Map,供給每個Action使用,并保證線程安全,所以在原則上,是比較耗費內存的。

4、 攔截器實現機制上,Struts2有以自己的interceptor機制,SpringMVC用的是獨立的AOP方式,這樣導致Struts2的配置文件量還是比SpringMVC大。
5、SpringMVC的入口是servlet,而Struts2是filter(這里要指出,filter和servlet是不同的。以前認為filter是servlet的一種特殊),這就導致了二者的機制不同,這里就牽涉到servlet和filter的區別了。
6、SpringMVC集成了Ajax,使用非常方便,只需一個注解@ResponseBody就可以實現,然后直接返回響應文本即可,而Struts2攔截器集成了Ajax,在Action中處理時一般必須安裝插件或者自己寫代碼集成進去,使用起來也相對不方便。
7、SpringMVC驗證支持JSR303,處理起來相對更加靈活方便,而Struts2驗證比較繁瑣,感覺太煩亂。
8、Spring MVC和Spring是無縫的。從這個項目的管理和安全上也比Struts2高(當然Struts2也可以通過不同的目錄結構和相關配置做到SpringMVC一樣的效果,但是需要xml配置的地方不少)。
9、 設計思想上,Struts2更加符合OOP的編程思想, SpringMVC就比較謹慎,在servlet上擴展。
10、SpringMVC開發效率和性能高于Struts2。
11、SpringMVC可以認為已經100%零配置。
五、Spring MVC 執行流程
Spring MVC 高層次的請求處理工作流程如下(圖來自 Spring 官網):


image.png

細分后,Spring MVC 執行流程如下,共包括八步:
1.Spring MVC 相關接口解釋:
(1)DispatcherServlet
前端控制器,所有的請求都有經過它來統一分發,請求會被分發給對應的 Handler。
(2)HandlerMapping(處理器映射器)
解析請求鏈接,然后根據請求鏈接找到執行這個請求的類(HandlerMapping 所說的 handler)。
(3)HandlerAdapter(處理器適配器)
調用具體的方法對用戶發來的請求來進行處理。
(4)Controller
Controller 將處理用戶請求,Controller 處理完用戶請求,則返回 ModelAndView 對象給 DispatcherServlet 前端控制器。
從宏觀角度考慮,DispatcherServlet 是整個 Web 應用的控制器;從微觀考慮,Controller 是單個 Http 請求處理過程中的控制器。
(5)ViewResolver(視圖解析器)
解析 MdoelAndView,將 MdoelAndView 中的邏輯視圖名變為一個真正的 View 對象,并將 MdoelAndView 中的 Model 取出。

2、注解驅動的控制器2.1、使用@RequestMapping映射請求
* 通過請求URL進行映射
@RequestMapping("/user/register")

@RequestMpping不但支持標準的URL,還支持Ant風格(即?、和的字符)的和帶{xxx}占位符的URL,可以通過@ParhVariable將URL中的占位符參數綁定到控制器處理方法的入參中。
* 通過請求參數、請求方法或請求頭進行映射
@RequestMapping(value="/delete", method=RequestMethod.POST, params="userId", headers="content-type=text/
")

2.2、請求處理方法簽名
* 使用@RequestParam綁定請求參數值
public String handle(@RequestParam(value="userName", required=false))
* 使用@CookieValue綁定請求中的Cookie值
public String handle(@CookieValue(value="sessionId", required=false))
* 使用@RequestHeader綁定請求報文頭的屬性值
public String handle(@RequestHeader("Accept-Encoding") String encoding, @RequestHeader("Keep-Alive")long keepAlive)
* 使用命令/表單對象綁定請求參數值
/handle.html?userName=tom&userAge=12
Public String handle(User user)
* 使用Servlet API對象作為入參
public void handle(HttpServletRequest req, HttpServletResponse resp)
* 使用Spring MVC自定義的可代理Servlet原生API類的接口
public String handle(WebRequest req)
* 使用IO對象作為入參
Spring MVC可以獲取ServletRequest的InputStream/Reader或者ServletRespons的OutputStream/Writer,然后傳給控制器的處理方法
public void handle(OutputStream os)

2.3、使用HttpMessageConverter<T>
* HttpMessageConverter<T>是Spring 3.0新添加的一個重要的接口,它負責將請求信息轉換為一個對象(類型為T),將對象(類型為T)輸出為響應信息。
* 如果在Spring web容器中顯式定義了一個AnnotationMethodHandlerAdapter,則Spring MVC將使用它覆蓋默認的AnnotationMethodHandlerAdapter。
* 使用途徑:
1、使用@RequestBody/@ResponseBody對處理方法進行標注;
2、使用@HttpEntity<T>/ResponsEntity<T>作為處理方法的入參或者返回值;

2.4、處理模型數據
Spring MVC提供了多種途徑將模型數據暴露給視圖

* ModelAndView:處理方法返回值類型為ModelAndView時,方法體即可通過該對象添加模型數據;
* @ModelAttribute:方法入參標注該注解后,入參的對象就會放到數據模型中;
* Map 及 Model:入參為org.springframework.ui.Model、org.springframework.ui.ModelMap或java.util.Map時,處理方法返回時,Map中的數據會自動添加到模型中;
* @SessionAttributes:將模型中的某個屬性暫存到HttpSession中,以便多個請求之間共享這個屬性;

控制器方法返回字符串類型的值會被當成邏輯視圖名處理。當字符串帶"forward"或"redirect"前綴時,redirect會讓瀏覽器發起一個新的請求,而forward所到的目標地址位于當前請求中。

3、處理方法的數據綁定
Spring MVC會根據請求方法簽名的不同,將請求消息中的消息以一定的方式轉換并綁定到請求方法的入參中。在請求消息到達真正調用處理方法的這一段時間內,Spring MVC還完成了很多工作,包括數據轉換、數據格式化及數據校驗等。
3.1、數據轉換
//自定義轉換器 <userName>:<password>:<realName> -> UserObject
public class StringToUserConverter implements Converter<String, User >{...}
//將StringToUserConverter安裝到Spring上下文中
<beans ...>
<mvc:annotation-drever conversion-service="conversionService">
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactorybean">
<property name="converters"><list>
<bean class="...StringToUserConverter"/>
</list></property>
</bean>
</beans>
//使用StringToUserConverter
@ReqquestMapping(value="")
public String handle(@RequestParam("user") User user)
//url
xxx.html?user=tom:1234:jacktion

3.2、數據格式化
//將FormattingConversionServiceFactoryBean安裝到Spring上下文中
org.springframework.format.support.FormattingConversionServiceFactoryBean
//使用注解驅動格式化功能
@DateTimeFormat(pattern="yyyy-MM-dd")
private Date birthday;
Spring 提供了注解驅動的屬性對象格式化功能:在Bean屬性設置、Spring MVC處理方法入參數據綁定、模型數據輸出時自動通過注解應用格式化的功能。

3.3、數據校驗
JSR 303是Java為Bean數據合法性校驗所提供的標準框架,它已經包含在Java EE6.0中。

  • Spring校驗框架 LocalValidatorFactoryBean即實現了Spring的Validator接口,也實現了JSR303的Validator接口。
  • Spring MVC數據校驗,在表單/命令對象標注JSR303注解
    @Pattern(regexp="");//正則表達式
    private String userName;
    @Length(min=2, max=100)//字符串長度
    @DecimalMin //數值最小值
  • 校驗結果保存,前一個表單/命令對象的校驗結果保存在其后的入參中,這個校驗結果的入參必須是一個BindingResult和Errors類型
    public String handle(@Valid @ModelAtterbute("user") User user, BindingResult bindingResult, @Valid Dept dept, Errors depErrors)
    {if(bindingResult.hasError()) return ...}
  • 頁面顯示錯誤
    Spring MVC除了會將表單/命令對象的校驗結果保存在對應的BindingResult或Errors中,還會將所有校驗結果保存到“隱含模型”中。
    <form:errors path="*"/> //顯示表單對象所有的錯誤信息
    <form:errors path="userName" cssClass="errorClass"/> //顯示userName屬性的錯誤

4、視圖和視圖解析器
請求方法執行完以后,最中返回一個ModelAndView對象,對于那些返回String、View或ModelMap等類型的處理方法,Spring MVC也會在內部將他們裝配成一個ModelAndView對象,它包含了視圖邏輯名和模型對象的信息。可以通過orderNo屬性指定解析器的優先順序,orderNo值越小優先級越高。
4.1、視圖解析器
視圖解析器工作內涵:根據邏輯視圖名和本地化對象得到一個視圖對象。
4.2、JSP和JSTL
jsp是最常見的視圖技術,使用InternalResourceViewResolver作為視圖解析器。
4.3、 模板視圖

Spring Web上下文裝配FreeMarker的基礎設施和FreeMark視圖解析器:
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">

4.4、Excel
擴展Spring的AbstractExcelView 或 AbstractJExcelView,使用BeanNameViewResolver視圖解析器。
4.5、PDF
擴展AbstractOdfView,使用BeanNameViewResolver視圖解析器。
4.6、輸出XML
使用MarshallingView視圖解析器,注入XStreamMarshaller,將模型數據轉化為XML。
4.7、 輸出JSON
Spring MVC的MappingJacksonJsonView借助Jackson框架的ObjectMapper將模型數據轉化為JSON格式輸出。
4.8、混合使用多種視圖技術
ContentNegotiatingViewResolver根據請求所要求的MIME類型決定由哪個視圖解析器負責解析,一般將其的優先級設置為最高。
5、本地化解析
* AcceptHeaderLocaleResolver:根據HTTP報文頭的Accept-Language參數確定本地化類型;
* CookieLocaleResolver:根據指定的Cookie值確定本地化類型;
* SessionLocaleResolver:根據Session中特定的屬性值確定本地化類型;
* LocaleChangeInterceptor:從請求參數中獲取本次請求對應的本地化類型;

6、文件上傳
Spring MVC通過Jakarta Commons FileUpload技術實現了一個Multipartresolver實現類:CommonsMultipartResolver。
7、雜項7.1、靜態資源處理
* 采用<mvc:default-servlet-handler/>將靜態資源的處理經由Spring MVC框架交回Web應用服務器處理;
* <mvc:resources mapping="" location=""/> 由Spring MVC框架自己處理靜態資源,并添加有用的附加值功能;

7.2、裝配攔截器
<mvc:interceptors></mvc:interceptors>
7.3、異常處理
Spring MVC通過HandlerExceptionResolver處理程序的異常,包括處理器映射、數據綁定以及處理器執行時的異常。

* DeaufaultHandlerExceptionResolver 會將Spring MVC框架的異常轉換為相應的相應狀態碼;
* AnnotationMethodHandlerExceptionResolver 允許通過@ExceptionHandler的注解指定處理特定異常的方法;
* SimpleMappingExceptionResolver 將異常類名映射為視圖名,即發生異常時使用對應的視圖報告異常;
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.Spring web mvc介紹 Spring web mvc和Struts2都屬于表現層的框架,它是Spri...
    七弦桐語閱讀 11,554評論 2 38
  • Spring mvc 框架 DispatcherServlet前端控制器 ---- 整個流程控制的中心,由它調用其...
    蕊er閱讀 720評論 0 0
  • 前言 對于Spring MVC項目搭建相信大家按照網上教程來做基本都會,但更多時候我們應該多問幾個為什么,多思考實...
    九風萍舟閱讀 2,782評論 0 12
  • 前言 Spring MVC框架是一個MVC框架,通過實現Model-View-Controller模式來很好地將數...
    niaoge2016閱讀 2,637評論 0 1
  • 1、Spring MVC請求流程 (1)初始化:(對DispatcherServlet和ContextLoderL...
    拾壹北閱讀 1,974評論 0 12