Spring Web MVC

Spring Web MVC

Spring Web MVC is the original web framework built on the Servlet API and included in the Spring Framework from the very beginning. The formal name "Spring Web MVC" comes from the name of its source module spring-webmvc but it is more commonly known as " Spring MVC".
Parallel to Spring Web MVC, Spring Framework 5.0 introduced a reactive stack, web framework whose name Spring WebFlux is also based on its source module spring-webflux. This section covers Spring Web MVC. The next section covers Spring WebFlux.
For baseline information and compatibility with Servlet container and Java EE version ranges please visit the Spring Framework Wiki.

Spring MVC入門

入門教程能夠參考: https://course.tianmaying.com/spring-mvc

Spring MVC是什麼

Spring Web MVC(下文簡稱Spring MVC)和Struts2都屬於表現層的框架,它 是Spring框架的一部分,咱們能夠從Spring的總體結構中看得出來,以下圖:

Spring MVC處理一次請求到響應的流程

快速入門

基本步驟

  1. 建立項目
  2. 導入jar包
  3. 建立springmvc.xml文件並配置Controller掃描
  4. 在web.xml文件中配置前端控制器
  5. 建立jsp文件用於測試
  6. 建立POJO
  7. 建立Controller類
  8. 進行測試
步驟詳見附件
建立springmvc.xml文件並配置Controller掃描
SpringMVC自己就是Spring的子項目,對Spring兼容性很好,不須要作不少配置, 這裏只配置一個Controller掃描,讓Spring對頁面控制層Controller進行管理
在web.xml文件中配置前端控制器
建立POJO
加入jsp頁面
將jsp頁面放置到WEB-INF/jsp文件夾下
建立Controller
根據jsp頁面編寫Controller類
  • Controller是一個普通的java類,不須要實現任何接口
  • 須要在類上添加@Controller註解,把Controller交由Spring管理
  • 在方法上面添加@RequestMapping註解,裏面指定請求的url
    • 其中「.action」能夠加也能夠不加

Spring MVC的架構

框架結構

上圖中,前端控制器(紫色)僅須要配置,處理器映射器、處理器適配器和視圖解析器(灰色)是固有的組件,須要咱們編碼的僅有處理器和視圖(橙色)

架構處理請求的流程

  1. 用戶發送請求至前端控制器DispatcherServlet
  2. DispatcherServlet收到請求調用HandlerMapping處理器映射器
  3. 處理器映射器根據請求url在Spring容器中(經過RequestMapping註解內容)尋找對應的處理器Controller(也叫後端控制器),若找到,爲其生成處理器對象及處理器攔截器(若是有則生成)一併返回給DispatcherServlet
  4. DispatcherServlet經過HandlerAdapter處理器適配器調用處理器
  5. 執行處理器
  6. Controller執行完成返回ModelAndView
  7. HandlerAdapter將Controller執行結果ModelAndView返回給DispatcherServlet
  8. DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
  9. ViewReslover解析後返回具體View
  10. DispatcherServlet對View進行渲染視圖(即將模型數據填充至視圖中)
  11. DispatcherServlet響應用戶
組件詳細說明
如下組件一般使用框架提供實現:
DispatcherServlet:前端控制器
用戶請求到達前端控制器,它就至關於mvc模式中的c,DispatcherServlet是整個流程控制的中心,由它調用其它組件處理用戶的請求,DispatcherServlet的存在下降了組件之間的耦合性
HandlerMapping:處理器映射器
HandlerMapping負責根據用戶請求url找到Handler即處理器,springmvc提供了不一樣的映射器實現不一樣的映射方式,例如:配置文件方式,實現接口方式,註解方式等
Handler:處理器
Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的用戶請求進行處理
因爲Handler涉及到具體的用戶業務請求,因此通常狀況須要程序員根據業務需求開發Handler
HandlerAdapter:處理器適配器
經過HandlerAdapter對處理器進行執行,這是適配器模式的應用,經過擴展適配器能夠對更多類型的處理器進行執行
下圖是許多不一樣的適配器,最終均可以使用usb接口鏈接
ViewResolver:視圖解析器
View Resolver負責將處理結果生成View視圖,View Resolver首先根據邏輯視圖名解析成物理視圖名即具體的頁面地址,再生成View視圖對象,最後對View進行渲染將處理結果經過頁面展現給用戶
View:視圖
Spring MVC框架提供了不少的View視圖類型的支持,包括:jstlView、freemarkerView、pdfView等,咱們最經常使用的視圖就是jsp
通常狀況下須要經過頁面標籤或頁面模版技術將模型數據經過頁面展現給用戶,須要由程序員根據業務需求開發具體的頁面
說明:在Spring MVC的各個組件中, 處理器映射器 處理器適配器 視圖解析器稱爲 Spring MVC的三大組件。
須要用戶開發的組件有 HandlerView

