一. SpringMVC概述及原理1. SpringMVC是什麼
Spring MVC屬於SpringFrameWork的後續產品,已經融合在Spring Web Flow裡面。Spring 框架提供了構建 Web 應用程式的全功能 MVC 模組。使用 Spring 可插入的 MVC 架構,從而在使用Spring進行WEB開發時,可以選擇使用Spring的Spring MVC框架或整合其他MVC開發框架,如Struts1(現在一般不用),[Struts 2](/file/2020/09/24/20200924103654_11.jpg 2/2187934)(一般老專案使用)等。
SpringMVC 已經成為目前最主流的 MVC 框架之一, 從 Spring3.0 的釋出, 就已全面超越 Struts2,成為最優秀的 MVC 框架。它通過一套註解,讓一個簡單的 Java 類成為處理請求的控制器,而無須實現任何介面。同時它還支援RESTful 程式設計風格的請求。
2. MVC和三層架構MVC模式(Model-View-Controller)是軟體工程中的一種軟體架構模式,把軟體系統分為三個基本部分:模型(Model)、檢視(View)和控制器(Controller)。
控制器(Controller):Servlet,控制器主要處理使用者的請求
檢視(View):HTML, JSP, 前端框架
模型(Model):邏輯業務程式(後臺的功能程式), Service, Dao, JavaBean
JavaWEB發展史Model1所有的業務邏輯交給jsp單獨處理完成,一個web專案只存在DB層和JSP層,所有的東西都耦合在一起,對後期的維護和擴充套件極為不利。
Model2 第一代JSP Model2有所改進,把業務邏輯的內容放到了JavaBean中,而JSP頁面負責顯示以及請求排程的工作。雖然第二代比第一代好了些,但JSP還是把view和controller的業務耦合在一起。依然很不理想。
Model2 第二代(三層架構)Model2第二代就是現在大力推廣的和使用的mvc,將一個專案劃分為三個模組,各司其事互不干擾,既解決了jsp所形成的耦合性,又增加了邏輯性、業務性以及複用性和維護性
表示層(web層):包含JSP,Servlet等web相關的內容
業務邏輯層(Service):處理業務,不允許出現servlet中的request、response。
資料層(Data Access Object):也叫持久層,封裝了對資料庫的訪問細節。
其中 web層相當於mvc中的view+controller,Service層和dao層相當於mvc中的model。
3. SpringMVC 在三層架構的位置MVC模式:(Model-View-Controller):為了解決頁面程式碼和後臺程式碼的分離.
檢視是否生成webapp目錄和maven專案打包方式是否變為war
在springmvc早期版本中需要我們自己載入springmvc的三大元件(現在我們使用的版本5.0.6會自動載入這三大元件)
**處理器對映器:RequestMappingHandlerMapping **
處理器介面卡:RequestMappingHandlerAdapter
處理器解析器:ExceptionHandlerExceptionResolver
在早期的版本中使用 <mvc:annotation-driven> 自動載入這三大元件,但是高版本的不需要<mvc:annotation-driven>來載入
同時它還提供了:資料繫結支援,@NumberFormatannotation支援,@DateTimeFormat支援,@Valid支援,讀寫XML的支援(JAXB,讀寫JSON的支援(Jackson)。我們處理響應ajax請求時,就使用到了對json的支援(配置之後,在加入了jackson的core和mapper包之後,不寫配置檔案也能自動轉換成json)
springmvc配置檔案說明注意:預設的Spring配置檔案放在WEB-INF下,名為{servlet-name}-servlet.xml
{servlet-name}指的是,核心控制器配置的名字
如:dispatcherServlet-servlet.xml
當請求被springmvc處理時,springmvc會去預設路徑下載入xxxx-servlet.xml核心配置檔案
但是我們在開發中一般都是把配置檔案寫在classes下的,我們可以在web.xml中設定springmvc配置檔案的路徑
1、客戶端傳送請求給前端控制器(DispatcherServlet)
2、dispatcherServlet接收到請求呼叫HandlerMapping處理器對映器
3、處理器對映器根據請求的url找對應的處理器,生成處理器物件(handler)返回
4、dispatchServlet將handler傳入處理器介面卡執行
5、處理器介面卡執行handler
6、執行完成最終封裝一個ModelAndView
7、將ModelAndView返回給前端控制器
8、前端控制器將請求的路徑交給檢視解析器進行解析
9、最終封裝一個View物件給dispatcherServlet,此View物件封裝了響應引數
10、JSP頁面渲染資料
11、響應客戶端
1.8 SpringMVC原始碼分析我們知道SpringMVC實質上是對servlet進行封裝,讓我們的開發更加簡便
1. 準備工作我們知道springmvc在工作開始之前會載入預設的處理器對映器、處理器介面卡、處理器解析器等
可以在spring-webmvc-5.0.6.RELEASE.jar原始碼包下檢視DispatcherServlet.properties檔案看有哪些處理器是springmvc預設載入的
我們發現DispatcherServlet最終還是繼承與HttpServlet,那麼我們就直接找service方法吧!
經打斷點發現,最終會走向DispacherServlet的doDispacher方法!
此時請求進入DispatcherServlet,按照我們畫圖分析的結果應該是把請求交給處理器對映器HandlerMapping最終返回一個Handler
接下來進入處理器介面卡HandlerAdapter執行handler最終返回一個ModelAndView
然後請求交給檢視解析器進行解析最終返回一個View物件
1.9.核心控制器SpringMVC自帶了攔截器請求的核心控制器.所以就可以在請求過來的時候,直接啟動Spring框架
預設情況下,Spring容器是在核心控制器DispatcherServlet獲得請求後才啟動的.
能不能網站啟動的時候,Spring容器就立刻啟動.
@RequestMapping("/demo3_1")public String demo3_1(){ return "/success.jsp"; //直接返回字串}
返回ModelAndView
ModelAndView是SpringMVC幫我們提供的,即"模型和檢視"
@RequestMapping("/demo3_2")public ModelAndView demo3_2(){ //返回ModelAndView ModelAndView mav=new ModelAndView(); mav.setViewName("success.jsp"); mav.addObject("username","東方標準"); return mav;}
返回void一般用於使用原生的Servlet物件或者ajax請求
@RequestMapping("/demo3_3")\t\t//返回void(一般用於ajax)public void demo3_2(HttpServletResponse response) throws IOException { response.setContentType("text/html;charset=utf8"); response.getWriter().write("東方標準");}
轉發和重定向
SpringMVC提供了一個 String 型別返回值之後會自動解析forward、redirect等特殊字串
檢視解析器配置的字首和字尾解析不支援forward、redirect
:redirect:代表重定向response.sendRedirect(url)
@RequestMapping("/demo3_4")public String demo3_4(Model model) { //轉發 System.out.println("執行啦!"); model.addAttribute("username","東方標準"); return "forward:/success.jsp";}
@RequestMapping("/demo3_5")public String demo3_5(HttpSession session) { //重定向 session.setAttribute("password","admin"); System.out.println("執行啦!"); return "redirect:/success.jsp";}
四. 對映路徑-@RequestMapping1. 探究RequestMapping
註解式處理器對映器,對類中標記了@ResquestMapping的方法進行對映。根據@ResquestMapping定義的url匹配@ResquestMapping標記的方法,匹配成功返回HandlerMethod物件給前端控制器。HandlerMethod物件中封裝url對應的方法Method。
@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Mappingpublic @interface RequestMapping {}
名稱空間
按照我們傳統的url寫法不能很好的規定請求路徑,即不能按照業務來區分請求
例如現在user需要定義一個findById,goods也需要定義一個findById,此時就會有衝突,針對這種現象我們可以在類上定義一個名稱空間,即在類上使用@RequestMapping註解,類似於一級目錄,以後訪問此類下的任意資源都需要加上此目錄
類上請求 URL 的第一級訪問目錄。此處不寫的話,就相當於應用的根目錄。 寫的話需要以/開頭。它出現的目的是為了使我們的 URL 可以按照模組化管理:
例如:
user模組:
/user/register
/user/update
/user/findById
goods模組:
/goods/add
/goods/update
/goods/findById
對映路徑的有三種:標準的對映路徑,帶萬用字元的對映路徑,帶路徑變數的對映路徑
方法上請求 URL 的第二級訪問目錄。
屬性:value:用於指定請求的 URL。 它和 path 屬性的作用是一樣的。method:用於指定請求的方式。params:用於指定限制請求引數的條件。 它支援簡單的表示式。 要求請求引數的 key 和 value 必須和配置的一模一樣。params = {“userId”},表示請求引數必須有 userId,區分大小寫
params = {“userId!=20”},表示請求引數中 id不能是 20。可以不攜帶userId引數,區分大小寫
headers:用於指定限制請求訊息頭的條件。
package com.dfbz.controller;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.ModelAndView;@Controllerpublic class HelloController{ public HelloController(){ System.out.println("Hello建立了"); } /* \t代表此方法的訪問路徑為/hello.form,如果攜帶userId引數那麼引數必須不能等於1 \t並且提交方式一定要為POST */ @RequestMapping(value = "/hello.form",params = "userId!=1",method = RequestMethod.POST) public ModelAndView hello(){ ModelAndView mav=new ModelAndView(); mav.addObject("msg","小標"); mav.setViewName("/hello.jsp"); return mav; }}
小結:
2.3. RESTFUL1.引數必須包括:params={“username”,“password”}
2.引數不能包括:params={"!userid"}
3引數值必須是指定的值:params={“username=zhangsan”})
4.引數值必須不是指定的值:params={“userid!=123”})
所謂的路徑變數,就是將引數放在路徑裡面,而不是放在?的後面
如:原get請求方法 /login.mvc?username=’zhangsan’&pwd=’123456’
路徑變數寫法:
/zhangsan/123456/login.form
2.3.1 什麼是RESTFULREST(英文:Representational State Transfer,簡稱REST)RESTful是一種軟體架構風格、設計風格,而不是標準,只是提供了一組設計原則和約束條件。它主要用於客戶端和伺服器互動類的軟體。基於這個風格設計的軟體可以更簡潔,更有層次,更易於實現快取等機制。
2.3.2 RESTFUL示例:請求方式有幾種?7種
jsp、html,只支援get、post。
基於restful風格的url:新增http://localhost:8080/SpringMVC_01/user
提交方式: post
修改http://localhost:8080/SpringMVC_01/user
提交方式:put
提交方式:delete
查詢http://localhost:8080/SpringMVC_01/user/102
提交方式:get
五. 資料繫結1. 資料繫結是什麼SpringMVC裡面,所謂的資料繫結就是將請求帶過來的表單資料繫結到執行方法的引數變數中,或將伺服器資料繫結到內建物件,傳遞到頁面
2. 自動繫結的資料型別2.1 自動繫結資料型別基本資料型別:基本資料型別+String+包裝類包裝資料型別(POJO):包裝實體類陣列和集合型別:List、Map、Set、陣列等資料型別2.2 內建繫結資料自動繫結:ServletAPI:HttpServletRequest
HttpServletResponse
HttpSession
SpringMVC內建物件Model
ModelMap
ModelAndView
Model和ModelMap預設都是儲存了Request請求作用域的資料的物件
這個兩個物件的作用是一樣.就將資料返回到頁面.
頁面:<h3>測試Post亂碼</h3><form action="/demo" method="post"> <input type="text" name="username"> <input type="text" name="password"> <input type="text" name="address"> <input type="submit"></form>
controller:@RequestMapping("/demo7.form") //Pojo物件引數繫結public String demo7(User user){ System.out.println(user); return "/success.jsp";}
發現POST亂碼
解決post提交亂碼我們可以配置spring提供的過濾器
遇到需要強制繫結的幾種情況
a. 預設引數繫結的是表單資料,如果資料不是來自表單(如restful),那麼必須需要強制繫結
b. 資料是來自表單的,但是引數名不匹配,那麼也需要強制繫結
c. 資料是來自表單的,但是需要將資料繫結在Map物件裡面,需要強制繫結
4.1. @PathVariable:繫結路徑引數這個註解是繫結路徑引數的.
/** * @SessionAttribute:從session中獲取一個值 * @param username * @param user * @return */@RequestMapping(value = "/demo6")public String demo5(@SessionAttribute("password") String username,@SessionAttribute("user") User user){ System.out.println(username); return "/success.jsp";}
5. 格式化引數型別SpringMVC之所以能夠幫我們實現自動資料型別轉換是因為SpringMVC提供了非常多的轉換器(Converter)
例如:
發現他們都實現Converter介面,如果我們需要之定義轉換器必須實現Converter介面
案例:實現日期的轉換
SpringMVC提供了,request,session ,globalsession三個生命週期
request:每次新的請求,建立一個新的例項.session:每次會話建立一個新的例項. 就是同一個瀏覽器,就使用同一個例項globalsession:基於叢集的session每個Session建立一個例項
<mvc:annotation-driven conversion-service=“myConverters”/>
六. Controller的生命週期Spring框架預設建立的物件是單例.所以業務控制器是一個單例物件.
SpringMVC提供了,request,session ,globalsession三個生命週期
request:每次新的請求,建立一個新的例項.session:每次會話建立一個新的例項. 就是同一個瀏覽器,就使用同一個例項globalsession:基於叢集的session每個Session建立一個例項