Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 在线播放国产不卡免费视频,欧美日在线观看,国产精品久久久久影院

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          SpringMVC 02- SpringMVC響應(yīng)g

          SpringMVC 02: SpringMVC響應(yīng)get和post請(qǐng)求 + 5種獲取前端數(shù)據(jù)的方式

          應(yīng)get和post請(qǐng)求

          • SpringMVC中使用@RequestMapping注解完成對(duì)get請(qǐng)求和post請(qǐng)求的響應(yīng)
          • 項(xiàng)目結(jié)構(gòu)和配置文件與SpringMVC博客集中的"SpringMVC 01"保持一致
          • 在webapp/admin目錄下新建2個(gè)jsp文件,這兩個(gè)jsp文件分別作為相應(yīng)請(qǐng)求的響應(yīng)頁面
          • mainGet.jsp
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>mainGet.jsp</title>
          </head>
          <body>
          <h2>main......page.....get......</h2>
          </body>
          </html>
          
          • mainPost.jsp
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>mainPost.jsp</title>
          </head>
          <body>
          <h2>main......page.....post......</h2>
          </body>
          </html>
          
          • 新增控制器:ReqAction,在@RequestMapping注解后可以跟兩個(gè)參數(shù)
          • value參數(shù)負(fù)責(zé)對(duì)應(yīng)請(qǐng)求路徑,只有正確請(qǐng)求路徑下的目標(biāo)action方法,才可能被調(diào)用
          • method參數(shù)負(fù)責(zé)指定該action方法負(fù)責(zé)響應(yīng)的請(qǐng)求類型
          • 僅是請(qǐng)求路徑對(duì)應(yīng)上并不可以調(diào)用action方法,必須請(qǐng)求路徑和請(qǐng)求方式都對(duì)上,相應(yīng)的action方法才會(huì)被調(diào)用
          package com.example.controller;
          
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RequestMethod;
          
          @Controller
          public class ReqAction {
              @RequestMapping(value="/req", method=RequestMethod.GET)
              public String reqGet(){
                  System.out.println("獲取到get請(qǐng)求,服務(wù)器被訪問......");
                  return "mainGet";
              }
          
              @RequestMapping(value="/req", method=RequestMethod.POST)
              public String reqPost(){
                  System.out.println("獲取到post請(qǐng)求,服務(wù)器被訪問......");
                  return "mainPost";
              }
          }
          
          • webapp/index.jsp如下,以form表單的形式,分別發(fā)送get和post請(qǐng)求
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>index.jsp</title>
          </head>
          <body>
          <h2>分別用get和post方式訪問服務(wù)器</h2>
          <form action="${pageContext.request.contextPath}/req.action" method="get/post">
              <input type="submit" value="get/post方式提交">
          </form>
          </body>
          </html>
          
          • 部署并啟動(dòng)tomcat測試,第一次用表單發(fā)送get請(qǐng)求,第二次用表單發(fā)送post請(qǐng)求
          • 表單發(fā)送get請(qǐng)求時(shí),網(wǎng)站首頁(left),請(qǐng)求到的頁面(mild),控制臺(tái)輸出(right)如下

          • 表單發(fā)送post請(qǐng)求時(shí),網(wǎng)站首頁(left),請(qǐng)求到的頁面(mild),控制臺(tái)輸出(right)如下

          5種獲取前端數(shù)據(jù)的方式

          • 1.直接注入獲取
          • 2.實(shí)體類封裝獲取
          • 3.動(dòng)態(tài)占位符獲取
          • 4.@RequestParam注解方式獲取
          • 5.手工獲取數(shù)據(jù)
          • 在webapp/admin目錄下新建dataSubmit.jsp,作為5種請(qǐng)求方式的響應(yīng)結(jié)果頁面
          • dataSubmit.jsp
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>dataSubmit.jsp</title>
          </head>
          <body>
          <h2>dataSubmit.........page</h2>
          </body>
          </html>
          
          • webapp/index.jsp如下,是網(wǎng)站的首頁,包含5種請(qǐng)求方式的前端顯示
          <%@ page contentType="text/html;charset=UTF-8" language="java" %>
          <html>
          <head>
              <title>index.jsp</title>
          </head>
          <body>
              
          <h2>SpringMVC中獲取前端提交數(shù)據(jù)的5種方式</h2>
          <hr>
              
          <h2>方式1:單個(gè)數(shù)據(jù)的獲取方式</h2>
          <form action="${pageContext.request.contextPath}/dataSubmit/submit01.action" method="get">
              姓名:<input type="text" name="name"><br>
              年齡:<input type="text" name="age"><br>
              <input type="submit" value="提交">
          </form>
              
          <h2>方式2:封裝成實(shí)體類進(jìn)行獲取</h2>
          <form action="${pageContext.request.contextPath}/dataSubmit/submit02.action" method="get">
              姓名:<input type="text" name="name"><br>
              年齡:<input type="text" name="age"><br>
              <input type="submit" value="提交">
          </form>
              
          <h2>方式3:動(dòng)態(tài)占位符獲取提交的數(shù)據(jù)(只可以用在超鏈接或地址欄)</h2>
          <!-- 攜帶的數(shù)據(jù)放在.action之前,用斜杠分隔開-->
          <a href="${pageContext.request.contextPath}/dataSubmit/submit03/xun/22.action">動(dòng)態(tài)占位符獲取提交數(shù)據(jù)</a>
              
          <h2>方式4:參數(shù)名稱不一致時(shí)接收數(shù)據(jù)</h2>
          <form action="${pageContext.request.contextPath}/dataSubmit/submit04.action" method="get">
              姓名:<input type="text" name="name"><br>
              年齡:<input type="text" name="age"><br>
              <input type="submit" value="提交">
          </form>
              
          <h2>方式5:手工獲取前端提交的數(shù)據(jù)</h2>
          <form action="${pageContext.request.contextPath}/dataSubmit/submit05.action" method="get">
              姓名:<input type="text" name="name"><br>
              年齡:<input type="text" name="age"><br>
              <input type="submit" value="提交">
          </form>
          </body>
          </html>
          
          • 新增SpringMVC控制器:DataSubmit,含有對(duì)前端5種請(qǐng)求方式的5種響應(yīng)處理
          package com.example.controller;
          
          import com.example.pojo.User;
          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.PathVariable;
          import org.springframework.web.bind.annotation.RequestMapping;
          import org.springframework.web.bind.annotation.RequestParam;
          
          import javax.servlet.http.HttpServletRequest;
          
          @Controller
          @RequestMapping("/dataSubmit")
          public class DataSubmit {
          
              //直接注入獲取
              @RequestMapping("/submit01")
              public String dataSubmit01(String name, int age){//前端提交的數(shù)據(jù),通過SpringMVC框架依次分別注入到目標(biāo)方法的參數(shù)中,且自動(dòng)完成了類型轉(zhuǎn)換
                  System.out.println("姓名: " + name + " 年齡: " + age);
                  return "dataSubmit";
              }
          
              //封裝成實(shí)體類來獲取
              @RequestMapping("/submit02")
              public String dataSubmit02(User user){//SpringMVC自動(dòng)創(chuàng)建實(shí)體類對(duì)象,并將前端提交的數(shù)據(jù),注入到User實(shí)體類中的對(duì)應(yīng)屬性中
                  System.out.println(user);
                  return "dataSubmit";
              }
          
              //動(dòng)態(tài)占位符獲取數(shù)據(jù)
              @RequestMapping("/submit03/{name}/{age}")//目標(biāo)路徑后用大括號(hào)接住前端隨著地址攜帶來的數(shù)據(jù),括號(hào)用斜杠分割開,括號(hào)內(nèi)名稱和@PathVariable后面的注解名一致,將攜帶的數(shù)據(jù)注入給目標(biāo)方法中的對(duì)應(yīng)變量
              public String dataSubmit03(
                      @PathVariable("name")
                      String name,
                      @PathVariable("age")
                      int age){
                  System.out.println("姓名: " + name + " 年齡: " + age);
                  return "dataSubmit";
              }
          
              //參數(shù)名稱不一致時(shí)獲取數(shù)據(jù)
              @RequestMapping("/submit04")
              public String dataSubmit04(
                      @RequestParam("name")//若前端數(shù)據(jù)名和后端變量名不一致,則可以將@RequestParam注解名和前端傳來的數(shù)據(jù)名稱保持一致,這樣將前端數(shù)據(jù)傳給注解標(biāo)識(shí)的變量
                      String uname,
                      @RequestParam("age")
                      int uage){
                  System.out.println("姓名: " + uname + " 年齡: " + uage);
                  return "dataSubmit";
              }
          
              //手工獲取前端提交的數(shù)據(jù)
              @RequestMapping("/submit05")
              public String dataSubmit05(HttpServletRequest request){//就是傳統(tǒng)servlet開發(fā)時(shí)獲取前端數(shù)據(jù)的方式,只不過這里HttpServletRequest實(shí)例對(duì)象由SpringMVC框架自動(dòng)創(chuàng)建
                  String name=request.getParameter("name");
                  int age=Integer.parseInt(request.getParameter("age"));
                  System.out.println("姓名: " + name + " 年齡: " + age);
                  return "dataSubmit";
              }
          }
          
          • 部署tomcat,并啟動(dòng)測試
          • 前端頁面,一次輸入數(shù)據(jù),提交測試即可

          • 測試結(jié)果不再贅述

          學(xué)了一遍SpringMVC以后,想著做一個(gè)總結(jié),復(fù)習(xí)一下。復(fù)習(xí)寫下面的總結(jié)的時(shí)候才發(fā)現(xiàn),其實(shí)自己學(xué)得并不徹底、牢固、也沒有學(xué)全,視頻跟書本是要結(jié)合起來一起,每一位老師的視頻可能提到的東西都不一致,也導(dǎo)致也不是很全面,書本上會(huì)講的筆記系統(tǒng)、全面。同時(shí)我自己也是一個(gè)初學(xué)者,下面總結(jié)的可能并不完善、正確,希望看到的大神給我指出,在此非常感謝。


          目錄

          • SpringMVC流程及源碼分析
          • 一 、Spring核心模塊
            • 1、核心模塊
            • 2、Spring版本命名規(guī)則(補(bǔ)充)
          • 二、SpringMVC流程及原理
            • 1、執(zhí)行流程
              • 1.1、執(zhí)行流程
              • 1.2、執(zhí)行流程說明:
                • 1.2.1、第02、03說明
                • 1.2.2、第04說明
                • 1.2.2、SpringMVC組件說明
                • 1.2.3、SpringMVC詳細(xì)流程圖
          • 二、源碼分析
            • 1、初始化
              • 1.1、ApplicationContext
            • 2、前端控制器(中央處理器)DistepcherServlet
              • 2.1、查找處理器映射器HandlerMapping
              • 2.2、根據(jù)處理器映射器HandlerMapping返回結(jié)果調(diào)用處理器適配器HandlerAdapter
              • 2.3、檢查攔截器Interceptor
              • 2.3、處理器適配器HandlerAdapter執(zhí)行Handler(Controller)返回ModelAndView
              • 2.4、視圖解析器ViewResolver
              • 2.5、視圖View
                • 2.5.1、視圖對(duì)象的作用
                • 2.5.2、View接口圖
                • 2.5.3、View的實(shí)現(xiàn)類圖
                • 2.5.4、View的UML圖
                • 2.5.5、常用的View視圖類
              • 2.6、其他重要的點(diǎn)
                • 2.6.1、DispatcherServlet.properties
          • 三、引用參考資料
            • 1、引用資料
            • 2、參考資料

          一 、Spring核心模塊

          1、核心模塊

          Spring Web MVC (下文簡稱為 SpringMVC )是 Spring 提供 Web 應(yīng)用的框架設(shè)計(jì),屬于表現(xiàn)層的框架。SpringMVC是Spring框架的一部分。
          Spring框架包括大致六大模塊,核心容器(Core Container)、AOP和設(shè)備支持、數(shù)據(jù)訪問及集成、Web、報(bào)文發(fā)送、Test

          圖片來源于Spring官網(wǎng)5.0.0.M5:

          ? https://docs.spring.io/spring-framework/docs/5.0.0.M5/spring-framework-reference/html/overview.html#overview-modules

          對(duì)于Spring5模塊圖,有2點(diǎn)疑問:
          1、不清楚為什么在Spring官網(wǎng)上5.0版本以后,Release版(穩(wěn)定版)的都未找到模塊圖,但是在M(里程碑版)版找到 了,如果有人在5.0以后的Release版(穩(wěn)定版)找到,麻煩給我留個(gè)言,謝謝。
          2、在其他博文中看到Spring5模塊結(jié)構(gòu)圖是這樣的:

          挺奇怪這個(gè)圖是哪里來的?(路過的大神請(qǐng)指點(diǎn))

          對(duì)于問題2,我在Spring5.2.13.RELEASE GA中,找到了如下所示信息:

          拷貝以上信息:

          Spring Framework Documentation

          Version 5.2.13.RELEASE

          What’s New, Upgrade Notes, Supported Versions, and other topics, independent of release cadence, are maintained externally on the project’s Github Wiki.

          Overview

          history, design philosophy, feedback, getting started.

          Core

          IoC Container, Events, Resources, i18n, Validation, Data Binding, Type Conversion, SpEL, AOP.

          Testing

          Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient.

          Data Access

          Transactions, DAO Support, JDBC, O/R Mapping, XML Marshalling.

          Web Servlet

          Spring MVC, WebSocket, SockJS, STOMP Messaging.

          Web Reactive

          Spring WebFlux, WebClient, WebSocket.

          Integration

          Remoting, JMS, JCA, JMX, Email, Tasks, Scheduling, Caching.

          Languages

          Kotlin, Groovy, Dynamic Languages.

          按照以上信息的Web Servlet、Web Reactive已經(jīng)是分屬于不同的模塊了。

          • Web Servlet:Spring MVC, WebSocket, SockJS, STOMP Messaging.
          • Web Reactive:Spring WebFlux, WebClient, WebSocket.

          Spring官方文檔:https://spring.io/projects/spring-framework#learn/

          2、Spring版本命名規(guī)則(補(bǔ)充)

          上面提到了Spring有不同的版本,在此記錄一下各個(gè)版本的意義。

          描述方式

          說明

          含義

          Snapshot

          快照版

          尚不穩(wěn)定,仍處于開發(fā)中的版本

          Release

          穩(wěn)定版

          功能相對(duì)穩(wěn)定,可以對(duì)外發(fā)行,但有時(shí)間限制

          GA

          正式版

          代表廣泛可用的穩(wěn)定版(General Availability)

          M

          里程碑版

          (M是Milestone的意思)具有一些全新的功能或是有意義的版本

          RC

          終測版

          Release Candidate(最終測試),即將作為正式版發(fā)布

          二、SpringMVC流程及原理

          1、執(zhí)行流程

          SpringMVC執(zhí)行流程圖

          圖片來源:三、引用參考資料

          1.1、執(zhí)行流程

          • 01、用戶發(fā)送出請(qǐng)求到前端控制器(中央處理器)DispatcherServlet進(jìn)行處理。
          • 02、前端控制器DispatcherServlet收到請(qǐng)求后,調(diào)用處理器映射器HandlerMapping。
          • 03、處理器映射器HandlerMapping(處理器映射器)根據(jù)request請(qǐng)求的URL等信息查找能夠進(jìn)行處理的Handler,以及相關(guān)攔截器interceptor,并構(gòu)造HandlerExecutionChain執(zhí)行鏈,然后將構(gòu)造好的HandlerExecutionChain執(zhí)行鏈對(duì)象返回給前端控制器DispatcherServlet。
          • 04、前端控制器DispatcherServlet根據(jù)處理器映射器HandlerMapping的
          • 05、處理器適配器HandlerAdapter經(jīng)過適配調(diào)用具體的處理器(Handler/Controller),即業(yè)務(wù)中自己寫的Controller。
          • 06、Controller處理完后返回ModelAndView(springmvc的封裝對(duì)象,將model和view封裝在一起)給處理器適配器HandlerAdapter;
          • 07、處理器適配器HandlerAdapter將Controller執(zhí)行結(jié)果ModelAndView返回給前端控制器DispatcherServlet。
          • 08、前端控制器DispatcherServlet調(diào)用視圖解析器ViewReslover處理ModelAndView。
          • 09、視圖解析器ViewReslover解析后根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址,生成并返回具體對(duì)象View(springmvc封裝對(duì)象,是一個(gè)接口)。
          • 10、前端控制器DispatcherServlet根據(jù)對(duì)象View進(jìn)行視圖渲染,填充Model。
          • 11、前端控制器DispatcherServlet向用戶返回響應(yīng)

          1.2、執(zhí)行流程說明:

          1.2.1、第02、03說明

          (1) 處理器映射器:springmvc框架中的一種對(duì)象,框架把實(shí)現(xiàn)了HandlerMapping接口的類都叫做映射器(多個(gè));

          (2) 處理器映射器作用:根據(jù)請(qǐng)求,從springmvc容器對(duì)象中獲取處理器對(duì)象(MyController controller=ctx.getBean("some")

          (3) 框架把找到的處理器對(duì)象放到一個(gè)叫做處理器執(zhí)行鏈(HandlerExecutionChain)的類保存

          (4) HandlerExecutionchain:類中保存著
          ?a:處理器對(duì)象(MyController);
          ?b:項(xiàng)目中的所有的攔截器List

          (5) 方法調(diào)用:HandlerExecutionChain mappedHandler - getHandler (processedRequest);

          1.2.2、第04說明

          (1) HandlerExecutionChain執(zhí)行鏈找到對(duì)應(yīng)的處理器映射器HandlerAdapter。
          (2) 處理器適配器:springmvc框架中的對(duì)象,需要實(shí)現(xiàn)HandlerAdapter接口,
          (3) 處理器適配器作用:執(zhí)行處理器方法(調(diào)用MyController.doSome()得到返回值ModelAndView )
          (4) 前端控制器中調(diào)用適配器:HandlerAdapter ha=getHandlerAdapter (mappedHandler.getHandler());
          (5) 執(zhí)行處理器方法:mv=ha.handle (processedRequest, response, mappedHandler.getHandler());

          第08說明:
          (1) 視圖解析器:springmvc中的對(duì)象,需要實(shí)現(xiàn)ViewResoler接口(可以有多個(gè))
          (2) 視圖解析器作用:組成視圖完整路徑,使用前綴,后綴。并創(chuàng)建View對(duì)象。
          (3) view是一個(gè)接口,表示視圖的,在框架中jsp,htm1不是string表示,而是使用view和他的實(shí)現(xiàn)類表示視圖。

          InternalResourceview:視圖類,表示jsp文件,視圖解析器會(huì)創(chuàng)建InternalResourceView類對(duì)象。 這個(gè)對(duì)象的里面,有一個(gè)屬性u(píng)rl-/WEB-INF/view/show.jsp

          1.2.2、SpringMVC組件說明

          • (1). 前端控制器(DispatcherServlet):接收請(qǐng)求,響應(yīng)結(jié)果,相當(dāng)于電腦的CPU。
          • (2). 處理器映射器(HandlerMapping):根據(jù)URL去查找處理器.
          • (3). 處理器(Handler):(需要程序員去寫代碼處理邏輯的).
          • (4). 處理器適配器(HandlerAdapter):會(huì)把處理器包裝成適配器,這樣就可以支持多種類型的處理器,類比筆記本的適配器(適配器模式的應(yīng)用).
          • (5). 視圖解析器(ViewResovler):進(jìn)行視圖解析,多返回的字符串,進(jìn)行處理,可以解析成對(duì)應(yīng)的頁面.

          1.2.3、SpringMVC詳細(xì)流程圖

          綜上所述,總結(jié)下SpringMVC的詳細(xì)流程圖:


          圖片來源:三、引用參考資料

          二、源碼分析

          以下源碼來源jar包:spring-webmvc-5.25.RELEASE.jar

          1、初始化

          1.1、ApplicationContext

          ? ApplicationContext初始化入口類:ApplicationObjectSupport的setApplicationContext方法,setApplicationContext方法中核心部分就是初始化容器initApplicationContext(context),子類AbstractDetectingUrlHandlerMapping實(shí)現(xiàn)了該方法。
          類圖:


          UML圖:


          ? RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping來定義controller.
          初始化時(shí),3個(gè)類的大致分工如下:

          • AbstractHandlerMethodMapping定義整個(gè)算法流程;
          • RequestMappingInfoHandlerMapping提供匹配條件RequestMappingInfo的解析處理;
          • RequestMappingHandlerMapping根據(jù)@RequestMapping注解生成 RequestMappingInfo,同時(shí)提供isHandler實(shí)現(xiàn)

          2、前端控制器(中央處理器)DistepcherServlet

          ? 從上面的流程圖可以看到前端控制器(中央處理器)DistepcherServlet是SpringMVC核心,查看DistepcherServlet類的繼承情況。
          UML圖:
          ![2021022601-08-DispatcherServlet UML圖](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-08-DispatcherServlet UML圖.png)
          從繼承關(guān)系看出:
          ? DistepcherServlet ---> FrameworkServlet ---> HttpServletBean---> HttpServlet
          ? 那就說明DistepcherServlet 類也是一個(gè)Servlet類,那最終核心的方法就是service()方法,即Servlet的核心方法。
          ? 那就找service()方法,在DistepcherServlet中沒有servic()方法,在父類FrameworkServlet有service()方法,源碼如下:
          來源:

          org.springframework.web.servlet.FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)

          /**
          	 * Override the parent class implementation in order to intercept PATCH requests.
          	 */
          	@Override
          	protected void service(HttpServletRequest request, HttpServletResponse response)
          			throws ServletException, IOException {
          		HttpMethod httpMethod=HttpMethod.resolve(request.getMethod());
          		if (httpMethod==HttpMethod.PATCH || httpMethod==null) {
          			processRequest(request, response);
          		}
          		else {
          			super.service(request, response);
          		}
          	}
          

          可以看到:
          FrameworkServlet.service(HttpServletRequest request, HttpServletResponse response)拿到request請(qǐng)求,判斷當(dāng)前請(qǐng)求是否是PATCH請(qǐng)求,不是的就調(diào)用父類的servic()方法,調(diào)用父類中的service方法就是去調(diào)用該類中doPost(),doGet()方法,根據(jù)不同的請(qǐng)求方式然后走doPost()或者doGet(),調(diào)用中以doGet()為例,
          FrameworkServlet類的doGet()源碼:

          /**
          	 * Delegate GET requests to processRequest/doService.
          	 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
          	 * with a {@code NoBodyResponse} that just captures the content length.
          	 * @see #doService
          	 * @see #doHead
          	 */
          	@Override
          	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
          			throws ServletException, IOException {
          		processRequest(request, response);
          	}
          

          ? doGet()又調(diào)用FrameworkServlet類中的processRequest(request, response);

          /**
          	 * Process this request, publishing an event regardless of the outcome.
          	 * <p>The actual event handling is performed by the abstract
          	 * {@link #doService} template method.
          	 */
          	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
          			throws ServletException, IOException {
          
          		long startTime=System.currentTimeMillis();
          		Throwable failureCause=null;
          
          		LocaleContext previousLocaleContext=LocaleContextHolder.getLocaleContext();
          		LocaleContext localeContext=buildLocaleContext(request);
          
          		RequestAttributes previousAttributes=RequestContextHolder.getRequestAttributes();
          		ServletRequestAttributes requestAttributes=buildRequestAttributes(request, response, previousAttributes);
          
          		WebAsyncManager asyncManager=WebAsyncUtils.getAsyncManager(request);
          		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
          
          		initContextHolders(request, localeContext, requestAttributes);
          
          		try {
          			doService(request, response);
          		}
          		catch (ServletException | IOException ex) {
          			failureCause=ex;
          			throw ex;
          		}
          		catch (Throwable ex) {
          			failureCause=ex;
          			throw new NestedServletException("Request processing failed", ex);
          		}
          
          		finally {
          			resetContextHolders(request, previousLocaleContext, previousAttributes);
          			if (requestAttributes !=null) {
          				requestAttributes.requestCompleted();
          			}
          			logResult(request, response, failureCause, asyncManager);
          			publishRequestHandledEvent(request, response, startTime, failureCause);
          		}
          	}
          

          ? processRequest(request, response)方法中最關(guān)鍵的又調(diào)用了doService(request, response);查看FrameworkServlet類中的doService(request, response),或者是調(diào)試跟蹤可知,doService(request, response)由子類DispatcherServlet實(shí)現(xiàn)。

          源碼來源:

          org.springframework.web.servlet.FrameworkServlet.doService(HttpServletRequest request, HttpServletResponse response)

          /**
          	 * Subclasses must implement this method to do the work of request handling,
          	 * receiving a centralized callback for GET, POST, PUT and DELETE.
          	 * <p>The contract is essentially the same as that for the commonly overridden
          	 * {@code doGet} or {@code doPost} methods of HttpServlet.
          	 * <p>This class intercepts calls to ensure that exception handling and
          	 * event publication takes place.
          	 * @param request current HTTP request
          	 * @param response current HTTP response
          	 * @throws Exception in case of any kind of processing failure
          	 * @see javax.servlet.http.HttpServlet#doGet
          	 * @see javax.servlet.http.HttpServlet#doPost
          	 */
          	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
          			throws Exception;
          

          ? 查看DispatcherServlet中的doService(HttpServletRequest request, HttpServletResponse response)方法

          /**
          	 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
          	 * for the actual dispatching.
          	 */
          	@Override
          	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
          		logRequest(request);
          
          		// Keep a snapshot of the request attributes in case of an include,
          		// to be able to restore the original attributes after the include.
          		Map<String, Object> attributesSnapshot=null;
          		if (WebUtils.isIncludeRequest(request)) {
          			attributesSnapshot=new HashMap<>();
          			Enumeration<?> attrNames=request.getAttributeNames();
          			while (attrNames.hasMoreElements()) {
          				String attrName=(String) attrNames.nextElement();
          				if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
          					attributesSnapshot.put(attrName, request.getAttribute(attrName));
          				}
          			}
          		}
          
          		// Make framework objects available to handlers and view objects.
          		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
          		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
          		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
          		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
          
          		if (this.flashMapManager !=null) {
          			FlashMap inputFlashMap=this.flashMapManager.retrieveAndUpdate(request, response);
          			if (inputFlashMap !=null) {
          				request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
          			}
          			request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
          			request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
          		}
          
          		try {
          			doDispatch(request, response);
          		}
          		finally {
          			if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
          				// Restore the original attribute snapshot, in case of an include.
          				if (attributesSnapshot !=null) {
          					restoreAttributesAfterInclude(request, attributesSnapshot);
          				}
          			}
          		}
          	}
          

          ? DispatcherServlet的doService()方法中最終調(diào)用doDispatch(request, response),查看源碼如下:
          org.springframework.web.servlet.DispatcherServlet.doDispatch()

          /**
          	 * Process the actual dispatching to the handler.
          	 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
          	 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
          	 * to find the first that supports the handler class.
          	 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
          	 * themselves to decide which methods are acceptable.
          	 * @param request current HTTP request
          	 * @param response current HTTP response
          	 * @throws Exception in case of any kind of processing failure
          	 */
          	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
          		HttpServletRequest processedRequest=request;
          		HandlerExecutionChain mappedHandler=null;
          		boolean multipartRequestParsed=false;
          
          		WebAsyncManager asyncManager=WebAsyncUtils.getAsyncManager(request);
          
          		try {
          			ModelAndView mv=null;
          			Exception dispatchException=null;
          
          			try {
          				// 文件上傳相關(guān),判斷是不是二進(jìn)制請(qǐng)求
          				processedRequest=checkMultipart(request);
          				multipartRequestParsed=(processedRequest !=request);
          				// 取得處理當(dāng)前請(qǐng)求的controller,這里也稱為hanlder處理器,第一個(gè)步驟的意義就在這里體現(xiàn)了.這里并不是直接返回controller,而是返回的HandlerExecutionChain請(qǐng)求處理器鏈對(duì)象,該對(duì)象封裝了handler和攔截器interceptors.
          				// Determine handler for the current request.
          				mappedHandler=getHandler(processedRequest);
          				// 如果handler為空,則返回404
          				if (mappedHandler==null) {
          					noHandlerFound(processedRequest, response);
          					return;
          				}
          				//3. 獲取處理request的處理器適配器HandlerAdapter
          				// Determine handler adapter for the current request.
          				HandlerAdapter ha=getHandlerAdapter(mappedHandler.getHandler());
          
          				// Process last-modified header, if supported by the handler.
          				String method=request.getMethod();
          				boolean isGet="GET".equals(method);
          				if (isGet || "HEAD".equals(method)) {
          					long lastModified=ha.getLastModified(request, mappedHandler.getHandler());
          					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
          						return;
          					}
          				}
          				//處理器適配器執(zhí)行之前,檢查攔截器的方法
          				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          					return;
          				}
          				//處理器適配器根據(jù)找到,執(zhí)行handler,返回ModelAndView
          				// Actually invoke the handler.
          				mv=ha.handle(processedRequest, response, mappedHandler.getHandler());
          
          				if (asyncManager.isConcurrentHandlingStarted()) {
          					return;
          				}
          
          				applyDefaultViewName(processedRequest, mv);
          				mappedHandler.applyPostHandle(processedRequest, response, mv);
          			}
          			catch (Exception ex) {
          				dispatchException=ex;
          			}
          			catch (Throwable err) {
          				// As of 4.3, we're processing Errors thrown from handler methods as well,
          				// making them available for @ExceptionHandler methods and other scenarios.
          				dispatchException=new NestedServletException("Handler dispatch failed", err);
          			}
          			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
          		}
          		catch (Exception ex) {
          			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
          		}
          		catch (Throwable err) {
          			triggerAfterCompletion(processedRequest, response, mappedHandler,
          					new NestedServletException("Handler processing failed", err));
          		}
          		finally {
          			if (asyncManager.isConcurrentHandlingStarted()) {
          				// Instead of postHandle and afterCompletion
          				if (mappedHandler !=null) {
          					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
          				}
          			}
          			else {
          				// Clean up any resources used by a multipart request.
          				if (multipartRequestParsed) {
          					cleanupMultipart(processedRequest);
          				}
          			}
          		}
          	}
          

          ? 可以看出doDispatch()就是SpringMVC的核心代碼了,分析doDispatch():

          2.1、查找處理器映射器HandlerMapping

          ? 首先看下處理器映射器HandlerMapping類圖:

          doDispatch()關(guān)鍵代碼:

          HandlerExecutionChain mappedHandler=null;
          
          mappedHandler=getHandler(processedRequest);
          

          ? mappedHandler是一個(gè)執(zhí)行鏈HandlerExecutionChain 對(duì)象,這里封裝了handler和攔截器interceptors,getHandler(processedRequest)方法就是從處理器映射器HandlerMapping中找到url和controller的對(duì)應(yīng)關(guān)系,并返回給前端控制器DispatchServlet。
          查看getHandler(processedRequest);源碼:

          /**
          	 * Return the HandlerExecutionChain for this request.
          	 * <p>Tries all handler mappings in order.
          	 * @param request current HTTP request
          	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
          	 */
          	@Nullable
          	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
          		if (this.handlerMappings !=null) {
          			for (HandlerMapping mapping : this.handlerMappings) {
          				HandlerExecutionChain handler=mapping.getHandler(request);
          				if (handler !=null) {
          					return handler;
          				}
          			}
          		}
          		return null;
          	}
          

          調(diào)試代碼如下:


          從代碼調(diào)試中可以看到handlerMapping中有三個(gè)對(duì)象:

          this.handlerMappings={ArrayList@4662}  size=3
           0={BeanNameUrlHandlerMapping@4791} 
           1={RequestMappingHandlerMapping@4792} 
           2={RouterFunctionMapping@4793} 
          
          • BeanNameUrlHandlerMapping:初始化時(shí)會(huì)將urlpath做映射存儲(chǔ)(xml);
          • RequestMappingHandlerMapping:初始化時(shí)會(huì)將Controller中配置@RequestMapping注解的方法做映射存儲(chǔ)(注解);
          • RouterFunctionMapping:
            (這個(gè)對(duì)象不是太理解)
            這也就是為什么要去HandlerMapping找一個(gè)Handler了,因?yàn)樘幚砥饔成淦鱄andlerMapping有不同的實(shí)現(xiàn):
          • 1、xml方式
          • 2、注解方式

          接著看getHandler(HttpServletRequest request)方法,先遍歷HandlerMappers,查找控制器找到之后就返回執(zhí)行鏈HandlerExecutionChain類型的Handler。

          可以看到返回的Handler中,拿到的就是我們自己編碼的Controller類,以及攔截器(演示項(xiàng)目中未編寫,所以調(diào)試匯總返回的Handler最后是0 interceptors)
          HandlerExecutionChain with [com.bjpowernode.controller.MyController#doSome()] and 0 interceptors


          將正在調(diào)試的idea打開自己編寫的Controller來對(duì)照,發(fā)現(xiàn)一致:

          2.2、根據(jù)處理器映射器HandlerMapping返回結(jié)果調(diào)用處理器適配器HandlerAdapter

          doDispatch()里面的關(guān)鍵代碼:

          HandlerAdapter ha=getHandlerAdapter(mappedHandler.getHandler());
          

          源碼如下:

          /**
          	 * Return the HandlerAdapter for this handler object.
          	 * @param handler the handler object to find an adapter for
          	 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
          	 */
          	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
          		if (this.handlerAdapters !=null) {
          			for (HandlerAdapter adapter : this.handlerAdapters) {
          				if (adapter.supports(handler)) {
          					return adapter;
          				}
          			}
          		}
          		throw new ServletException("No adapter for handler [" + handler +
          				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
          	}
          

          為什么還要獲取處理器適配器HandlerAdapter:與獲取處理器映射器HandlerMapping一樣,Spring提供了不通的處理器適配器。
          調(diào)試如下:


          查看DEBUG調(diào)試模式中g(shù)etHandlerAdapter()方法在中的:
          handler、adapter、this.handlerAdapters


          以下是拷貝的結(jié)果:
          handler

          handler={HandlerMethod@4792} "com.bjpowernode.controller.MyController#doSome()"
           logger={LogAdapter$JavaUtilLog@4858} 
           bean={MyController@4859} 
           beanFactory={DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
           beanType={Class@3782} "class com.bjpowernode.controller.MyController"
           method={Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
           bridgedMethod={Method@4860} "public org.springframework.web.servlet.ModelAndView com.bjpowernode.controller.MyController.doSome()"
           parameters={MethodParameter[0]@4861} 
           responseStatus=null
           responseStatusReason=null
           resolvedFromHandlerMethod={HandlerMethod@4863} "com.bjpowernode.controller.MyController#doSome()"
           interfaceParameterAnnotations=null
           description="com.bjpowernode.controller.MyController#doSome()"
          

          adapter

          adapter={RequestMappingHandlerAdapter@4827} 
           customArgumentResolvers=null
           argumentResolvers={HandlerMethodArgumentResolverComposite@4833} 
           initBinderArgumentResolvers={HandlerMethodArgumentResolverComposite@4834} 
           customReturnValueHandlers=null
           returnValueHandlers={HandlerMethodReturnValueHandlerComposite@4835} 
           modelAndViewResolvers=null
           contentNegotiationManager={ContentNegotiationManager@4836} 
           messageConverters={ArrayList@4837}  size=4
           requestResponseBodyAdvice={ArrayList@4838}  size=0
           webBindingInitializer=null
           taskExecutor={SimpleAsyncTaskExecutor@4839} 
           asyncRequestTimeout=null
           callableInterceptors={CallableProcessingInterceptor[0]@4840} 
           deferredResultInterceptors={DeferredResultProcessingInterceptor[0]@4842} 
           reactiveAdapterRegistry={ReactiveAdapterRegistry@4844} 
           ignoreDefaultModelOnRedirect=false
           cacheSecondsForSessionAttributeHandlers=0
           synchronizeOnSession=false
           sessionAttributeStore={DefaultSessionAttributeStore@4845} 
           parameterNameDiscoverer={DefaultParameterNameDiscoverer@4846} 
           beanFactory={DefaultListableBeanFactory@4847} "org.springframework.beans.factory.support.DefaultListableBeanFactory@56b5a4c3: defining beans [myController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,org.springframework.web.servlet.view.InternalResourceViewResolver#0]; root of factory hierarchy"
           sessionAttributesHandlerCache={ConcurrentHashMap@4848}  size=0
           initBinderCache={ConcurrentHashMap@4849}  size=0
           initBinderAdviceCache={LinkedHashMap@4850}  size=0
           modelAttributeCache={ConcurrentHashMap@4851}  size=0
           modelAttributeAdviceCache={LinkedHashMap@4852}  size=0
           order=2147483647
           supportedMethods=null
           allowHeader="GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS"
           requireSession=false
           cacheControl=null
           cacheSeconds=-1
           varyByRequestHeaders=null
           useExpiresHeader=false
           useCacheControlHeader=true
           useCacheControlNoStore=true
           alwaysMustRevalidate=false
           servletContext={ApplicationContextFacade@4754} 
           logger={LogAdapter$JavaUtilLog@4854} 
           applicationContext={XmlWebApplicationContext@4665} "WebApplicationContext for namespace 'myweb-servlet', started on Tue Mar 02 23:25:35 CST 2021"
           messageSourceAccessor={MessageSourceAccessor@4855} 
          

          this.handlerAdapters

          this.handlerAdapters={ArrayList@4658}  size=4
           0={HttpRequestHandlerAdapter@4810} 
           1={SimpleControllerHandlerAdapter@4820} //XML方式
           2={RequestMappingHandlerAdapter@4827} //注解方式
           3={HandlerFunctionAdapter@4832} 
          

          可以看到找到4個(gè)處理器適配器。通過DEBUG模式可以看到,此次取到的處理器適配器HandlerAdapter是:RequestMappingHandlerAdapter

          ha={RequestMappingHandlerAdapter@4827} 
          

          2.3、檢查攔截器Interceptor

          doDispatch()中的關(guān)鍵代碼:

          if (!mappedHandler.applyPreHandle(processedRequest, response)) {
          					return;
          				}
          org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle
          

          applyPreHandle(processedRequest, response)源碼:

          /**
          	 * Apply preHandle methods of registered interceptors.
          	 * @return {@code true} if the execution chain should proceed with the
          	 * next interceptor or the handler itself. Else, DispatcherServlet assumes
          	 * that this interceptor has already dealt with the response itself.
          	 */
          	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
          		HandlerInterceptor[] interceptors=getInterceptors();
          		if (!ObjectUtils.isEmpty(interceptors)) {
          			for (int i=0; i < interceptors.length; i++) {
          				HandlerInterceptor interceptor=interceptors[i];
          				if (!interceptor.preHandle(request, response, this.handler)) {
          					triggerAfterCompletion(request, response, null);
          					return false;
          				}
          				this.interceptorIndex=i;
          			}
          		}
          		return true;
          	}
          

          2.3、處理器適配器HandlerAdapter執(zhí)行Handler(Controller)返回ModelAndView

          doDispatch()中的關(guān)鍵代碼:

          mv=ha.handle(processedRequest, response, mappedHandler.getHandler());
          

          DEBUG模式調(diào)試,是調(diào)到了:
          org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle
          源碼如下:

          /**
          	 * This implementation expects the handler to be an {@link HandlerMethod}.
          	 */
          	@Override
          	@Nullable
          	public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
          			throws Exception {
          
          		return handleInternal(request, response, (HandlerMethod) handler);
          	}
          

          再往下看handleInternal(request, response, (HandlerMethod) handler)方法,
          org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

          @Override
          	protected ModelAndView handleInternal(HttpServletRequest request,
          			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
          
          		ModelAndView mav;
          		checkRequest(request);
          
          		// Execute invokeHandlerMethod in synchronized block if required.
          		if (this.synchronizeOnSession) {
          			HttpSession session=request.getSession(false);
          			if (session !=null) {
          				Object mutex=WebUtils.getSessionMutex(session);
          				synchronized (mutex) {
          					mav=invokeHandlerMethod(request, response, handlerMethod);
          				}
          			}
          			else {
          				// No HttpSession available -> no mutex necessary
          				mav=invokeHandlerMethod(request, response, handlerMethod);
          			}
          		}
          		else {
          			// No synchronization on session demanded at all...
          			mav=invokeHandlerMethod(request, response, handlerMethod);
          		}
          
          		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
          			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
          				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
          			}
          			else {
          				prepareResponse(response);
          			}
          		}
          
          		return mav;
          	}
          

          注意,handleInternal(request, response, (HandlerMethod) handler)方法的返回值是ModelAndView ,這里就完成了處理器適配器HandlerAdapter執(zhí)行Handler(Controller)并將結(jié)果ModelAndView返回給前端控制器DistepchServlet

          2.4、視圖解析器ViewResolver

          ??接上2.3:前端控制器DistepchServlet接收到處理器適配器HandlerAdapter返回的ModelAndView以后,這里分2種情況:

          • (1)、如果ModelAndView里面是邏輯視圖
            前端控制器DistepchServlet調(diào)用視圖解析器ViewResolver通過邏輯視圖查找真正的視圖對(duì)象View,并返回給前端控制器DistepchServlet。
          • (2)、如果ModelAndView里面是非邏輯視圖:
            如:MappingJackson2JsonView(把當(dāng)前數(shù)據(jù)轉(zhuǎn)為為JSON數(shù)據(jù),并不需要對(duì)視圖邏輯名稱進(jìn)行轉(zhuǎn)換)

          總結(jié)一下:
          視圖解析器ViewResolver接口主要作用是解析前端控制器DispatcherServlet傳遞的邏輯視圖名,并將解析結(jié)果的真正的視圖對(duì)象View傳回給前端控制器DispatcherServlet

          ViewResolverd的實(shí)現(xiàn)類:


          ViewResolver的UML:

          2.5、視圖View

          2.5.1、視圖對(duì)象的作用

          • (1)、將控制器返回的數(shù)據(jù)處理渲染,最終返回客戶端展示給用戶,主要就是完成轉(zhuǎn)發(fā)或者是重定向的操作.。
          • (2)、為了實(shí)現(xiàn)視圖模型和具體實(shí)現(xiàn)技術(shù)的解耦(指的是Spring在org.springframework.web.servlet包中定義的抽象View接口),詳見2.5.2View接口圖。
          • (3)、視圖對(duì)象View由視圖解析器負(fù)責(zé)實(shí)例化。由于視圖是無狀態(tài)(每一次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的view對(duì)象)的,所以不會(huì)有線程安全的問題.

          2.5.2、View接口圖

          2.5.3、View的實(shí)現(xiàn)類圖

          2.5.4、View的UML圖

          ![2021022601-20-01-View-uml(hierarchic group layout)](https://gitee.com/chuchq/blogs-gallery/raw/master/images / 2021/2021022601-20-01-View-uml(hierarchic group layout).png)

          2.5.5、常用的View視圖類

          視圖類型

          簡介

          URL視圖資源圖

          InternalResourceView

          將JSP或其他資源封裝成一個(gè)視圖。被視圖解析器InternalResourceViewResolver默認(rèn)使用。

          JstlView

          InternalResourceView的子類。如果JSP中使用了JSTL的國際化標(biāo)簽,就需要使用該視圖類。

          文檔視圖

          AbstractExcelView

          Excel文檔視圖的抽象類。

          AbstractPdfView

          PDF文檔視圖的抽象類

          報(bào)表視圖

          ConfigurableJasperReportsView

          常用的JasperReports報(bào)表視圖

          JasperReportsHtmlView

          JasperReportsPdfView

          JasperReportsXlsView

          JSON視圖

          MappingJackson2JsonView

          將數(shù)據(jù)通過Jackson框架的ObjectMapper對(duì)象,以JSON方式輸出

          2.6、其他重要的點(diǎn)

          2.6.1、DispatcherServlet.properties

          DispatcherServlet.properties文件是在SpringMVC架包中:


          DispatcherServlet.properties內(nèi)容:

          # Default implementation classes for DispatcherServlet's strategy interfaces.
          # Used as fallback when no matching beans are found in the DispatcherServlet context.
          # Not meant to be customized by application developers.
          
          org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
          
          org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
          
          org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
          	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
          	org.springframework.web.servlet.function.support.RouterFunctionMapping
          
          org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
          	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
          	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
          	org.springframework.web.servlet.function.support.HandlerFunctionAdapter
          
          
          org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
          	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
          	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
          
          org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
          
          org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
          
          org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
          

          SpringMVC為什么能加載不同處理器映射器HandlerMapping、處理器適配器handlerAdapter,就是因?yàn)榭蚣芘渲昧诉@個(gè)DispatcherServlet.properties文件。

          轉(zhuǎn)載于:https://www.cnblogs.com/chuchq/p/14489716.html

          pring MVC框架中,View與ModelAndView是緊密關(guān)聯(lián)的核心組件,它們分別代表了視圖層的抽象概念與控制器返回結(jié)果的封裝對(duì)象,共同實(shí)現(xiàn)了MVC模式中的視圖渲染與模型數(shù)據(jù)傳遞。以下對(duì)這兩個(gè)組件進(jìn)行詳述,并輔以代碼示例。

          View(視圖)

          View是Spring MVC中對(duì)具體視圖技術(shù)(如JSP、Thymeleaf、FreeMarker等)的抽象,它負(fù)責(zé)將模型數(shù)據(jù)渲染成最終發(fā)送給客戶端的HTTP響應(yīng)內(nèi)容。View接口定義了視圖的基本行為:

          • void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response):將模型數(shù)據(jù)與HTTP請(qǐng)求、響應(yīng)對(duì)象結(jié)合,生成并寫入最終的響應(yīng)輸出。

          具體的視圖技術(shù)實(shí)現(xiàn)需要提供符合上述接口的類,例如JSP對(duì)應(yīng)的InternalResourceView、Thymeleaf對(duì)應(yīng)的ThymeleafView等。這些視圖類通常會(huì)解析模型數(shù)據(jù),并利用相應(yīng)的模板引擎或Servlet API將數(shù)據(jù)填充至HTML或其他格式的文檔中。

          ModelAndView(模型與視圖)

          ModelAndView是Spring MVC中用于封裝控制器方法處理結(jié)果的對(duì)象,它包含了視圖的邏輯名稱以及模型數(shù)據(jù)。ModelAndView同時(shí)扮演了模型與視圖兩個(gè)角色,簡化了控制器返回值的處理,使得控制器能夠在一個(gè)對(duì)象中同時(shí)返回渲染視圖所需的視圖名和模型數(shù)據(jù)。

          ModelAndView類主要包含以下屬性與方法:

          • String getViewName() & void setViewName(String viewName):獲取或設(shè)置邏輯視圖名。
          • Map<String, Object> getModel() & void setModel(Map<String, Object>):獲取或設(shè)置模型數(shù)據(jù),通常是一個(gè)鍵值對(duì)集合,其中鍵為模型屬性名,值為屬性值。
          • void addObject(String attributeName, Object attributeValue):向模型中添加單個(gè)屬性。

          在控制器方法中,可以創(chuàng)建并返回一個(gè)ModelAndView對(duì)象,如下所示:

          Java1import org.springframework.stereotype.Controller;
          2import org.springframework.web.bind.annotation.GetMapping;
          3import org.springframework.web.servlet.ModelAndView;
          4
          5@Controller
          6public class ExampleController {
          7
          8    @GetMapping("/example")
          9    public ModelAndView handleExampleRequest() {
          10        ModelAndView modelAndView=new ModelAndView("exampleView");
          11        modelAndView.addObject("message", "Hello, World!");
          12        return modelAndView;
          13    }
          14}

          在這個(gè)例子中,控制器方法創(chuàng)建了一個(gè)ModelAndView實(shí)例,設(shè)置了邏輯視圖名為exampleView,并向模型中添加了一個(gè)名為message、值為Hello, World!的屬性。當(dāng)DispatcherServlet收到此返回值時(shí),它會(huì)根據(jù)ViewResolver鏈來解析邏輯視圖名,找到對(duì)應(yīng)的視圖實(shí)現(xiàn),并將模型數(shù)據(jù)傳遞給視圖進(jìn)行渲染。最終,渲染后的結(jié)果作為HTTP響應(yīng)發(fā)送給客戶端。

          ModelAndView不僅支持傳統(tǒng)的視圖渲染,還適用于RESTful場景。在返回JSON、XML等非視圖內(nèi)容時(shí),可以僅設(shè)置模型數(shù)據(jù),不指定視圖名,Spring MVC會(huì)默認(rèn)選擇合適的HttpMessageConverter將模型數(shù)據(jù)序列化為響應(yīng)體。

          總結(jié)

          View與ModelAndView在Spring MVC中分別扮演了視圖層抽象與控制器返回結(jié)果封裝的角色。View接口定義了視圖渲染的基本規(guī)范,具體的視圖技術(shù)通過實(shí)現(xiàn)這一接口與Spring MVC框架集成。ModelAndView則作為控制器方法返回值,集中管理視圖名與模型數(shù)據(jù),簡化了視圖渲染的流程,確保了模型數(shù)據(jù)能夠準(zhǔn)確、高效地傳遞給視圖進(jìn)行展現(xiàn)。這兩個(gè)組件共同構(gòu)成了Spring MVC視圖渲染機(jī)制的核心,實(shí)現(xiàn)了MVC模式中視圖與模型的解耦與協(xié)作,為構(gòu)建松耦合、易維護(hù)的Web應(yīng)用程序提供了強(qiáng)有力的支持。


          主站蜘蛛池模板: 精品视频一区二区三区四区五区| 国产91一区二区在线播放不卡 | 97久久精品无码一区二区天美| 亚洲一区二区三区深夜天堂| 狠狠做深爱婷婷综合一区 | 国产福利电影一区二区三区,日韩伦理电影在线福 | 亚洲爽爽一区二区三区| 一区国产传媒国产精品| 一区二区三区日韩| 国产精品丝袜一区二区三区| 国产情侣一区二区三区| 成人免费一区二区三区| 成人午夜视频精品一区| 精品女同一区二区三区免费播放| 中文字幕日韩一区二区不卡| 中文字幕在线一区二区在线| 无码少妇一区二区| 日本亚洲成高清一区二区三区| 精品国产一区二区三区久久蜜臀| 无码国产亚洲日韩国精品视频一区二区三区 | 无码人妻aⅴ一区二区三区有奶水 人妻夜夜爽天天爽一区 | 精品视频一区二区三区四区 | 青娱乐国产官网极品一区| 国产一区二区三区亚洲综合| 日韩精品中文字幕视频一区| 四虎在线观看一区二区| 日本一区二区三区精品视频| 国产一区二区三区手机在线观看 | 日本一区精品久久久久影院| 亚洲AV午夜福利精品一区二区 | 色一情一乱一伦一区二区三区日本 | 波多野结衣一区视频在线| 一区二区亚洲精品精华液| 糖心vlog精品一区二区三区 | 中文字幕一精品亚洲无线一区| 亚洲综合av永久无码精品一区二区 | 日本免费电影一区| 亚洲一区精品伊人久久伊人| 国产成人精品无码一区二区三区| 亚洲国产综合无码一区| 91精品国产一区二区三区左线|