默認加載的組件

框架默認加載的組件配置文件位置以下
默認加載的組件已通過時,應該配置推薦使用的組件,見下文配置

組件掃描器

使用組件掃描器能夠省去手動一一配置Controller類的繁複操做

註解式處理器映射器

註解式處理器映射器,會對類中標記了@ResquestMapping註解的方法進行映射。根據@ResquestMapping定義的url匹配@ResquestMapping標記的方法,匹配成功後返回HandlerMethod對象到前端控制器
HandlerMethod對象內部封裝了url對應的方法Method
配置
從spring3.1版本開始,廢除了DefaultAnnotationHandlerMapping的使用,推薦使用RequestMappingHandlerMapping完成註解式處理器映射
在springmvc.xml配置文件中配置以下

註解式處理器適配器

註解式處理器適配器,將對標記了@ResquestMapping註解的方法進行適配
配置
從spring3.1版本開始,廢除了AnnotationMethodHandlerAdapter的使用,推薦使用RequestMappingHandlerAdapter完成註解式處理器適配
在springmvc.xml配置文件中配置以下

註解驅動

直接配置處理器映射器和處理器適配器比較麻煩,可使用註解驅動來加載
SpringMVC使用<mvc:annotation-driven>自動加載RequestMappingHandlerMapping和RequestMappingHandlerAdapter
能夠在springmvc.xml配置文件中使用<mvc:annotation-driven>替代註解處理器和適配器的配置

視圖解析器

能夠理解爲路徑解析器
視圖解析器使用SpringMVC框架默認的InternalResourceViewResolver, 這個視圖解析器支持Jsp視圖解析
在springmvc.xml配置文件中配置以下
邏輯視圖名須要在controller中返回ModelAndView指定,好比邏輯視圖名爲ItemList,則最終返回的jsp視圖地址爲:/ WEB-INF/jsp/itemList.jsp
最終jsp物理地址:前綴 +  邏輯視圖名 + 後綴
Controller配合上述配置使用
此後編寫路徑時就不須要寫全稱了

Spring MVC整合MyBatis

目標:控制層使用Spring MVC,持久層使用MyBatis實現
詳細見附件

基本步驟

  1. 導入依賴
  2. 加入配置文件
  3. 根據數據庫表生成/編寫POJO和映射文件並引入
  4. 測試
配置文件整合思路
Dao層
  • SqlMapConfig.xml,空文件便可,可是須要文件頭
  • applicationContext-dao.xml
    • 數據庫鏈接池
    • SqlSessionFactory對象,須要Spring和MyBatis整合包下的
    • 配置mapper文件掃描器
Service層
  • applicationContext-service.xml包掃描器,掃描@service註解的類
  • applicationContext-trans.xml配置事務
Controller層
  • springmvc.xml
    • 包掃描器,掃描@Controller註解的類
    • 配置註解驅動
    • 配置視圖解析器
Web.xml文件
  • 配置Spring
  • 配置前端控制器
配置文件彙總
  • sqlMapConfig.xml
  • applicationContext-dao.xml
  • db.properties
  • applicationContext-service.xml
  • applicationContext-trans.xml
  • springmvc.xml
  • web.xml

