SpringMVC源碼閱讀入門


1.導入

Spring Web MVC是基於Servlet API構建的原始Web框架,從一開始就包含在Spring框架中。正式的名稱“Spring Web MVC”來自於它的源模塊(spring-webmvc)的名稱,常被人們稱為“Spring MVC”。

本文通過一個簡單的增刪改查demo切入,對SpringMVC源碼進行解讀,Spring Framework版本是4.3.7

2.前期准備

2.1 項目組成

開發工具IntelliJ IDEA 2017.1,JDK1.8

Spring4.3.7,Hibernate 4.3.8,其余組件可以在pom.xml找到

項目文件目錄如下:

2.2 導入Demo

源碼請點擊這里,在idea中導入

輸入git容器地址,點擊clone

要讓idea識別這是Web項目,打開File->Project Structure,一般idea會自動檢測配置文件,提示你設置為spring配置文件,我們也可以手動添加

再選中Web,將WEB-INF下的web.xml選中,並識別webapp根目錄(idea會幫我們自動配置)

將Modules打成war_exploded

初始化數據,sql文件在/sql下,先運行table.sql,再運行init.sql

配置Tomcat,網上教程很多,不再贅述

3.實例

為web.xml配置入口Servlet

contextConfigLocation是上下文位置,讀取了我們的spring上下文配置文件

設置了編碼過濾器CharacterEncodingFilter

我們還配置了DispatcherServlet,這是SpringMVC的核心類,后續我們會詳細講解,url-pattern配置"/","/"代表映射所有請求地址,如Controller請求路徑/user/login,而不包括*.jsp,*.ftl等

<?xml version="1.0" encoding="UTF-8"?> <!--suppress ALL --> <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_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <filter-name>Set Character Encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>Set Character Encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springConfig/dispatcher-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> </web-app>

寫一個簡單的Controller

@Controller代表這個類是個Controller,在dispatcher-servlet.xml中被<context:component-scan base-package="org.format.demo.controller" />掃描到,並識別成是"Controller",在Spring容器中初始化

@RequestMapping意思是請求映射,@RequestMapping("/")中的"/"的意義就是contextPath后面的路徑;也就是 http://host:port/contextPath 后面的路徑

ModelAndView是一個模型視圖類,由handler返回,並有DispatcherServlet解析,我們往view加入了key為"welcome",value為"hello"的Object

@Controller
@RequestMapping("/") public class IndexController { @RequestMapping public ModelAndView index() { ModelAndView view = new ModelAndView("index"); view.addObject("welcome", "hello"); return view; } }

 在前端頁面我們可以看到key="welcome"

因為在前台我們可以用EL表達式取出來

<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>This is freemarker file</title> </head> <body> <h2>Welcome to user SpringMVC</h2> <h3>your welcome param: ${welcome}</h3></body> </html>

IndexController中ModelAndView view = new ModelAndView("viewName"); ,viewName="index"

根據freemarker.xml最終解析成/WEB-INF/view/{viewName}.ftl,所以找到了/WEB-INF/view/index.ftl

簡單看下EmployeeController

package org.format.demo.controller; import org.format.demo.model.Employee; import org.format.demo.service.IDeptService; import org.format.demo.service.IEmployeeService; import org.springframework.beans.factory.annotation.Autowired; 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.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.servlet.ModelAndView; import java.util.HashMap; import java.util.List; import java.util.Map; @Controller @RequestMapping(value = "/employee") public class EmployeeController { @Autowired private IEmployeeService employeeService; @Autowired private IDeptService deptService; @RequestMapping public ModelAndView index() { ModelAndView view = new ModelAndView("employee/list"); List<Employee> employees = employeeService.list(); view.addObject("list", employees); return view; } @RequestMapping(method = RequestMethod.POST, value = "/delete/{employeeId}") @ResponseBody public String delete(@PathVariable Integer employeeId) { employeeService.delete(employeeId); return "success"; } @RequestMapping(method = RequestMethod.GET, value = "/add") public ModelAndView add(ModelAndView view) { view.setViewName("employee/form"); view.addObject("depts", deptService.listAll()); return view; } @RequestMapping(method = RequestMethod.GET, value = "/detail/{employeeId}", produces={"application/json; charset=UTF-8"}) @ResponseBody public ModelAndView detail(@PathVariable Integer employeeId, ModelAndView view) { view.setViewName("employee/form"); view.addObject("employee", employeeService.getById(employeeId)); view.addObject("depts", deptService.listAll()); return view; } @RequestMapping(method = RequestMethod.POST, value = "/update") public String add(Employee employee) { if(employee.getDept().getId() == null) { employee.setDept(null); } employeeService.saveOrUpdate(employee); return "redirect:/employee/"; } }

1.@RequestMapping

這個注解會將 HTTP 請求映射到 MVC 和 REST 控制器的處理方法上,它既可以用在類上也可以用在方法上

2.@PathVariable

獲取請求參數的值,這樣每個員工都有獨立的URI資源

3.@ResponseBody

將Request的Accept設置為"application/json",就是把在@RequestMapping中produces加入"application/json";這里同樣要將Response的Content-Type設置成"application/json",即加上@ResponseBody

Accept和Content-Type的區別?

Accept表示瀏覽器/客戶端支持的類型,Content-Type表示發送端發送的數據類型

3.如何優雅高效地閱讀源碼

工欲善其事,必先利其器,這里我使用idea

3.1 官方文檔

https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#spring-introduction

理論以官方文檔和源碼為准

3.2 下載源碼

在閱讀源碼前,請大家下載源碼,可以在Maven中下載,請大家自行百度如何下載源碼。讀.class文件沒有意義,源碼有豐富的注釋

DispatcherServlet.class,我覺得我無法讀下去

DispatcherServlet.java,方法和變量都有詳細的注釋

3.3 常用快捷鍵

記住快捷鍵會讓你事半功倍

ctrl+n:快速進入類

ctrl+shift+n:進入普通文件

ctrl+f12:查看該類方法

在閱讀源碼的時候特別方便,因為你不可能每個方法都細細品讀

ctrl+alt+u:查看類結構圖,這些類都可以點擊進入,我比較喜歡用這個

ctrl+shift+alt+u:查看類結構圖,這些類不能進入

alt+f7:查看方法引用位置,以doDispatch()為例,可以看到DispatcherServlet 897行被引用,858行注釋被引用

ctrl+alt+b:跳轉到方法實現處,對者接口方法點擊,會彈出來在哪里實現。

接下來是我不得不說的idea神器---書簽,bookmark可以對代碼行進行標記,並進行快速切換

ctrl+f11:顯示bookmark標記情況,土黃色代表該字符已被占用,輸入或者點擊1代表在此位置書簽為1

我們以processDispatchResult()方法為例

ctrl+標記編號 快速回到標記處,如我剛才在這留下了書簽,ctrl+1,DispatcherServlet 1018行

shift+f11:顯示所有書簽,左欄是我打過書簽的類、行信息,右邊是代碼詳情

 

當你所有書簽都用完,0-9,a-z全部用完,可以直接ctrl+f11,記錄普通書簽,雖然無法用ctrl快速跳轉,在shift+f11還是可以找到

alt+f8:啟用Evaluate窗口

當我們想看返回值,無法聲明變量查看該變量的時候(源碼不可更改)

可以使用Evaluate表達式

 

4.結語

SpringMVC是一個優秀的Web框架,簡化了開發流程

接下來我們將進入源碼分析部分,待續...

5.參考

https://docs.spring.io/spring/docs/4.3.7.RELEASE/spring-framework-reference/htmlsingle/#spring-introduction

http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM