Spring MVC
1. Spring MVC 概述 1-2
1.1. 企業級應用基本架構 1-2
1.2. Web MVC架構及分析 1-3
1.3. Spring MVC 架構及分析 1-4
2. Spring MVC 程式設計基礎 2-5
2.1. 程式設計基本步驟 2-5
2.2. 基於xml程式設計實現 2-5
2.2.1. 建立Maven WEB 專案 2-5
2.2.2. 新增Spring MVC 專案依賴及配置檔案 2-5
2.2.3. 配置前端控制器 2-7
2.2.4. 建立後端控制器 2-7
2.2.5. 建立JSP頁面 2-8
2.2.6. 配置後端控制及檢視解析 2-8
2.2.7. 部署到tomcat執行 2-9
2.2.8. 執行原理分析 2-9
2.3. 基於註解程式設計實現 2-10
2.3.1. 建立Maven WEB 專案 2-10
2.3.2. 新增Spring MVC 專案依賴及配置檔案 2-10
2.3.3. 配置前端控制器 2-11
2.3.4. 建立後端控制器 2-12
2.3.5. 配置元件掃描與檢視解析 2-12
2.3.6. 部署與執行 2-12
3. Spring MVC 程式設計請求處理進階 3-13
3.1. 請求路徑對映 3-13
3.1.1. 普通url對映 3-13
3.1.2. Rest風格url對映 3-13
3.2. 請求方式對映 3-14
3.2.1. 請求方式限定 3-14
3.2.2. 請求方式組合 3-14
3.3. 請求引數對映(重點) 3-14
3.3.1. 標準Servlet API 3-14
3.3.2. 直接量儲存 3-15
3.3.3. Java bean物件 3-15
3.3.4. Rest url資料 3-16
3.3.5. 請求頭資料 3-16
4. Spring MVC 響應處理進階 4-17
4.1. 響應資料封裝 4-17
4.1.1. ModelAndView 物件 4-17
4.1.2. Model物件 4-17
4.1.3. Map物件 4-18
4.2. 響應資料轉換JSON 4-18
4.2.1. JSON 應用概述 4-18
4.2.2. 客戶端JSON資料操作 4-19
4.2.3. JAVA端JSON資料操作 4-19
4.2.4. Spring 整合jackson庫 4-23
4.2.5. Spring 整合fastjson庫 4-24
5. Spring 攔截器應用 5-25
5.1. 攔截器概述 5-25
5.2. 攔截器編寫及配置 5-26
6. Spring MVC異常處理 6-28
6.1. Spring MVC 異常概述 6-28
6.2. Spring MVC 異常處理 6-29
7. 總結 7-29
7.1. 重點和難點分析 7-29
7.2. 常見FAQ 7-30
7.3. 作業 7-30
1. Spring MVC 概述
1.1. 企業級應用基本架構
企業級應用基本架構(C/S)以及SPRING在架構中的作用。
此架構圖中spring要解決什麼問題?
1) 物件的構建,物件的依賴管理。(重點是從資源使用角度進行分析)
2) 擴充套件業務的動態切入。(基於OCP更好實現功能擴充套件,同時進行解耦)
3) 簡化傳統web mvc架構中的一些細節處理問題(引數獲取,校驗,值的注入,響應方式及資料格式的轉換)。
問題:
1)我們一般說的解耦是沒有耦合嗎?不是,所有軟體系統中的物件之間都會存在耦合,只是要把耦合降低。
2) 降低耦合的最主要目的是什麼?就是要提高系統的可維護性,便於系統進行更好的升級擴充套件。
3) 降低耦合的主要實現方式?
3.1)物件之間的耦合儘量耦合與介面與工廠
3.2)程式碼的重用盡量使用組合而非繼承。(has a 取代 is a)
1.2. Web MVC架構及分析
基於servlet,jsp,javabean技術實現的MVC架構
問題:
1) 假如我們沒有使用spring mvc,你如何對系統採用mvc思想進行分層?(參考jsp+servlet+javabean奇數)
2) 傳統的web mvc 程式設計架構中有什麼優勢,劣勢?
優勢:結構層次更加清晰,可讀性,可維護性相對較好
劣勢:引數獲取,型別轉換,流程呼叫相對都比較複雜
3)市場上相對比較成熟的mvc框架:spring mvc,struts2,….
1.3. Spring MVC 架構及分析
Spring MVC是MVC架構模式的一種完美實現,它簡化了Java WEB 中基於MVC架構的程式設計過程,是Spring中的WEB應用模組。其官方MVC概要架構圖如下:
Spring MVC 底層核心架構圖及工作流程(先了解,寫完專案案例再重點強化)
Spring MVC 中的核心元件:
1) DispatcherServlet (前端控制器, 處理請求的入口)
2) HandlerMapping (對映器物件, 用於管理url與對應controller的對映關係)
3) Controller (後端控制器, 負責處理請求的控制邏輯)
4) ModelAndView (模型, 封裝業務處理結果和檢視)
5) ViewResolver(檢視解析器,解析對應的檢視關係:字首+view+字尾)
備註:假如希望瞭解Spring MVC的詳細處理流程可以基於斷點除錯法進行跟蹤。
2. Spring MVC 程式設計基礎
2.1. 程式設計基本步驟
Step01:建立maven web 專案並解決專案中的錯誤問題
Step02:新增專案依賴(spring-webmvc)及spring核心配置檔案
Step03:配置前端控制器DispatcherServlet(web.xml)
Step04:建立後端控制器(Controller)及頁面
Step05:spring配置檔案中配置核心應用元件
Step06:部署及測試springmvc 應用。
2.2. 基於xml程式設計實現
2.2.1. 建立Maven WEB 專案
Web專案打包方式為war方式
Web專案的target runtimes為tomcat
Web 專案的編譯版本為JDK1.8
可能會遇到的問題:
1) war專案預設不會建立web.xml(需要自己生成)
2) 專案建立好需要設定執行時環境tomcat(多個tomcat時選哪個)
3) 統一編譯版本(版本不統一很有可能會出現專案不編譯)
4) 統一編碼(UTF-8)
5) 假如建立的專案還有問題,可對專案進行clean操作
2.2.2. 新增Spring MVC 專案依賴及配置檔案
開啟專案的pom.xml檔案,然後新增依賴(選擇組groupId為org.springframework)
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.9.RELEASE</version> </dependency> <dependencies>
假如新增好了依賴,都沒有找到對應的jar依賴,先檢測網路是否是通的.假如網路是通的,還沒有下載到具體的依賴,此時要右鍵專案,選擇maven/upate maven project/fore update…進行maven強制更新操作.
在專案的resource的目錄中新增核心配置檔案applicationContext.xml,例如:
<?xml version="1.0" encoding="UTF-8"?> <beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd" > </beans>
說明:配置檔案的名字需要自己定義,當這個空的配置檔案中的某行有相關錯誤
時,先去檢測網路是不是通的。
2.2.3. 配置前端控制器
開啟web.xml,配置DispatcherServlet物件
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
前端控制器是spring mvc處理請求的入口,是springmvc的核心,這個控制器一般需要在伺服器啟動時即初始化。
其中
1) load-on-startup 表示啟動時則載入此servlet
2) init-param 中的引數名不能變(此名字在DispatcherServlet父類中定義)
2.2.4. 建立後端控制器
後端控制器編寫時可以實現Controller介面,然後重寫handleRequest方法處理請求
public class HelloController implements Controller{}
其中:
ModelAndView物件為一個模型與檢視物件,內建一個map物件,主要用於封裝業務資料和檢視名。
ModelAndView構造方法中傳遞的為檢視名,addObject方法可以以key/value形式儲存資料。
ModelAndView 物件返回時會被spring mvc自動儲存到請求作用域,在對應的檢視頁面可以直接從此作用域獲取對應的值。
2.2.5. 建立JSP頁面
在專案的WEB-INF/pages資料夾下建立hello.jsp檔案,然後設定其內容,例如
2.2.6. 配置後端控制及檢視解析
在spring mvc 核心配置檔案中添如下配置。
<!-- 將Controller這個Bean物件交給Spring管理 --> <bean id="helloController" class="spring.controller.XmlHelloController"> </bean> <!-- 配置HandlerMapping 對映處理器配置url到具體的Controller之間的對映--> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello.do">helloController</prop> </props> </property> </bean> <!-- 配置檢視解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean>
2.2.7. 部署到tomcat執行
將專案部署到tomcat,然後啟動執行,在位址列輸入具體url訪問對應controller。
問題:
1) tomcat啟動時出現ClassNotFoundException,而這個class又不是我們自己的類,此時要重新maven update,重新發布(右鍵tomcat 重新publish),多次嘗試還是不可以,此時重啟eclipse。
2) 404異常,一般表示服務端資源沒找到,首先檢測訪問路徑是否正確,然後還可以在專案的部署目錄中去查詢對應的資源,必須確保資源是存在的,假如資源不存在,說明程式碼沒有正常編譯。(很常見)
3) 如何解決這種專案不編譯的問題?
step01) 將tomcat下的專案移除,clean你的tomcat伺服器
step02) 將專案的jre從buildpath移除,然後重新新增
step03) 對專案先進行maven clean操作(清除原先編譯結構,然後重新編譯)
step04) 再次對專案進行clean操作
step05) 重新部署專案,啟動tomcat執行
4) 執行專案時儘量不要右鍵執行選在run as /run on server
2.2.8. 執行原理分析
本應用的簡易處理流程如下:
4.2. 響應資料轉換JSON
4.2.1. JSON 應用概述
JSON(JavaScript Object Notation):一種輕量級資料交換格式,通常用於實現客戶端與服務端之間的資料傳輸.
企業級Java專案資料傳輸方式:
5. Spring 攔截器應用
5.1. 攔截器概述
攔截器是SpringMVC中的一個核心應用元件,主要用於處理多個Controller的共性問題.當我們的請求由DispatcherServlet派發到具體Controller之前首先要執行攔截器中一些相關方法,在這些方法中可以對請求進行相應預處理(例如許可權檢測,引數驗證),這些方法可以決定對這個請求進行攔截還是放行.通過spring mvc 架構圖分析,攔截器在Spring MVC中處理流程中的一個位置
回顧Spring MVC詳細架構圖
思考:假如對請求資料進行編碼,是應在過濾器還是攔截器?
5.2. 攔截器編寫及配置
攔截器如何編寫?
我們自己編寫Spring MVC攔截器需要實現HandlerInterceptor介面或者繼承此介面的實現類 HandlerInterceptorAdapter(繼承這個類時可根據需求重寫必要的方法)
public class SysUserInterceptor implements HandlerInterceptor { @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); return true;//表示放行 } @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandler" + ".modelAndView="+modelAndView); } @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion.handler="+ handler.getClass()); } }
這些方法的簡易執行流程點如下圖所示:
這些方法的詳細的執行時間點如下:
我們自己的攔截器編寫完成以後需要在spring配置檔案中進行配置,,
例如:
<mvc:interceptors> <mvc:interceptor> <!-- 指定攔截哪些請求路徑 --> <mvc:mapping path="/**"/> <!-- 排除要攔截的路徑 --> <mvc:exclude-mapping path="/sys/doLogin.do"/> <!-- 攔截器 --> <bean class="cn.spring.mvc.interceptor.SysUserInterceptor"/> </mvc:interceptor> </mvc:interceptors>
當我們系統中有多個攔截器時,這些攔截器可以構成一個攔截器鏈.其原理類似過濾器中的過濾鏈。在多個攔截器應用中僅當所有匹配的攔截器的preHandle()都執行之後,才會呼叫Controller中處理請求的方法,然後再執行所有匹配的攔截器的postHandler(),再執行所有匹配的攔截器的afterCompletion()。
在攔截器鏈中,各攔截器的執行先後順序取決於配置檔案中配置的節點的先後順序!
6. Spring MVC異常處理
6.1. Spring MVC 異常概述
實際專案中我們經常會採用分層架構設計程式,每一層都可能會有異常,假如異常資訊沒有處理,可能會選擇丟擲,假如這些被丟擲的異常與具體業務相關,那到控制層以後我們一般都進行相應的處理(處理方式應該相對友好)
在Spring mvc 專案中,邊界出現異常以後我們通常會在Controller中進行處理,常用分層架構中的異常分析:
在分層架構中,異常可能會從DAO層逐步丟擲到控制層,可以在控制層對異常進行相關處理。
6.2. Spring MVC 異常處理
在spring中處理異常時,通常會在Controller中定義具體的異常處理方法,這個方法上使用@HandlerException註解進行描述.例如在指定Controller中定義異常處理方法:
@ExceptionHandler(value=Exception.class) @ResponseBody public String handleException(Exception e){ System.out.println("區域性異常處理"); return e.getMessage(); }
當Spring的controller中沒有定義具體的異常方法,我們外部定義一個全域性的異常處理類,這個類使用@ControllerAdvice註解進行修飾.然後在這個類中定義具體的異常處理方法,這些方法再使用@HandlerExcpeiton進行修飾,例如
@ControllerAdvice public class AdviceExceptionHandler { @ExceptionHandler(Throwable.class) @ResponseBody public String handlerException(Throwable e){ System.out.println("全域性的異常處理"); return e.getMessage(); } }
1. Spring MVC 檔案上傳
1.1. 檔案上傳業務場景
在電子商務系統中對具體商品採用圖片方式進行描述,這個圖片需要上傳到伺服器等等。
1.2. Spring MVC 檔案上傳基本步驟
Step01: 新增檔案上傳相關依賴(jar包:commons-fileupload)
Step02: 配置對上傳檔案物件的解析(spring的核心配置檔案)
Step03: 編寫檔案上傳表單(請求方式為post,enctype必須為multipart/form-data)
Step04: 編寫對應的控制層物件處理檔案上傳(通過mutilpartFile引數接收檔案)
1.2.1. 新增依賴
<dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency>
1.2.2. 配置物件解析
在spring的核心配置檔案中新增物件解析
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置檔案編碼處理 --> <property name="defaultEncoding" value="utf-8"/> <!-- 配置檔案大小限制 --> <property name="maxUploadSize" value="4096000000"/> <!-- 配置記憶體緩衝區大小 --> <property name="maxInMemorySize" value="1024000"/> </bean>
說明:配置物件解析時,bean的id一定要指定,而且官方規定必須為multipartResolver
1.2.3. 定義upload.jsp
在WEB-INF/pages目錄下建立一個upload.jsp,然後建立上傳表單
<body> <h1>檔案上傳</h1> <h1>${msg}</h1> <form action="doUpload.do" method="post" enctype="multipart/form-data"> <input type="file" name="upfile"/> <br/> <input type="submit" value="upload"> </form> </body>
說明:定義表單時,提交方式必須為post,enctype必須為multipart/form-data
1.2.4. 定義UploadController
@RequestMapping("/upload/") @Controller public class UploadController { @RequestMapping("uploadUI") public String uploadUI(){ return "upload"; } @RequestMapping("doUpload") public ModelAndView doUpload(MultipartFile upfile) throws IOException{ //獲取檔名以及檔案大小,檢測是否獲得檔案相關資料 String fileName=upfile.getOriginalFilename(); long size=upfile.getSize(); System.out.println(fileName+"/"+size); //構建檔案目標物件,這個物件對應的檔案路徑必須是存在的或者通過file物件自己建立 File dest=new File("D:/SSMWORK/"+fileName); //transferto實現檔案上傳 upfile.transferTo(dest); //封裝資料返回 ModelAndView mv=new ModelAndView("upload"); mv.addObject("msg", "upload ok"); return mv; } }
說明:在控制層方法接收請求中file型別的資料時需要藉助MultipartFile 型別的引數物件,其引數名要求與表單中type為file的引數名相同。