概述
用久了SpringBoot,深受其約定大於配置的便利性 “毒害” 之後,我想回歸到SpringMVC時代,看看SpringMVC開發模式中使用者是如何參與的。本文就來體驗一下SpringMVC時代開發的流程。
注: 本文首發於 My 公眾號 CodeSheep ,可 長按 或 掃描 下面的 小心心 來訂閱 ↓ ↓ ↓
SpringMVC架構模式
一個典型的SpringMVC請求流程如圖所示,詳細分為12個步驟:
- 使用者發起請求,由前端控制器DispatcherServlet處理
- 前端控制器通過處理器對映器查詢hander,可以根據XML或者註解去找
- 處理器對映器返回執行鏈
- 前端控制器請求處理器介面卡來執行hander
- 處理器介面卡來執行handler
- 處理業務完成後,會給處理器介面卡返回ModeAndView物件,其中有檢視名稱,模型資料
- 處理器介面卡將檢視名稱和模型資料返回到前端控制器
- 前端控制器通過檢視解析器來對檢視進行解析
- 檢視解析器返回真正的檢視給前端控制器
- 前端控制器通過返回的檢視和資料進行渲染
- 返回渲染完成的檢視
- 將最終的檢視返回給使用者,產生響應
整個過程清晰明瞭,下面我們將結合實際實驗來理解這整個過程。
SpringMVC專案搭建
實驗環境如下:
- IntelliJ IDEA 2018.1 (Ultimate Edition)
- SpringMVC 4.3.9.RELEASE
- Maven 3.3.9
這裡我是用IDEA來搭建的基於Maven的SpringMVC專案,搭建過程不再贅述,各種點選並且下一步,最終建立好的專案架構如下:
新增前端控制器配置
使用了SpringMVC,則所有的請求都應該交由SpingMVC來管理,即要將所有符合條件的請求攔截到SpringMVC的專有Servlet上。
為此我們需要在 web.xml
中新增SpringMVC的前端控制器DispatcherServlet:
<!--springmvc前端控制器-->
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc-dispatcher.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
複製程式碼
該配置說明所有符合.action的url,都交由mvc-dispatcher這個Servlet來進行處理
編寫SpringMVC核心XML配置檔案
從上一步的配置可以看到,我們定義的mvc-dispatcher Servlet依賴於配置檔案 mvc-dispatcher.xml
,在本步驟中我們需要在其中新增三個方面的配置
- 0x01. 新增處理器對映器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
複製程式碼
SpringMVC的處理器對映器有多種,這裡的使用的BeanNameUrlHandlerMapping其對映規則是將bean的name作為url進行處理
- 0x02. 新增處理器介面卡
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
複製程式碼
SpringMVC的處理器介面卡也有多種,這裡的使用的SimpleControllerHandlerAdapter是Controller實現類的介面卡類,其本質是執行Controller中的handleRequest方法。
- 0x03. 新增試圖解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" />
複製程式碼
這裡配置了InternalResourceViewResolver檢視解析器後,其會根據controller方法執行之後返回的ModelAndView中的檢視的具體位置,來載入對應的介面並繫結資料
編寫控制器
這裡模擬的是一個列印學生名單的Service,我們編寫的控制器需要將查詢到的學生名單資料通過ModelAndView渲染到指定的JSP頁面中
public class TestController implements Controller {
private StudentService studentService = new StudentService();
@Override
public ModelAndView handleRequest( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
List<Student> studentList = studentService.queryStudents();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("studentList",studentList);
modelAndView.setViewName("/WEB-INF/views/studentList.jsp");
return modelAndView;
}
}
class StudentService {
public List<Student> queryStudents() {
List<Student> studentList = new ArrayList<Student>();
Student hansonwang = new Student();
hansonwang.setName("hansonwang99");
hansonwang.setID("123456");
Student codesheep = new Student();
codesheep.setName("codesheep");
codesheep.setID("654321");
studentList.add(hansonwang);
studentList.add(codesheep);
return studentList;
}
}
複製程式碼
編寫檢視檔案
這裡的檢視檔案是一個jsp檔案,路徑為:/WEB-INF/views/studentList.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>學生名單</title>
</head>
<body>
<h3>學生列表</h3>
<table width="300px;" border=1>
<tr>
<td>姓名</td>
<td>學號</td>
</tr>
<c:forEach items="${studentList}" var="student" >
<tr>
<td>${student.name}</td>
<td>${student.ID}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
複製程式碼
結合本步驟和上一步驟,檢視和控制器都已編寫完成,由於我們之前配置的處理器對映器為:BeanNameUrlHandlerMapping,因此接下來我們還需要在mvc-dispatcher.xml檔案中配置一個可被url對映的controller的bean,供處理器對映器BeanNameUrlHandlerMapping查詢:
<bean name="/test.action" class="cn.codesheep.controller.TestController" />
複製程式碼
實驗測試
啟動Tomcat伺服器,然後瀏覽器輸入:
http://localhost:8080/test.action
複製程式碼
資料渲染OK。
備註:當然本文所使用的全是非註解的配置方法,即需要在XML中進行配置並且需要遵循各種實現原則。而更加通用、主流的基於註解的配置方法將在後續文章中詳述。
呼,長舒一口氣,這麼個小Demo用SpringMVC完成的話,各種XML配置了半天,真麻煩啊,算了,還是回SpringBoot好了!
後記
作者更多的SpringBt實踐文章在此:
- Spring Boot應用監控實戰
- SpringBoot應用部署於外接Tomcat容器
- ElasticSearch搜尋引擎在SpringBt中的實踐
- 初探Kotlin+SpringBoot聯合程式設計
- Spring Boot日誌框架實踐
- SpringBoot優雅編碼之:Lombok加持
如果有興趣,也可以抽點時間看看作者一些關於容器化、微服務化方面的文章:
- 利用K8S技術棧打造個人私有云 連載文章
- 從一份配置清單詳解Nginx伺服器配置
- Docker容器視覺化監控中心搭建
- 利用ELK搭建Docker容器化應用日誌中心
- RPC框架實踐之:Apache Thrift
- RPC框架實踐之:Google gRPC
- 微服務呼叫鏈追蹤中心搭建
- Docker容器跨主機通訊
- Docker Swarm叢集初探
- 高效編寫Dockerfile的幾條準則