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

SpringMVC源码阅读入门的更多相关文章

  1. SpringMVC源码阅读:过滤器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  2. SpringMVC源码阅读系列汇总

    1.前言 1.1 导入 SpringMVC是基于Servlet和Spring框架设计的Web框架,做JavaWeb的同学应该都知道 本文基于Spring4.3.7源码分析,(不要被图片欺骗了,手动滑稽 ...

  3. SpringMVC源码阅读:属性编辑器、数据绑定

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  4. SpringMVC源码阅读:拦截器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  5. SpringMVC源码阅读:核心分发器DispatcherServlet

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将介绍SpringMVC的核 ...

  6. SpringMVC源码阅读:定位Controller

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码分析,弄清楚Spr ...

  7. SpringMVC源码阅读:Controller中参数解析

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  8. SpringMVC源码阅读:Json,Xml自动转换

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

  9. SpringMVC源码阅读:视图解析器

    1.前言 SpringMVC是目前J2EE平台的主流Web框架,不熟悉的园友可以看SpringMVC源码阅读入门,它交代了SpringMVC的基础知识和源码阅读的技巧 本文将通过源码(基于Spring ...

随机推荐

  1. day04_雷神_函数

    #day04 1.函数 1.1函数传参 函数定义的时候是形参:函数执行的时候是实参 实参: 位置参数.关键字参数.混合参数 位置参数:位置一一对应 关键字参数: 可以位置不对应 混合参数:关键字参数要 ...

  2. Android-Kotlin-枚举enum

    案例一 星期: 星期的枚举:enum class 类名 {} package cn.kotlin.kotlin_oop09 /** * 定义星期的枚举类 */ enum class MyEnumera ...

  3. SignalR简介

    什么是SignalR? ASP.NET SignalR是ASP.NET开发人员的库,它简化了向应用程序添加实时Web功能的过程.实时Web功能是指服务器代码在连接的客户端可用时立即将内容推送到连接的客 ...

  4. 在ASP.NET Core中,静态类如何读取配置文件

    这是今天下午一个同事问我的问题,如何在静态类中读取json配置文件.我当时并没有告诉他如何如何去做,办法肯定是有,但是这种编程思维确实得改改了.静态类.静态方法不是面向对象编程的最佳实践..NET C ...

  5. 【BZOJ2595】 [Wc2008]游览计划

    BZOJ2595 [Wc2008]游览计划 Solution 考虑这是一个最小费用连通性的问题,既然大家都说这是什么斯坦纳树那就是的吧... 所以我们肯定可以这样设一个dp状态: \(dp_{i,j, ...

  6. 有标号的DAG图计数1~4

    前言 我什么都不会,菜的被关了起来. 有标号的DAG图I Solution 考虑递推,设\(f_i\)表示i个点的答案,显然这个东西是可以组合数+容斥递推? 设\(f_i\)表示i个点的答案,我们考虑 ...

  7. nginx-2.nginx是什么

    Nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器: Nginx可以作为一个HTTP服务器进行网站的发布处理,另外Nginx可以 ...

  8. atomic write pipe

    阅读 skynet 代码 socket_server 部分,发现对 socket 的写操作流程是这样的: 1. 各个服务(各线程)将数据写到 sendctrl_fd,这是一个 pipe 的 写端 2. ...

  9. POJ 2442(优先队列 k路归并 堆)

    Description Given m sequences, each contains n non-negative integer. Now we may select one number fr ...

  10. " XSS易容术---bypass之编码混淆篇+辅助脚本编写"

    一.前言本文原创作者:vk,本文属i春秋原创奖励计划,未经许可禁止转载!很多人对于XSS的了解不深.一提起来就是:“哦,弹窗的”.”哦,偷cookie的.”骚年,你根本不知道什么是力量.虽然我也不知道 ...