參數綁定

若Controller須要接收參數,則涉及到Spring MVC的參數綁定
Struts2的Action類是單例的,能夠直接用屬性來接收請求參數,而Spring MVC的Controller不是單例的,就不能夠用屬性來接收請求參數了
Spring MVC的Controller綁定參數的方法是 在Controller類中對應方法添加一個形式參數,Spring MVC會將請求參數傳遞給對應方法

Spring MVC默認支持的參數類型

  • HttpServletRequest:經過request對象獲取請求信息
  • HttpServlcetResponse:經過response處理響應信息
  • HttpSession:經過session對象獲得session中存放的對象

經過這種方式也能夠獲取請求參數並封裝響應信息傳遞到前臺,但不建議使用

Model/ModelMap

Model
除了ModelAndView之外,還可使用Model來向頁面傳遞數據, Model是一個接口,在參數裏直接聲明model便可
若是使用Model則能夠不使用ModelAndView對象,Model對象能夠向頁面傳遞數據,View對象則可使用String返回值替代
不論是Model仍是ModelAndView,其 本質都是使用Request對象向jsp傳遞數據
ModelMap
ModelMap是Model接口的實現類,也能夠經過ModelMap向頁面傳遞數據
使用Model和ModelMap的效果同樣,若是直接使用Model,Spring MVC會實例化ModelMap
也可使用返回String的方式來設定視圖

綁定簡單類型

當請求的參數名稱和處理器形參 名稱一致時會將請求參數與形參進行綁定
參數綁定支持的簡單類型
  • 整形:Integer、int
  • 字符串:String
  • 單精度:Float、float
  • 雙精度:Double、double
  • 布爾型:Boolean、boolean
    • 對於布爾類型的參數,請求的參數值爲true/false或者1/0
    • 如:url爲http://localhost:8080/xxx.action?id=2&status=false,處理器方法爲public String editItem(Model model,Integer id,Boolean status) 
@RequestParam註解
@RequestParam註解經常使用於處理簡單類型的綁定
其用法以下:
  • value:參數名字,即入參的請求參數名字
    • 如value=「itemId」表示請求的參數區中的名字爲itemId的參數的值將傳入
  • required:是否必須,默認是true,表示請求中必定要有相應的參數,不然將報錯
  • defaultValue:默認值,表示若是請求中沒有同名參數時的默認值
示例:

綁定POJO

若是請求參數較多,或提交的表單中內容不少時,可使用簡單類型接收數據,但更推薦使用POJO對象接收數據
使用方法:
POJO類中的屬性應該與input內name屬性一致
如圖

解決修改post提交數據亂碼問題

須要在web.xml文件中添加Spring的編碼過濾器相關配置
另外,對於get請求中文參數出現亂碼的解決方法有兩個
綁定包裝POJO
使用包裝POJO接收參數
建立包裝POJO類,修改前臺頁面,input的name屬性應該加上被包裝的POJO名稱前綴,以下

自定義參數綁定

Spring MVC提供數據類型自定義轉換功能,能夠經過手動編寫轉換器轉換規則來轉換前臺傳入的數據類型,如:字符串按必定規則轉換成日期
需求
在商品修改頁面能夠修改商品的生產日期,而且根據業務需求自定義日期格式。
需求分析
因爲日期數據有不少種格式,Spring MVC沒辦法把字符串轉換成日期類型,因此須要自定義參數綁定
前端控制器接收到請求後,找到註解形式的處理器適配器,對RequestMapping標記的方法進行適配,並對方法中的形參進行參數綁定
能夠在Spring MVC處理器適配器上自定義轉換器Converter進行參數綁定
通常使用<mvc:annotation-driven/>註解驅動加載處理器適配器,能夠在此標籤上進行配置
在set標籤內能夠配置多個Converter
Converter代碼以下

