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 官方文檔
理論以官方文檔和源碼為准
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.參考
http://www.cnblogs.com/fangjian0423/p/springMVC-introduction.html