SpringMVC是一種輕量級的、基於MVC的Web層應用框架。html
經過一套 MVC 註解,讓 POJO 成爲處理請求的控制器,而無須實現任何接口。前端
採用了鬆散耦合可插拔組件結構,比其餘 MVC 框架更具擴展性和靈活性。java
優勢:web
一、天生與Spring框架集成,如:(IOC,AOP)spring
二、支持Restful風格瀏覽器
三、支持靈活的URL到頁面控制器的映射tomcat
四、很是容易與其餘視圖技術集成,如:Velocity、FreeMarker等等服務器
五、由於模型數據不存放在特定的API裏,而是放在一個Model裏(Map數據結構實現,所以很容易被其餘框架使用)網絡
六、很是靈活的數據驗證、格式化和數據綁定機制、能使用任何對象進行數據綁定,數據結構
七、更加簡單、強大的異常處理
八、對靜態資源的支持
九、支持靈活的本地化、主題等解析
經常使用主要組件
① DispatcherServlet:前端控制器
② Controller:處理器/頁面控制器,作的是MVC中的C的事情,但控制邏輯轉移到前端控制器了,用於對請求進行處理
③ HandlerMapping:請求映射處處理器,找誰來處理,若是映射成功返回一個HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象、多個HandlerInterceptor攔截器對象)
④ View Resolver : 視圖解析器,找誰來處理返回的頁面。把邏輯視圖解析爲具體的View,進行這種策略模式,很容易更換其餘視圖技術;如InternalResourceViewResolver將邏輯視圖名映射爲JSP視圖
⑤ LocalResolver:本地化、國際化
⑥ MultipartResolver:文件上傳解析器
⑦ HandlerExceptionResolver:異常處理器
流程分析
基本步驟:
① 客戶端請求提交到DispatcherServlet
② 由DispatcherServlet控制器查詢一個或多個HandlerMapping,找處處理請求的Controller
③ DispatcherServlet將請求提交到Controller(也稱爲Handler)
④ Controller調用業務邏輯處理後,返回ModelAndView
⑤ DispatcherServlet查詢一個或多個ViewResoler視圖解析器,找到ModelAndView指定的視圖
⑥ 視圖負責將結果顯示到客戶端
標準的 HTTP 請求報頭
一、使用@RequestMapping 註解來映射請求的 URL
@RequestMapping能夠應用的地方
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Mapping
public @interface RequestMapping {…}
請求的方式有
public enum RequestMethod { GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE }
@RequestMapping能夠爲控制器指定能夠處理哪些 URL 請求,將該註解中的 value 屬性值映射成URL,客戶端能夠經過該URL請求到指定類中的方法。
1)在控制器的類定義或方法定義處均可標註 @RequestMapping
① 標記在類上:提供初步的請求映射信息。相對於 WEB 應用的根目錄
② 標記在方法上:提供進一步的細分映射信息。相對於標記在類上的 URL。
2)若類上未標註 @RequestMapping,則方法處標記的 URL 相對於 WEB 應用的根目錄
3)做用:DispatcherServlet 截獲請求後,就經過控制器上 @RequestMapping 提供的映射信息肯定請求所對應的處理方法。
@RequestMapping屬性
value:指定URL路徑
method:指定請求方式
params:指定請求參數
headers:指定請求頭信息
映射請求參數、請求方式或請求頭
1)@RequestMapping 除了可使用請求 URL 映射請求外,還可使用請求方法、請求參數及請求頭來精確映射對應請求
2)@RequestMapping 的 value【重點】、method【重點】、params【瞭解】 及 heads【瞭解】 分別表示請求 URL、請求方式、請求參數及請求頭的映射條件,他們之間是與的關係,聯合使用多個條件可以讓請求映射更加精確化。即:需知足全部映射條件纔可匹配到對應方法
3)params 和 headers支持簡單的表達式:
param1: 表示請求必須包含名爲 param1 的請求參數
!param1: 表示請求不能包含名爲 param1 的請求參數
param1 != value1: 表示請求包含名爲 param1 的請求參數,但其值不能爲 value1
{"param1=value1", "param2"}: 請求必須包含名爲 param1 和param2 的兩個請求參數,且 param1 參數的值必須爲 value1
Ant 風格資源地址支持 3 種匹配符:【瞭解】
?:匹配文件名中的一個字符
*:匹配文件名中的任意字符
**:** 匹配多層路徑
/user/*/**/createUser?? 匹配 /user/xxx/多層/createUserXX
REST是什麼?由於REST的內涵很是豐富,因此很難用一兩句話解釋清楚這個問題。首先,REST是Web自身的架構風格。
參考資料:理解本真的REST架構風格
REST:即 Representational State Transfer。(資源)表現層狀態轉化。是目前最流行的一種互聯網軟件架構。它結構清晰、符合標準、易於理解、擴展方便
資源(Resources):資源是一種看待服務器的方式。是網絡上的一個實體,能夠是一段文本、一張圖片,能夠用一個URI(統一資源定位符,獨一無二的識別符)指向它,獲取這個資源,訪問它的URI就能夠了
表現層:資源的表述(Representation)是一段對於資源在某個特定時刻的狀態的描述,即把資源具體呈現出來的形式, 好比,文本能夠用 txt 、JSON 格式表現,甚至能夠採用二進制格式。
狀態轉化(State Transfer):狀態轉移說的是:在客戶端和服務器端之間轉移(transfer)表明資源狀態的表述。經過轉移和操做資源的表述,來間接實現操做資源的目的。如:每發出一個請求,就表明了客戶端和服務器的一次交互過程。HTTP協議,是一個無狀態協議,即全部的狀態都保存在服務器端。所以,若是客戶端想要操做服務器,必須經過某種手段,讓服務器端發生「狀態轉化」。而這種轉化是創建在表現層之上的,因此就是 「表現層狀態轉化」。
統一接口(Uniform Interface)REST要求,必須經過統一的接口來對資源執行各類操做。對於每一個資源只能執行一組有限的操做。例如:HTTP/1.1協議定義了一個操做資源的統一接口。REST還要求,對於資源執行的操做,其操做語義必須由HTTP消息體以前的部分徹底表達,不能將操做語義封裝在HTTP消息體內部。這樣作是爲了提升交互的可見性
超文本驅動(Hypertext Driven)將Web應用看做是一個由不少狀態(應用狀態)組成的有限狀態機。資源之間經過超連接相互關聯,超連接既表明資源之間的關係,也表明可執行的狀態遷移。即:客戶端應該依賴的是超媒體的狀態遷移語義,而不該該對因而否存在某個URI或URI的某種特殊構造方式做出假設。一切都有可能變化,只有超媒體的狀態遷移語義可以長期保持穩定。
具體對於HTTP來講,就是 HTTP 協議裏面對應的四種經常使用基本操做:GET 用來獲取資源,POST 用來新建資源,PUT 用來更新資源,DELETE 用來刪除資源。應使用由客戶端定義的請求方式指定對應的某種操做,而不該該經過某種特殊構造方式進行指定
瀏覽器 form 表單只支持 GET 與 POST 請求,HiddenHttpMethodFilter 能夠將POST請求轉換爲標準的 http 方法以達到REST風格
使用步驟
1. 必須將form表單中的method設置爲POST
2. 提交表單時,必須提交"_method"參數,通常使用隱藏域
緣由:HiddenHttpMethodFilter過濾器將HttpServletRequest中的getMethod()方法,重寫啦。
<!-- 配置處理請求方式--> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Spring MVC 框架會將 HTTP 請求的信息綁定到相應的方法入參中,並根據方法的返回值類型作出相應的後續處理。
能夠對方法及方法入參標註相應的註解( @PathVariable 、@RequestParam、@RequestHeader 等)
@PathVariable請求佔位符
是 Spring3.0 新增的功能,經過 @PathVariable 能夠將 URL 中佔位符參數綁定到控制器處理方法的入參中
//@PathVariable 註解能夠將請求URL路徑中的請求參數,傳遞處處理請求方法的入參中 // 瀏覽器的請求爲: testPathVariable/1001 @RequestMapping(value="/testPathVariable/{id}",method=RequestMethod.DELET) public String testPathVariable(@PathVariable("id") Integer id) {}
@RequestParam請求參數
若是請求參數與形參不一致時,可使用@RequestParam註解實現獲取參數值
書寫位置:標註在方法的參數中,springMVC默認會將請求參數注入(綁定)到方法形參中(兩個參數名一致)
一旦使用該註解,必須爲相應參數傳參數。若是未傳參,會報錯:400,由於required默認爲 true,
value:用於映射請求參數名稱
required:是否必須。默認爲 true, 表示請求參數中必須包含對應的參數,若不存在,將拋出異常
defaultValue: 默認值,當沒有傳遞參數時使用該值做爲默認值,不設默認爲 null
@RequestMapping(value="/testRequestParam?username=guigu&age=10") public String testRequestParam( @RequestParam(value="username") String username, @RequestParam(value="age",required=false,defaultValue="0") int age){ return "success"; }
@RequestHeader 請求頭
獲取請求頭信息,請求頭包含了若干個屬性,服務器可據此獲知客戶端的信息,經過 @RequestHeader 便可將請求頭中的屬性值綁定處處理方法的入參中
@CookieValue
獲取指定的Cookie信息,可以讓處理方法入參綁定某個 Cookie 值
使用POJO做爲參數
Spring MVC 會按請求參數名和 POJO 屬性名進行自動匹配,自動爲該對象填充屬性值。支持級聯屬性。
@RequestMapping(value = "/emps",method = RequestMethod.PUT) public String updateEmp(Employee employee){ employeeDao.save(employee); return "redirect:/emps"; } //Spring MVC 會按請求參數名和 Employee 屬性名進行自動匹配, 自動爲該對象填充屬性值。支持級聯屬性
配置字符編碼過濾器
<!-- 處理POST請求和響應亂碼--> <filter> <filter-name>characterEncodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
使用Servlet原生API
/** * 可使用 Serlvet 原生的 API 做爲目標方法的參數 具體支持如下類型 * HttpServletRequest * HttpServletResponse * HttpSession * java.security.Principal * Locale
* InputStream * OutputStream * Reader * Writer */ @RequestMapping("/testServletAPI") public void testServletAPI(HttpServletRequest request,HttpServletResponse response, Writer out) throws IOException { System.out.println("testServletAPI, " + request + ", " + response); out.write("hello springmvc"); }
二、返回值會經過視圖解析器解析爲實際的物理視圖
輸出模型數據類型
1) ModelAndView: 做爲返回值類型,響應數據:處理方法返回值類型爲 ModelAndView 時, 方法體便可經過該對象添加模型數據
2) String: 做爲返回值類型,即爲視圖信息直接找字符串映射 URL 路徑,轉發或重定向
3) Map 或 Model: 做爲參數,響應數據:入參爲 Model、ModelMap 或 Map,處理方法返回時,Map 中的數據會自動添加到模型中。
ModelAndView
控制器處理方法的返回值若是爲 ModelAndView, 則其既包含視圖信息,也包含模型數據信息。
1) 兩個重要的成員變量:
private Object view; 【視圖信息】
private ModelMap model; 【模型數據】
2)添加模型數據:
MoelAndView addObject(String attributeName, Object attributeValue) 【設置模型數據】
ModelAndView addAllObject(Map<String, ?> modelMap)
4)設置視圖:
void setView(View view) 【設置視圖對象】
void setViewName(String viewName) 【設置視圖名字】
5)獲取模型數據
protected Map<String, Object> getModelInternal() 【獲取模型數據】
public ModelMap getModelMap()
public Map<String, Object> getModel()
@RequestMapping("/testModelAndView") public ModelAndView testModelAndView(){ String viewName = "success"; ModelAndView mv = new ModelAndView(viewName); mv.addObject("time",new Date().toString()); //實質上存放到request域中 return mv; }
ModelAndView 底層工做原理,不論控制器返回一個String,ModelAndView,View都會轉換爲ModelAndView對象,將數據放到request域中,再經過轉發實現頁面跳轉
Spring MVC 在內部使用了一個 org.springframework.ui.Model 接口存儲模型數據
Spring MVC 在調用方法前會建立一個隱含的模型對象做爲模型數據的存儲容器。
若是方法的入參爲 Map 或 Model 類型,Spring MVC 會將隱含模型的引用傳遞給這些入參。
在方法體內,開發者能夠經過這個入參對象訪問到模型中的全部數據,也能夠向模型中添加新的屬性數據
//目標方法的返回類型也能夠是一個Map類型參數(也能夠是Model,或ModelMap類型) @RequestMapping("/testMap") public String testMap(Map<String, Object> map) { //【重點】 System.out.println(map.getClass().getName()); //org.springframework.validation.support.BindingAwareModelMap map.put("names", Arrays.asList("Tom", "Jerry", "Kite")); return "success"; }
注意問題:Map集合的泛型,key爲String,Value爲Object,而不是String
由源碼可知:不論用那個類型做爲數據模型,其內部都會轉化爲BindingAwareModelMap類型使其指向同一map對象
BindingAwareModelMap底層支持兩種接口(Map&Model)推薦使用 Map 便於框架移植