SpringMVC基礎知識
1、
學習SpringMVC框架最核心的就是DispatcherServlet的設計,掌握好DispatcherServlet是掌握SpringMVC的核心關鍵。
2、SpringMVC的優點
2)強大而直接的配置方式:將框架類和應用程式類都能作為JavaBean配置,支援跨多個context的引用,例如,在web控制器中對業務物件和驗證器validator的引用。
3)可適配、非侵入:可以根據不同的應用場景,選擇合適的控制器子類(simple型、command型、from型、wizard型、multi-action型或者自定義),而不是一個單一控制器(比如Action/ActionForm)繼承。
4)可重用的業務程式碼:可以使用現有的業務物件作為命令或表單物件,而不需要去擴充套件某個特定框架的基類。
5)可定製的繫結(binding)和驗證(validation):比如將型別不匹配作為應用級的驗證錯誤,這可以保證錯誤的值。再比如本地化的日期和數字繫結等等。在其他某些框架中,你只能使用字串表單物件,
需要手動解析它並轉換到業務物件。
6)可定製的handler mapping和view resolution:Spring提供從最簡單的URL對映,到複雜的、專用的定製策略。與某些web MVC框架強制開發人員使用單一特定技術相比,Spring顯得更加靈活。
7)靈活的model轉換:在Springweb框架中,使用基於Map的鍵/值對來達到輕易的與各種檢視技術整合。
8)可定製的本地化和主題(theme)解析:支援在JSP中可選擇地使用Spring標籤庫、支援JSTL、支援Velocity(不需要額外的中間層)等等。
9)簡單而強大的JSP標籤庫(Spring Tag Library):支援包括諸如資料繫結和主題(theme)之類的許多功能。他提供在標記方面的最大靈活性。
10)JSP表單標籤庫:在Spring2.0中引入的表單標籤庫,使用在JSP編寫表單更加容易。
11)Spring Bean的生命週期:可以被限制在當前的HTTP Request或者HTTP Session。準確的說,這並非Spring MVC框架本身特性,而應歸屬於Spring MVC使用的WebApplicationContext容器。
3、SpringMVC的實現原理
SpringMVC的MVC模式:
SpringMVC的具體執行流程:
當發起請求時被前置的控制器攔截到請求,根據請求引數生成代理請求,找到請求對應的實際控制器,控制器處理請求,建立資料模型,
訪問資料庫,將模型響應給中心控制器,控制器使用模型與檢視渲染檢視結果,將結果返回給中心控制器,再將結果返回給請求者。
1、DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心。使用者發出請求,DispatcherServlet接收請求並攔截請求。
2、HandlerMapping為處理器對映。DispatcherServlet呼叫HandlerMapping,HandlerMapping根據請求url查詢Handler。
3、返回處理器執行鏈,根據url查詢控制器,並且將解析後的資訊傳遞給DispatcherServlet
4、HandlerAdapter表示處理器介面卡,其按照特定的規則去執行Handler。
5、執行handler找到具體的處理器
6、Controller將具體的執行資訊返回給HandlerAdapter,如ModelAndView。
7、HandlerAdapter將檢視邏輯名或模型傳遞給DispatcherServlet。
8、DispatcherServlet呼叫檢視解析器(ViewResolver)來解析HandlerAdapter傳遞的邏輯檢視名。
9、檢視解析器將解析的邏輯檢視名傳給DispatcherServlet。
10、DispatcherServlet根據檢視解析器解析的檢視結果,呼叫具體的檢視,進行試圖渲染
11、將響應資料返回給客戶端
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.3.RELEASE</version> </dependency> </dependencies>
2)編寫web.xml檔案
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--配置DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--
關聯springmvc的配置檔案
此配置檔案的屬性可以不新增,但是需要在WEB-INF的目錄下建立 前端控制器名稱-servlet.xml檔案
-->
<init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </init-param> </servlet>
<!--匹配servlet的請求,
/:標識匹配所有請求,但是不會jsp頁面
/*:攔截所有請求,攔截jsp頁面
但是需要注意的是,當配置成index.html的時候,會發現請求不到
原因在於,tomcat下也有一個web.xml檔案,所有的專案下web.xml檔案都需要繼承此web.xml
在伺服器的web.xml檔案中有一個DefaultServlet用來處理靜態資源,但是url-pattern是/
而我們在自己的配置檔案中如果添加了url-pattern=/會覆蓋父類中的url-pattern,此時在請求的時候
DispatcherServlet會去controller中做匹配,找不到則直接報404
而在伺服器的web.xml檔案中包含了一個JspServlet的處理,所以不過攔截jsp請求
-->
<servlet-mapping> <servlet-name>springmvc</servlet-name> <!--/*和/都是攔截所有請求,/會攔截的請求不包含*.jsp,而/*的範圍更大,還會攔截*.jsp這些請求--> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
3)編寫springmvc需要的spring配置檔案,applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!--處理對映器--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean> <!--處理器介面卡--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean> <!--檢視解析器--> <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--配置字首--> <property name="prefix" value="/WEB-INF/jsp/"></property> <!--配置字尾--> <property name="suffix" value=".jsp"></property> </bean> <bean id="/hello" class="com.llxazy.controller.HelloController"></bean> </beans>
4)HelloController.java
package com.llxazy.controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //建立模型和檢視物件 ModelAndView mv = new ModelAndView(); //將需要的值傳遞到model中 mv.addObject("msg","helloSpringMVC"); //設定要跳轉的檢視, mv.setViewName("hello"); return mv; } }
5)建立hello.jsp頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${msg}
</body>
</html>
6)配置tomcat,傳送請求
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!--自動掃描包,由IOC容器進行控制管理--> <context:component-scan base-package="com.llxazy"></context:component-scan> <!-- 檢視解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 字首 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 字尾 --> <property name="suffix" value=".jsp" /> </bean> </beans>
4)編寫HelloController.java
package com.llxazy.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller public class HelloController{ /* * @RequestMapping就是用來標識此方法用來處理什麼請求,其中的/可以取消 * 取消後預設也是從當前專案的根目錄開始查詢,一般在編寫的時候看個人習慣 * 同時,@RequestMapping也可以用來加在類上, * */ @RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","hello,SpringMVC"); return "hello"; } }
5)編寫hello.jsp
6)配置tomcat,傳送請求
6、
1)客戶端傳送請求http://localhost:8080/hello
2)由tomcat接受到對應的請求
3)SpringMVC的前端控制器DispatcherServlet接收到所有的請求
4)檢視請求地址和@RequestMapping註解的哪個匹配,來找到具體的類的處理方法
5)前端控制器找到目標處理類和方法之後,執行目標方法
6)方法執行完成之後會有一個返回值,SpringMVC會將這個返回值用檢視解析器進行解析拼接成完整的頁面地址
7)DispatcherServlet拿到頁面地址之後,轉發到具體的頁面
7、
@RequestMapping用來匹配客戶端傳送的請求,可以在方法上使用,也可以在類上使用。
方法:表示用來匹配要處理的請求
類上:表示為當前類的所有方法的請求地址新增一個前置路徑,訪問的時候必須要新增此路徑
在整個專案的不同方法上不能包含相同的@RequestMapping值
@RequestMapping註解還可以新增很多額外的屬性值,用來精確匹配請求
@RequestMapping還包含了很多複雜的匹配功能,提供了萬用字元的支援
package com.llxazy.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/llxazy") public class HelloController{ /* * @RequestMapping就是用來標識此方法用來處理什麼請求,其中的/可以取消 * 取消後預設也是從當前專案的根目錄開始查詢,一般在編寫的時候看個人習慣 * 同時,@RequestMapping也可以用來加在類上, * */ @RequestMapping("/hello") public String hello(Model model){ model.addAttribute("msg","hello,SpringMVC"); return "hello"; } /** * Request的其他屬性值 * value:要匹配的請求 * method:限制傳送請求的方式: POST GET * params:表示請求要接受的引數,如果定義了這個屬性,那麼傳送的時候必須要新增引數 * params有幾種匹配規則 * 1、直接寫引數的名稱,param1,param2 * params = {"username"} * 2、表示請求不能包含的引數,!param1 * params = {"!username"} * 3、表示請求中需要要包含的引數但是可以限制值 param1=values param1!=value * params = {"username=123","age"} * params = {"username!=123","age"} * headers:填寫請求頭資訊 * chrome:User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36 * firefox:User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0 * * consumers:只接受內容型別是哪種的請求,相當於指定Content-Type * produces:返回的內容型別 Content-Type:text/html;charset=utf-8 * * @return */ @RequestMapping(value = "/hello2",method = RequestMethod.POST) public String hello2(){ return "hello"; } @RequestMapping(value = "/hello3",params = {"username!=123","age"}) public String hello3(String username){ System.out.println(username); return "hello"; } @RequestMapping(value = "/hello4",headers = {"User-Agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0"}) public String hello4(){ return "hello"; } /** * @Request包含三種模糊匹配的方式,分別是: * ?:能替代任意一個字元 * *: 能替代任意多個字元和一層路徑 * **:能代替多層路徑 * @return */ @RequestMapping(value = "/**/h*llo?") public String hello5(){ System.out.println("hello5"); return "hello"; } }
@PathVariable註解,此註解就是提供了對佔位符URL的支援,就是將URL中佔位符引數繫結到控制器處理方法的引數中。
package com.llxazy.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller @RequestMapping("/llxazy") public class HelloController{ @RequestMapping(value = "/pathVariable/{name}") public String pathVariable(@PathVariable("name") String name){ System.out.println(name); return "hello"; } }