Spring MVC與Struts2的對比

  • Spring MVC的入口是一個servlet即前端控制器,而struts2入口是一個filter過濾器
  • Spring MVC基於方法開發(一個url對應一個方法),請求參數傳遞到方法的形參,能夠設計爲單例或多例(建議單例),Struts2是基於類開發,傳遞參數是經過類的屬性,只能設計爲多例
  • Struts2採用值棧存儲請求和響應的數據,經過OGNL存取數據Spring MVC經過參數解析器是將request請求內容解析,並給方法形參賦值,將數據和視圖封裝成ModelAndView對象,最後又將ModelAndView中的模型數據經過request域傳輸到頁面(Jsp視圖解析器默認使用jstl)

Spring MVC進階

高級參數綁定

綁定數組

能夠在Controller的方法中添加String[]類型的形參,也可使用POJO的String[]類型屬性接收數組類型的請求參數
以下
綁定List
請求參數能夠是存放多個POJO的List對象,經過在QueryVo中增長List<*>類型的屬性能夠接收List類型的參數
要求:jsp頁面中input標籤的name屬性應該爲List類型的屬性名稱 + 下標 + 元素屬性
以下
實際前端HTML頁面代碼應該以下
注意
List類型不能直接由Controller中方法的形參接收,必須由POJO來間接接收List類型的參數
*關於foreach遍歷標籤
  • ${current}:當前此次迭代的(集合中的)項
  • ${status.first}判斷當前項是否爲集合中的第一項,返回值爲true或false
  • ${status.last}判斷當前項是否爲集合中的最後一項
  • varStatus屬性經常使用參數總結下:
    • ${status.index}輸出行號,從0開始。
    • ${status.count}輸出行號,從1開始。
    • ${status.next}後一項,返回值爲true或false
    • begin、end、step分別表示:起始序號,結束序號,步長

@RequestMapping註解

經過@RequestMapping註解能夠定義不一樣的處理器映射規則
又如下的功能

設置URL路徑映射

用法:
  • 設置單個路徑映射
    • @RequestMapping(value="/item")
      • 或當僅須要配置value屬性時,能夠省略value=:@RequestMapping("/item")
  • value值的類型是數組,能夠將多個URL映射到同一個方法中
    • @RequestMapping(value = { "itemList", "itemListAll" })

設置通用請求前綴

在class類名前添加@RequestMapping(url)指定通用請求前綴,能夠限制此類下的全部方法請求url必須以請求前綴開頭
可使用此方法來對URL進行分類管理
以下
此後訪問這個Controller的特定方法的URL應該如:*/item/itemList.action

設置限定的請求方法

能夠限定請求進入這個Controller的方法(post/get)
使用RequestMethod屬性配置特定請求可入
其類型也是一個數組
  • 限定GET方法@RequestMapping(method = RequestMethod.GET)
    • 若是經過POST訪問則報錯:HTTP Status 405 - Request method 'POST' not supported
  • 限定POST方法:@RequestMapping(method = RequestMethod.POST)
    • 若是經過GET訪問則報錯:HTTP Status 405 - Request method 'GET' not supported
  • GET和POST都可:@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})
  • DELETE等等其餘方法(國內少用)

Controller中方法的返回值

Controller中方法的返回值有如下幾種
  • 返回ModelAndView
  • 返回void
  • 返回String

返回ModelAndView

Controller中方法中定義ModelAndView對象並返回,對象中可添加model數據,指定view視圖
不推薦使用這種方式

返回void

在Controller方法形參上能夠定義request和response,使用request或response指定響應結果來處理、控制請求,相似servlet開發
這種方式適合處理ajax的請求,由於處理ajax請求只須要返回(響應)數據,不須要返回視圖,直接使用response對象返回json數據便可

返回String

攜帶數據
使用Model對象來攜帶數據傳遞
邏輯視圖名
Controller方法返回字符串能夠 指定邏輯視圖名經過視圖解析器解析爲物理視圖地址
Redirect重定向
Contrller方法返回字符串能夠重定向到一個url地址
用法:在返回的字符串前加上 redirect: 字段
如:return "redirect:/itemEdit.action";
若帶參數重定向:return "redirect:/itemEdit.action?itemId=" + item.getId();
Forward轉發
某個Controller方法執行後繼續執行另外一個Controller方法
用法:相似重定向,加上 forward: 字段
如:return "forward: /itemEdit.action";
官方推薦使用返回String的方式開發Controller,這種方式能夠將數據和視圖分離、解耦,符合MVC架構的思想

