SpringMVC源碼閱讀入門

1.導入

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

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

2.前期準備

2.1 項目組成

開發工具IntelliJ IDEA 2017.1,JDK1.8java

Spring4.3.7,Hibernate 4.3.8,其他組件能夠在pom.xml找到git

項目文件目錄以下:github

2.2 導入Demo

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

輸入git容器地址,點擊clonespring

要讓idea識別這是Web項目,打開File->Project Structure,通常idea會自動檢測配置文件,提示你設置爲spring配置文件,咱們也能夠手動添加sql

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

將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

相關文章
相關標籤/搜索