Spring Web MVC是基於Servlet API構建的傳統Web框架,而且從一開始就已包含在Spring框架中html
與Spring Web MVC並行,Spring Framework 5.0引入了一個新的反應式Web框架,其名稱「 Spring WebFlux;前端
理解:java
首先SpringMVC 是一個MVC構架模式的web框架,是基於Servlet的,從Spring第一個版本就一塊兒推出了,python
傳統web框架,指的是SpringMVC依然使用多線程同步併發的方式來處理請求,現現在你們都在鼓吹異步併發多麼多麼好,從測試數據來看異步併發效率的確更好,可是其並不成熟,極大多數公司項目尚未更新到異步技術,盲目的進行重構可能會引起更多的問題, 而且異步編程在代碼結構上會產生較大的變化,對於初學者而言,掌握難度是較大的;web
構架圖:
spring
能夠看出apache
SpringMVC 並無代替Servlet,它只是在Servlet上提供了一套封裝好的組件,提升開發效率;編程
還使得開發出的項目更加規範;不然每一個人可能有每一個人不一樣的MVC;json
思考:後端
若沒有SpringMVC框架,咱們該如何去編寫一個較大的web項目呢,能夠發如今選課系統中出現了大量的Servlet,由於一個請求地址就須要一個Servlet,使得項目體積變大,且Servlet是長期存在內存的;
第一步,咱們但願用一個Servlet來處理多個請求甚至是全部請求,就須要實現能根據請求路徑查找處理請求方法的邏輯,這也是SpringMVC要作的第一件事情;
固然還有一些其餘的
類型 | 說明 |
---|---|
HandlerExceptionResolver |
Handler異常處理器 |
LocaleResolver |
提供國際化的視圖。根據不一樣地區顯示不一樣內容 |
ThemeResolver |
根據不一樣地區提供個性化的佈局 |
MultipartResolver |
解析multipart請求數據,如瀏覽器表單文件上傳 |
FlashMapManager |
經常使用於經過重定向將屬性從一個請求傳遞到另外一個請求 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>MVC01</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>MVC01 Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties> <dependencies> <!-- SpringMVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.2.RELEASE</version> </dependency> <!--JEE相關的--> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.3</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies> </project>
與在web項目中使用Spring中相同的是,咱們也須要讓SpringMVC隨着web項目啓動,SpringMVC的作法是利用DIspatcherServlet;
<?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"> <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:springmvc.xml</param-value> </init-param> <load-on-startup></load-on-startup> </servlet> <!-- 要交給SpringMVC處理的請求--> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
DispatcherServlet作了兩個事情,1:初始化一個Spring容器,2:註冊一個Servlet
SpringMVC本質上也是一個Spring容器,在不涉及WEB時使用方法和Spring沒有任何區別;ß
只有請求地址可以匹配到到被DispatcherServlet的url-pattern的請求才會被SpringMVC處理,那麼那些請求要交給SpringMVC處理呢,一般是除靜態資源之外的請求;
經常使用pattern:
pattern | 說明 |
---|---|
/ | 除了.jsp 之外的全部請求 |
/* | 全部請求 |
*.action | 全部 以action結尾的請求 |
須要說明的是action並非固定的不一樣公司可能不一樣,但不管是點什麼,其目的都是爲了和靜態資源加以區分
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 TestController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { ModelAndView modelAndView = new ModelAndView();//建立一個表示模型和視圖的對象 modelAndView.setViewName("index.jsp");//設置視圖名稱 modelAndView.addObject("msg","hello springMVC");//添加視圖須要的數據 //httpServletRequest.setAttribute("msg","hello SpringMVC"); //等同於上面一行 return modelAndView; //返回模型和視圖給dispatcherServlet } }
ModelAndView,其實就是把視圖資源和數據打包到一塊兒,而後視圖名稱交給視圖解析器,Object放到請求中;
springmvc.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 name="/testController" class="com.yh.controller.TestController"/> </beans>
DispatcherServlet是按照請求路徑來查找Handler,咱們必須告訴SpringMVC,這個控制器是用來處理哪一個請求地址的,默認狀況下,SpringMVC會查找beanName與請求地址相同的Handler來處理;
打開瀏覽器輸入地址:http://localhost:8080/MVC01_war_exploded/testController
咱們在Request中添加了key爲msg的字符內容hello SpringMVC
看到上述內容說明SpringMVC以及成功處理了請求;
上述方法每一個Controller只能處理一個請求地址,不夠靈活,且須要Controller實現指定接口,這是就須要使用註解來配置Controller了;
@Controller
該註解寫在類上,用於註冊控制器bean到容器中,這是以前以及學習過的
@RequestMapping("url")
該註解寫在方法上時,用於爲方法指定要匹配的url,該url是相對根路徑的
寫在類上時類上的url是相對於根路徑,而類中方法則相對於類的url
@Controller //@RequestMapping("/user") public class UserController { @RequestMapping("/getMsg") public ModelAndView getMsg(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("/index.jsp"); modelAndView.addObject("msg","hello SpringMVC annotation!"); return modelAndView; } }
請求地址:http://localhost:8080/MVC01_war_exploded/getMsg,可正常訪問
當把類上註釋的url打開時,上面的地址404了
正確地址:http://localhost:8080/MVC01_war_exploded/user/getMsg
須要注意的是:
viewName路徑若不帶/時則從當前請求的位置查找文件,帶/則表示從根路徑查找
咱們完成了一個簡單的入門案例,可是你會發現除了DispatcherServlet以外沒有出現其餘上面提到過的組件,那麼它們是否是沒有做用呢?
其實SpringMVC提供了不少默認配置,使咱們能夠快速的開項目,而無需繁瑣的配置,在SpringMVC的包下能夠找到一個DispatcherServlet.properties
配置,這即是默認的配置文件了;
RouterFunctionMapping和HandlerFunctionAdapter都是webFlux中的這裏很少關注;
HandlerMapping | 映射方式 |
---|---|
BeanNameUrlHandlerMapping | 用beanName做爲url |
RequestMappingHandlerMapping | 使用註解配置url |
HandlerAdapter | 處理對象: |
---|---|
HttpRequestHandlerAdapter | 實現HttpRequestHandler的處理器 |
SimpleControllerHandlerAdapter | 實現Controller的處理器 |
RequestMappingHandlerAdapter | 使用註解的handler,無需實現接口 |
SimpleServletHandlerAdapter | Servlet類Handler,需繼承HttpServlet |
SimpleServletHandlerAdapter
默認是沒有的,當須要使用Servlet相關API時使用,須要在配置文件中聲明
<bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/>
注意:當手動添加了適配器後,系統就不會自動添加任何其餘適配器了;
SimpleServletHandlerAdapter案例:
@Controller("/servletController") public class YouController extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().println("servlet API"); } }
請求地址:http://localhost:8080/MVC01_war_exploded/servletController,記得註冊Adapter到容器中;
在上述4中handler中最經常使用的是使用註解形式的;
視圖解析器用於查找視圖文件,及生成視圖對象,咱們不用過多關注,惟一會用到的就是,爲視圖名稱配置前綴和後綴從而簡化,Handler中的書寫
在一個實際項目中頁面文件可能比較多,能夠用文件夾管理,可是這致使咱們在編寫視圖名稱時更加繁瑣,例如:
handler中:
這時就可在配置中對視圖解析器進行相關設置;
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--指定視圖類型--> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> <!--指定前綴--> <property name="prefix" value="/pages/jsp/"/> <!--指定後綴--> <property name="suffix" value=".jsp"/> </bean>
處理器中:
@RequestMapping("/getMsg") public ModelAndView getMsg(){ ModelAndView modelAndView = new ModelAndView(); modelAndView.setViewName("index"); modelAndView.addObject("msg","hello SpringMVC annotation!"); return modelAndView; }
視圖解析器會自動在viewName先後分別拼接前綴和後綴;如:/pages/jsp/index.jsp
上面提到,SpringMVC默認會加載DispatcherServlet.properties
中的配置做爲默認配置,當咱們須要添加額外的自定義配置時該怎麼辦呢?這是咱們須要啓用MVC配置,經過在配置文件中添加如下標籤
<mvc:annotation-driven/>
爲了減小配置項,該標籤向容器中添加了提供MVC基礎服務的Bean,並添加了json,xml,的轉換器
有興趣能夠源碼位置:web包下的AnnotationDrivenBeanDefinitionParser,
此時看不出該標籤對系統有什麼影響,但在後續自定義驗證器,轉換器時就不得不使用到該標籤了
官方原話:
"in XML configuration, you can use the `<mvc:annotation-driven/>` element to enable MVC configuration, the preceding example registers a number of Spring MVC infrastructure beans and adapts to dependencies available on the classpath (for example, payload converters for JSON, XML, and others)"