本文纲要
Spring MVC概述
1.1Web开发模式的演进
1.2Spring MVC的定位与核心能力Spring MVC入门案例
2.1 项目环境搭建
2.2 项目代码结构
2.3Spring MVC核心配置
2.4 编写控制器
2.5 容器初始化配置
2.6 启动与测试- 入门案例工作流程解析
3.1 服务器启动流程
3.2 单次请求处理流程 Bean加载控制
4.1 问题背景
4.2 精确包扫描方案
4.3 排除过滤器方案
4.4 容器初始化简化写法Postman工具介绍
5.1 什么是Postman
5.2 基本使用- 总结
Spring MVC 概述
1 ) Web 开发模式的演进
现代 Java Web 开发经历了从繁到简的演进过程,理解其发展脉络有助于深入掌握 Spring MVC 的设计思想。
1.1 传统三层架构
最早期的开发采用清晰的三层架构:
浏览器 → Servlet → Web 层 → Service 层 → DAO 层 → 数据库
- Web 层:负责接收请求、收集参数、生成页面。
- Service 层:负责业务逻辑处理。
- DAO 层:负责数据持久化。
弊端:一个 Servlet 只能处理一个请求,导致系统中存在大量 Servlet,难以维护。
1.2 MVC 模式
为优化 Servlet 的职责,引入 MVC(Model-View-Controller) 模式,让一个控制器能够分派多个请求:
- Controller:接收请求、调用业务、转发/重定向。
- Model:承载业务数据。
- View:负责页面渲染(典型技术:JSP)。
该模式下一个 Controller 可以处理多个请求,但 View 层与后端仍然紧密耦合。
1.3 前后端分离(异步调用模式)
当下主流开发方式:前端静态页面(HTML + CSS + JS)通过 Ajax(异步请求) 与后端交互,数据格式由 JSON 统一:
这种模式下:
- 后端专注提供数据(JSON),不再关心页面渲染。
- 前端独立开发,通过 JSON 数据驱动界面。
2 ) Spring MVC 的定位与核心能力
Spring MVC 是一个基于 Java 的 MVC 模型 的 轻量级 Web 框架,隶属于 Spring 生态,专用于 Web 层开发。它在当前前后端分离架构中承担两项核心职责:
- Controller 开发:接收前端请求,调度业务层。
- 数据转换:将处理结果自动转换成 JSON 格式返回给前端。
使用 Spring MVC 开发 Web 层,相较于原生 Servlet 具有 开发速度快、扩展性强、灵活性好 等显著优势。
Spring MVC 入门案例
下面通过一个最简示例展示 Spring MVC 的完整开发步骤。
1 ) 项目环境搭建
创建 Maven 工程,选择 war 打包方式,并在 pom.xml 中添加必要依赖和 Tomcat 插件。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.wb</groupId>
<artifactId>springmvc01quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- Servlet API,作用域 provided,避免与 Tomcat 冲突 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring MVC 核心包,自动引入 spring-web 等 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Tomcat7 Maven 插件,方便运行 -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
注意:spring-webmvc 会自动传递依赖 spring-web、spring-context 等,因此无需额外声明。
2 ) 项目代码结构
springmvc_01_quickstart
├── pom.xml
└── src
└── main
├── java
│ └── com/wb
│ ├── config
│ │ ├── ServletContainersInitConfig.java # 容器初始化类
│ │ └── SpringMvcConfig.java # Spring MVC 配置类
│ └── controller
│ └── UserController.java # 控制器
└── webapp
└── index.jsp # 欢迎页(可忽略)
3 ) Spring MVC 核心配置
SpringMvcConfig 是一个标准的 Spring 配置类,使用 @ComponentScan 扫描控制器所在的包。
package com.wb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
// springmvc 配置类,本质上还是一个 spring 配置类
@Configuration
@ComponentScan("com.wb.controller")
public class SpringMvcConfig {
}
4 ) 编写控制器
控制器类使用 @Controller 标识为表现层 Bean,方法通过 @RequestMapping 绑定请求路径,@ResponseBody 表示返回值直接作为响应体(而非视图名)。
package com.wb.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
// 定义表现层控制器 bean
@Controller
public class UserController {
// 设置映射路径为 /save,即外部访问路径
@RequestMapping("/save")
// 设置当前操作返回结果为指定 json 数据(本质上是一个字符串信息)
@ResponseBody
public String save() {
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
// 设置映射路径为 /delete
@RequestMapping("/delete")
@ResponseBody
public String delete() {
System.out.println("user delete ...");
return "{'info':'springmvc'}";
}
}
5 ) 容器初始化配置
在 Servlet 3.0 环境中,可通过继承 Spring 提供的抽象类完成 DispatcherServlet 的注册和配置。
5.1 传统写法(完整控制)
package com.wb.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
// web 容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
// 加载 springmvc 配置类,产生 springmvc 容器(本质还是 spring 容器)
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// 设置由 springmvc 控制器处理的请求映射路径
protected String[] getServletMappings() {
return new String[]{"/"};
}
// 加载 spring 配置(本例未使用)
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
5.2 简化写法(推荐后续使用)
Spring 还提供了更简洁的子类,只需返回配置类的 Class 对象即可。
package com.wb.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class}; // Spring 配置(见后文)
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
6 ) 启动与测试
- 使用 Maven 命令启动 Tomcat:
tomcat7:run。 - 浏览器访问
http://localhost/save。 - 控制台输出
user save ...,浏览器显示{'info':'springmvc'}。
注意:若未添加 @ResponseBody,Spring MVC 会将返回值当作视图名解析,从而报 404 错误。
至此,一个最简 Spring MVC 应用构建完成。
入门案例工作流程解析
深入理解入口案例的底层流程,有助于排查问题和灵活定制。整个流程分为服务器启动和请求处理两个阶段。
1 ) 服务器启动流程
关键环节说明:
createServletApplicationContext():构建 Spring MVC 专属容器,并将SpringMvcConfig注册进去。容器实例为AnnotationConfigWebApplicationContext。- 组件扫描:扫描到
UserController并将其作为 Bean 管理,同时解析@RequestMapping("/save")等方法映射关系。 getServletMappings():指定 DispatcherServlet 拦截所有请求("/"),后续所有到达 Tomcat 的请求都会先交给 Spring MVC 处理。
2 )单次请求处理流程
- 映射查找:Spring MVC 在启动时已将
/save→save()的映射存入HandlerMapping,请求到达时快速匹配。 @ResponseBody:告诉 DispatcherServlet 不进行视图转发,直接将返回值作为响应体输出,配合return的字符串即可返回 JSON 数据。
Bean 加载控制
在实际项目中,我们不仅要引入 Spring MVC,还会整合 Spring 核心容器来管理 Service、DAO 及 MyBatis 等组件。此时必须明确划分两个容器的职责,避免重复加载或冲突。
1 ) 问题背景
典型项目包结构例如:
com.wb
├── config # 配置类
├── controller # 表现层(由 Spring MVC 管理)
├── service # 业务层(由 Spring 管理)
├── dao # 数据层(由 Spring 管理)
└── domain # 实体类
- Spring MVC 容器:应只加载
controller包中的 Bean(@Controller)。 - Spring 容器:应加载
service、dao及其他组件(@Service、@Repository等),但不能加载 controller 包。
若 Spring 的 @ComponentScan 范围过大(例如直接扫描 com.wb),会错误地将 Controller 也纳入 Spring 容器,导致 Bean 重复定义、事务失效等问题
2 ) 精确包扫描方案
在 Spring 的配置类中,将 @ComponentScan 的 value 精确设置为需要扫描的具体包,从而避免扫入 Controller
package com.wb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan({"com.wb.service", "com.wb.dao"})
public class SpringConfig {
}
优点:简单直接,无额外配置。
建议:无论数据层是否使用 MyBatis 自动代理,都应将 dao 包显式纳入扫描,以保证技术更换时的通用性。
3 ) 排除过滤器方案
仍然扫描顶级包,但通过 excludeFilters 按照注解类型排除不希望加载的 Bean。
package com.wb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan(value = "com.wb",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
type = FilterType.ANNOTATION:按注解过滤。classes = Controller.class:排除所有标有@Controller的类。
这种方式更为灵活,常用于框架源码或需要细粒度控制的场景(例如后续 Spring Boot 的底层实现)
完整示例:springmvc_02_bean_load 项目中,除了上面的 SpringConfig,还包含了 Service、DAO 等
代码结构如下:
springmvc_02_bean_load
├── pom.xml
└── src/main/java/com/wb
├── config
│ ├── SpringConfig.java
│ ├── SpringMvcConfig.java
│ └── ServletContainersInitConfig.java # 使用简化写法
├── controller
│ └── UserController.java
├── service
│ ├── UserService.java
│ └── impl/UserServiceImpl.java
├── dao
│ └── UserDao.java
└── domain
└── User.java
可通过一个简单的 main 方法验证排除效果:
import com.wb.config.SpringConfig;
import com.wb.controller.UserController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println(ctx.getBean(UserController.class)); // 应抛出异常
}
}
运行结果将抛出 NoSuchBeanDefinitionException,证明 UserController 未被 Spring 容器加载
4 ) 容器初始化简化写法
在 springmvc_02_bean_load 中,ServletContainersInitConfig 采用了更简洁的 AbstractAnnotationConfigDispatcherServletInitializer,同时配置 Spring 和 Spring MVC 的配置类:
package com.wb.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class}; // Spring 容器
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class}; // Spring MVC 容器
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
此时 SpringMvcConfig 内部只需保持 @ComponentScan("com.wb.controller") 即可
Postman 工具介绍
1 ) 什么是 Postman
Postman 是一款功能强大的 网页调试与发送 HTTP 请求 的工具,可以模拟浏览器发送 GET、POST、PUT、DELETE 等各类请求,并支持添加请求头、请求体(JSON/表单等),是后端开发必备的测试利器。
核心优势:
- 无需编写 HTML 表单或 JavaScript 代码即可发送 POST / Ajax 请求。
- 支持保存请求历史,组织成集合(Collections)方便回归测试。
- 支持环境变量、脚本自动化等高级功能。
2 ) 基本使用
安装与启动
- 从官网下载对应系统版本,双击安装。
- 首次启动可能需要注册账号(免费),登录后可创建云同步工作空间。
创建请求
- 点击 New → HTTP Request
- 选择请求方法(GET / POST 等)
- 输入 URL,例如 http://localhost/save
- 点击 Send 发送请求
下方响应区可切换查看 Pretty(格式化)、Raw(原始)、Preview(预览) 等多种视图。
管理请求集合
- 保存请求:按
Ctrl+S,命名并选择一个 Collection。 - Collection 相当于测试目录,可按模块(如“入门案例”、“请求与响应”)分类。
- 以后直接点击 Collection 中的请求即可复用,无需重复输入。
示例:将 /save 和 / 两个请求保存至“入门案例”集合中。
| 请求名称 | 方法 | URL | 所属集合 |
|---|---|---|---|
| 保存用户 | GET | http://localhost/save | 入门案例 |
| 首页 | GET | http://localhost/ | 入门案例 |
利用 Postman,可以快速验证 Spring MVC 接口,极大提高开发与联调效率。
总结
本文从 Web 开发模式演进出发,系统介绍了 Spring MVC 的核心概念,并通过入门案例详细展示了:
- Maven 工程搭建与依赖配置
- Spring MVC 配置类与控制器编写
- 容器初始化类的传统与简化写法
- 服务器启动与请求处理的工作流程
- Spring 与 Spring MVC 容器的 Bean 加载隔离策略
- Postman 测试工具的基本用法
掌握以上内容后,即可轻松构建标准的前后端分离 Web 应用。
后续的学习可以逐步深入 RESTful 风格开发、SSM 整合以及拦截器等高级特性。
1066



被折叠的 条评论
为什么被折叠?