異常處理器

Spring MVC在處理請求過程當中出現異常信息將交由 異常處理器進行處理, 自定義異常處理器能夠編寫代碼實現系統的異常處理邏輯

異常處理思路

系統中異常包括兩類:預期異常和運行時異常RuntimeException,前者經過捕獲異常從而獲取異常信息,後者主要經過規範代碼開發、測試經過手段減小運行時異常的發生
系統的Dao、Service、Controller出現都經過throws Exception向上拋出,最後由Spring MVC前端控制器交由異常處理器進行異常處理,以下圖

自定義異常類

爲了區別不一樣的異常,一般根據異常類型進行區分,能夠自定義一個異常類

自定義異常處理器

能夠自定義一個異常處理器按照編寫的邏輯處理接收到的異常
異常處理器要實現HandlerExceptionResolver接口,並重寫resolveException方法
其中resolveException方法的參數意義以下
  • HttpServletRequest request:當前請求對象
  • HttpServletResponse response:當前響應對象
  • Object obj:發生異常的位置所在(異常發生在哪一個類)
  • Exception e:當前發生的異常對象

配置異常處理器

在springmvc.xml文件配置

引入錯誤頁面

Spring MVC異常處理基本開發思路

Spring MVC已經提供好了HandlerExceptionResolver接口供開發者實現,要處理異常:
  1. 首先編寫自定義異常處理器,實現HandlerExceptionResolver接口
    1. 異常處理器內部編寫異常處理邏輯
    2. 定義發生異常時轉發到什麼頁面
  2. 配置異常處理器到Spring容器中
  3. 引入錯誤頁面並配置發生異常時轉發

上傳圖片

上傳圖片的功能其實就是接收圖片/文件請求參數

上傳圖片的步驟

在Tomcat上配置虛擬目錄
在Tomcat下conf/server.xml中添加<Context docBase="D:\develop\upload\temp" path="/pic" reloadable="false"/>
在IDEA配置Tomcat的虛擬目錄以下圖
訪問對應地址(加上具體資源名稱和後綴)便可訪問本地目錄下的圖片

