SpringMVC 入門

SpringMVC 框架概述

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

構架圖:
image-20200206122121806spring

Spring-MVC在系統中的位置

image-20200206122121806

能夠看出apache

SpringMVC 並無代替Servlet,它只是在Servlet上提供了一套封裝好的組件,提升開發效率;編程

還使得開發出的項目更加規範;不然每一個人可能有每一個人不一樣的MVC;json

SpringMVC核心組件

思考:後端

若沒有SpringMVC框架,咱們該如何去編寫一個較大的web項目呢,能夠發如今選課系統中出現了大量的Servlet,由於一個請求地址就須要一個Servlet,使得項目體積變大,且Servlet是長期存在內存的;

第一步,咱們但願用一個Servlet來處理多個請求甚至是全部請求,就須要實現能根據請求路徑查找處理請求方法的邏輯,這也是SpringMVC要作的第一件事情;

  • DispatcherServlet:前端控制器
    用戶請求首先到達前端控制器,它就至關於mvc模式中的c,DispatcherServlet是整個流程控制的調度中心,由它調用其它組件處理用戶的請求,DispatcherServlet的存在下降了組件之間的耦合性。
  • Handler:處理器
    Handler是繼DispatcherServlet前端控制器的後端控制器,DispatcherServlet會將請求發送至對應的Handler來進行處理。Handler是處理業務邏輯的地方,須要咱們本身來編寫具體代碼,等同於以前的Service層
  • HandlerMapping:處理器映射器
    HandlerMapping負責根據用戶請求路徑找到Handler,springmvc提供了不一樣的映射器實現不一樣的映射方式,例如:BeanName映射,配置文件映射,註解映射等。
  • HandlAdapter:處理器適配器
    經過HandlerAdapter來執行Handler,由於Handler有不一樣形式,意味着調用方式是不一樣的,這是適配器模式的應用,咱們也能夠擴展適配器來實現新的Handler;
  • ViewResolver:視圖解析器
    ViewResolver負責從Handler中獲取數據和視圖,根據邏輯視名稱查找物理視圖文件,並查找View對象,再生成View對象;
  • View:視圖
    View的職責就是裝配數據,SpringMVC框架提供了不少的View視圖類型的支持,包括:jstlView、freemarkerView、pdfView等。經常使用視圖就是jsp。咱們須要根據業務需求,經過頁面標籤或頁面模版技術將模型數據展現給用戶

固然還有一些其餘的

類型 說明
HandlerExceptionResolver Handler異常處理器
LocaleResolver 提供國際化的視圖。根據不一樣地區顯示不一樣內容
ThemeResolver 根據不一樣地區提供個性化的佈局
MultipartResolver 解析multipart請求數據,如瀏覽器表單文件上傳
FlashMapManager 經常使用於經過重定向將屬性從一個請求傳遞到另外一個請求

請求處理流程簡述

入門程序

pom依賴

<?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.xml配置

與在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沒有任何區別;ß

url-pattern

只有請求地址可以匹配到到被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

image-20200206143953076

咱們在Request中添加了key爲msg的字符內容hello SpringMVC

看到上述內容說明SpringMVC以及成功處理了請求;

註解配置Controller

上述方法每一個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

啓用MVC 配置

上面提到,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)"
相關文章
相關標籤/搜索