這步的目的是爲了讓前臺頁面經過上述設置的虛擬目錄訪問到這個圖片( 毋需經過本地目錄訪問圖片了
 
導入jar包依賴
  • commons-fileupload-1.2.2.jar
  • commons-io-2.4.jar
配置文件上傳解析器
在springmvc.xml中配置文件上傳解析器
文件上傳解析器配置的bean的id必須爲multipartResolver
修改jsp頁面
在jsp頁面中form標籤添加enctype屬性,值爲multipart/form-data
在Controller對應方法中添加圖片上傳邏輯
按照這個步驟開發的文件上傳功能能夠將上傳的文件(目錄)與發佈的war包分離,互相獨立不影響

JSON數據交互

@RequestBody註解

JSON  -->  Java對象
@RequestBody註解用於讀取HTTP 請求的內容(字符串),而後能夠經過Spring MVC提供的 HttpMessageConverter接口將讀到的內容(json數據)轉換爲Java對象並綁定到Controller方法的參數上

@ResponseBody

Java對象 --> JSON
@ResponseBody註解用於Controller中的方法返回的對象,能夠經過Spring MVC提供的HttpMessageConverter接口轉換爲指定格式的數據如:json,xml等,經過Response響應給客戶端

實現JSON數據交互的步驟

引入依賴的jar包
Gson/Jackson/FastJson/等等
此處使用Jackson
編寫Controller
安裝瀏覽器的測試工具
如Postman等
測試
*若不使用註解驅動(annotation-driven)則須要手動配置JSON轉換器
若是不使用註解驅動<mvc:annotation-driven/>,就須要給處理器適配器配置json轉換器, 參考以前學習的自定義參數綁定

RESTful支持

RESTful簡介

RESTful就是一個 資源定位資源操做風格
RESTful不是標準也不是協議,只是一種風格。基於這個風格設計的軟件能夠更簡潔,更有層次,更易於實現緩存等機制
資源:互聯網全部的事物均可以被抽象爲資源
資源操做:使用:POST、DELETE、PUT、GET,使用不一樣方法對資源進行操做, 分別對應:添加、刪除、修改、查詢
經過請求method的不一樣來區分此次請求要怎樣操做資源

Spring MVC支持的RESTful

經過@RequestMapping註解能夠識別RESTful風格的請求
  • 其中{*}爲佔位符
  • 使用@PathVariable註解能夠獲取URL上的數據
  • 若是@RequestMapping中表示爲"item/{id}",id和形參名稱一致,@PathVariable不用指定名稱,若是不一致,例如"item/{ItemId}"則須要指定名稱@PathVariable("itemId")
  • @PathVariable是獲取url上數據的,而@RequestParam獲取請求參數的(包括post表單提交)
  • 若是加上@ResponseBody註解,就不會走視圖解析器,不會返回頁面,目前返回的json數據,若是不加,就走視圖解析器,返回頁面

攔截器

Spring Web MVC的處理器攔截器 相似於Servlet開發中的過濾器Filter過濾器,用於對處理器進行 預處理後處理

攔截器定義

攔截器內能夠定義三個方法,分別對應三個時間點
  • preHandle:執行Controller方法前
  • postHandle:執行Controller方法後
  • afterCompletion:頁面渲染後
攔截器須要實現HandlerInterceptor接口

攔截器配置

在spirngmvc.xml中配置攔截器

測試

多個攔截器的攔截規則

詳見附件
配置兩個攔截器HandlerInterceptor1和HandlerInterceptor2
正常運行流程
中斷運行流程
HandlerInterceptor1的preHandler方法返回false,HandlerInterceptor2返回true,運行流程以下:
HandlerInterceptor1..preHandle..
從日誌看出第一個攔截器的preHandler方法返回false後第一個攔截器只執行了preHandler方法,其它兩個方法沒有執行,第二個攔截器的全部方法不執行,且Controller也不執行了
HandlerInterceptor1的preHandler方法返回true,HandlerInterceptor2返回false,運行流程以下:
HandlerInterceptor1..preHandle..
HandlerInterceptor2..preHandle..
HandlerInterceptor1..afterCompletion..
從日誌看出第二個攔截器的preHandler方法返回false後第一個攔截器的postHandler沒有執行,第二個攔截器的postHandler和afterCompletion沒有執行,且 Controller也不執行了
結論
  • preHandle按攔截器配置順序調用
  • postHandle按攔截器配置逆序調用
  • afterCompletion按攔截器定義逆序調用
  • postHandler在攔截器鏈內全部攔截器返true成功才調用
  • afterCompletion只有同一個攔截器定義的preHandle返回true才調用
preHandle和postHandle相似俄羅斯套娃

攔截器應用示例

需求
  1. 有一個登陸頁面,須要寫一個Controller訪問登陸頁面
  2. 登陸頁面有一提交表單的動做。須要在Controller中處理。
    1. 判斷用戶名密碼是否正確(在控制檯打印)
    2. 若是正確,向session中寫入用戶信息(寫入用戶名username)
    3. 跳轉到商品列表
  3. 攔截器。
    1. 攔截用戶請求,判斷用戶是否登陸(登陸請求不能攔截)
    2. 若是用戶已經登陸則放行
    3. 若是用戶未登陸,跳轉到登陸頁面
詳細開發細節見附件
細節
只攔截訪問商品的URL請求,修改ItemController,讓全部的請求都必須以item開頭
配置攔截器時使用如下方式攔截對/item/開頭的URL的請求

附件列表

相關文章
相關標籤/搜索