一、简介
SpringMVC 就是 Spring 框架中的 MVC 模块,用于构建 Web 应用中的"控制层"。
SpringMVC 是 Spring 提供的一个基于 Servlet 的 Web MVC 框架模块,是 Spring 整个体系中的"Web 层核心"。
SpringMVC 是 Spring 的一部分,Spring 框架的主要模块包括:
1. Core(核心容器)
2. AOP(面向切面)
3. Data Access(JDBC、ORM)
4. Web(包括 Web、Web MVC、Web WebSocket)
5. Messaging
6. Test
1-1、SpringMVC 的职责是什么?
它实现了经典的 MVC 架构中的 控制器 Controller 和前端分发器 DispatcherServlet 功能。
MVC分工:
角色 | SpringMVC 中的实现 |
---|---|
Model | Service 层 + Java Bean |
View | JSP、Thymeleaf、Freemarker 等 |
Controller | 控制层,工程中的servlet,@Controller / @RestController 注解的类;功能:接受请求,响应浏览器 |
Dispatcher | DispatcherServlet ,是 SpringMVC 的核心 |
JavaBean分为两类:
一类称为**实体类Bean:**专门存储业务数据的,如 Student、User 等
一类称为**业务处理 Bean:**指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。
1-2、MVC的工作流程:
┌───────────────┐
浏览器请求 ---> │ DispatcherServlet │
└───────────────┘
│
▼
┌────────────────────┐
│ Controller(控制器) │ <== 负责接收请求、调服务
└────────────────────┘
│
▼
┌────────────────────┐
│ Service(业务逻辑) │ <== 处理逻辑,调数据库
└────────────────────┘
│
▼
┌────────────────────┐
│ DAO / Model(数据) │ <== 数据层/模型层
└────────────────────┘
│
▼
┌────────────────────┐
│ View(JSP/HTML) │ <== 渲染页面
└────────────────────┘
1-3、SpringMVC 和 SpringBoot 是什么关系?
-
SpringMVC 是"Spring体系中的 MVC 模块"
-
SpringBoot 是"简化 Spring 配置的一套框架"
-
SpringBoot 内部集成了 SpringMVC,所以你写 SpringBoot Web 项目,底层其实就是用的 SpringMVC。
1-4、SpringMVC 和 Servlet 是什么关系?
SpringMVC 是基于 Servlet 的高级封装:
对比 | Servlet | SpringMVC |
---|---|---|
入口 | 每个 Servlet 写一个类 | 一个 DispatcherServlet 就能接收所有请求 |
映射 | 在 web.xml 或注解中配置路径 | 使用 @RequestMapping 等注解 |
请求处理 | 自己解析参数 | 自动绑定参数(甚至对象) |
响应处理 | 手动写输出 | 自动 JSON 返回或视图渲染 |
扩展性 | 不好扩展 | 支持拦截器、参数解析器、数据转换器 |
二、SpringMVC的特点
2-1**、SpringMVC 的核心特点(总结 + 示例 + 对比)**
1. 基于注解,开发简洁
使用注解(如
@Controller
,@RequestMapping
,@ResponseBody
)快速定义控制器和请求路径。
示例:
java
@Controller
public class UserController {
@RequestMapping("/hello")
@ResponseBody
public String sayHello() {
return "Hello SpringMVC!";
}
}
对比传统 Servlet:
传统 Servlet | SpringMVC 注解风格 |
---|---|
需配置 web.xml 映射路径 | 用注解快速映射 URL |
手动解析参数 | 自动参数绑定 |
写出响应内容麻烦 | 支持 @ResponseBody 返回 JSON |
2. 请求参数自动绑定
SpringMVC 自动将请求参数绑定到方法参数、对象属性,支持类型转换。
示例:
java
@PostMapping("/addUser")
public String add(User user) {
// 请求中 name=Tom&age=18 自动注入到 user 对象
return "ok";
}
对比传统 Servlet:
Servlet 中这样写 |
---|
String name = request.getParameter("name"); |
手动封装 User 实例 |
3. 强大的 RESTful 支持
SpringMVC 原生支持 REST 风格请求(不同方法映射到不同逻辑)。
示例:
java
@GetMapping("/user/{id}")
public User getUser(@PathVariable int id) { ... }
@DeleteMapping("/user/{id}")
public String deleteUser(@PathVariable int id) { ... }
对比传统方式:
Servlet 只能识别 URL,不能区分 GET/POST/DELETE/PATCH,需手动判断 request.getMethod()
4. 内置视图解析器支持多种视图(JSP/Thymeleaf/JSON)
说明:
SpringMVC 可返回逻辑视图名,由视图解析器处理,或返回 JSON 数据(配合 @ResponseBody
或 @RestController
)
示例:
java
@GetMapping("/list")
public String list(Model model) {
model.addAttribute("students", studentService.getAll());
return "studentList"; // JSP 或 Thymeleaf
}
或者:
java
@RestController
@RequestMapping("/api")
public class ApiController {
@GetMapping("/info")
public Map<String, Object> info() {
return Map.of("status", "ok", "time", System.currentTimeMillis());
}
}
5. 全局异常处理、拦截器、数据转换器可插拔扩展
你可以很方便地实现:
-
自定义参数校验器(
@Valid
+@ControllerAdvice
) -
请求拦截器(
HandlerInterceptor
) -
统一异常处理(
@ExceptionHandler
/@ControllerAdvice
)
2-2、总结对比表:SpringMVC vs Servlet vs Struts2
比较维度 | SpringMVC | Servlet | Struts2 |
---|---|---|---|
架构模式 | MVC | 非 MVC,结构混乱 | MVC |
开发方式 | 注解驱动,自动装配 | 手动获取 request/response | 配置繁琐,OGNL 绑定 |
REST 支持 | ✅ 原生支持 | ❌ 不支持 | ❌ 需要插件支持 |
参数绑定 | ✅ 自动对象绑定 + 转换器 | ❌ 手动处理 | ✅ OGNL,但性能较差 |
异常处理 | ✅ 注解 + 全局统一 | ❌ 需 try-catch | ❌ 自定义 filter 实现 |
视图选择 | 多视图支持 | JSP | JSP / Freemarker |
JSON 返回 | ✅ 内置支持 | ❌ 需写输出流 | ✅ 支持 JSON 插件 |
社区活跃度 | ✅ 非常高,主流标准 | ❌ 已过时 | ❌ 弃用趋势 |
2-3、RESTful 接口
RESTful 接口开发 = "资源 URL" + "HTTP 方法" ,在 SpringMVC 中,就是用 @GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
来准确表达"我要对这个资源做什么"。
举个比喻:
-
/users
是一群"用户" -
/users/1
是用户 1 -
然后你要"干什么",就用 HTTP 方法说清楚
想干什么 | URL | 方法 | 注解 |
---|---|---|---|
查所有用户 | /users |
GET | @GetMapping |
新增一个用户 | /users |
POST | @PostMapping |
查询某个用户 | /users/1 |
GET | @GetMapping("/{id}") |
修改某个用户 | /users/1 |
PUT | @PutMapping("/{id}") |
删除某个用户 | /users/1 |
DELETE | @DeleteMapping("/{id}") |
三、idea创建spring-mvc项目 (maven)
1、不使用maven-webapp模版,直接创建maven项目
2、在pom.xml中导入相关依赖
XML
<dependencies>
<!-- spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<!-- 日志门面 API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<!-- slf4j 到 logback 的实现桥接器(含 core 和 classic)-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- servlet api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!-- tomcat中自带了servlet api和jsp的jar包的! -->
<!-- provided:已被提供,当项目打成war包,这个servlet的jar包就不会存在于当前war包中的web-inf的lib中 -->
<scope>provided</scope>
</dependency>
<!-- spring5和thymeleaf的整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
</dependencies>
【注意】:
pom.xml中添加的依赖对应的jar,在当前project打成war包后,会被自动加入到web-inf下的lib文件夹下,但是加了<scope>provided<scope>的,不会被加入到web-inf下的lib文件夹下。
3、添加webapp文件夹

4、添加web.xml文件


【注意】:
修改此处的路径地址!
3-1、手动配置 DispatcherServlet
------ SpringMVC 的核心组件(前端控制器)
DispatcherServlet 是整个 SpringMVC 的入口
配置 DispatcherServlet 的两种方式(推荐 XML)
1、默认配置方式
springMVC的配置文件默认位于web-inf下:

XML
<!-- 注册 DispatcherServlet,对浏览器发送的请求统一处理 -->
<servlet>
<!--
这个 <servlet-name> 其实是给 DispatcherServlet 起的一个"别名"
自定义
它与配置文件名有关!
当你不给 DispatcherServlet 指定配置文件路径时(省略 <init-param>),Spring 会默认去加载这个路径:
/WEB-INF/<servlet-name>-servlet.xml
示例:
如果你写成:<servlet-name>abc</servlet-name>
默认加载:/WEB-INF/abc-servlet.xml
但是可以通过 <init-param> 指定配置文件:
-->
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<!--
给 Servlet(如 DispatcherServlet)指定它要拦截哪些 URL 请求
设置 springMVC 的核心控制器所能处理的请求的请求路径
/ 所匹配的请求可以是 /login 或.html 或.js 或.css 方式的请求路径
但是 / 不能匹配.jsp 请求路径的请求
/*,匹配所有的请求路径,包括.jsp 请求路径的请求
-->
<url-pattern>/</url-pattern>
</servlet-mapping>
但是maven项目,约定,所有的配置文件要统一放到resource文件夹下!
所以,推荐用扩展配置方式
<url-pattern>/</url-pattern>:将所有的请求都交给 DispatcherServlet 来处理(也就是 SpringMVC)
<url-pattern>
有哪些写法?
写法 | 说明 |
---|---|
/ |
拦截所有请求(包括 .jsp 和静态资源,注意需特殊配置) |
*.do |
只拦截 .do 结尾的请求 |
/app/* |
拦截以 /app/ 开头的路径 |
/hello |
只拦截 /hello 这个路径 |
*.action |
拦截 .action 的请求(老项目常见) |
2、扩展配置方式 (推荐)
XML
<!-- 注册 DispatcherServlet,对浏览器发送的请求统一处理 -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 加载 SpringMVC 配置文件:/resource/springMVC.xml -->
<init-param>
<param-name>contextConfigLocation</param-name>
<!--
classpath:默认就是当前项目下的resources文件夹下
-->
<param-value>classpath:springMVC.xml</param-value>
</init-param>
<!--
指定当前 Servlet 是否在服务器启动时立即加载(初始化),以及加载的优先级。
-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<load-on-startup>
是干什么用的?指定当前 DispatcherServlet 是否在服务器启动时立即加载(初始化),以及加载的优先级。
值 含义 大于等于 0 启动Tomcat时立即创建 Servlet 实例,值越小优先级越高(先加载) 小于 0 或不写 服务器启动时不会加载 这个 Servlet,第一次请求它时才创建实例(要创建的内容很懂的时候,会影响性能!)
若是:第一次请求时才会加载 DispatcherServlet(延迟初始化),可能出现"首次访问慢"或配置未生效问题
创建springMVC.xml配置文件

3-2、创建SpringMVC 中的"控制器":Controller 类
被 @Controller
注解的类,就是 SpringMVC 中用于接收请求、处理业务逻辑、返回视图或数据的控制器。
示例:
java
@Controller
public class HelloController {
// "/" -->/WEB-INF/views/index.html
@RequestMapping("/")
public String index(){
return "index";
}
}
3-3、配置springMVC.xml配置文件
既然使用了注解,就要配置扫描组件
XML
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 开启注解驱动 -->
<mvc:annotation-driven/>
<!-- 扫描 Controller 包 -->
<context:component-scan base-package="com.wsbazinga.controller"/>
<!-- 视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<!-- 可以有多个视图解析器,用order属性配置优先级 -->
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/views/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateMode" value="HTML"/>
</bean>
</property>
</bean>
</property>
</bean>
</beans>
1、<mvc:annotation-driven/>说明:
启用 SpringMVC 对注解(如 @RequestMapping
、@ResponseBody
、@RequestParam
等)的支持功能,也就是告诉 Spring:"我要用注解方式来开发控制器"。
它自动注册以下组件:
组件名 | 作用 |
---|---|
RequestMappingHandlerMapping |
处理 URL 和方法的映射关系 |
RequestMappingHandlerAdapter |
调用控制器方法并处理参数和返回值 |
HttpMessageConverter |
负责 JSON ↔ Java 对象 的转换(如使用 Jackson) |
Validator |
表单参数校验支持(如 @Valid ) |
3-4、配置tomcat启动项目
此时,直接启动tomcat,会通过域名:http://localhost:8080/WsSpringMvc/,直接访问web-inf/views/index.html文件!
3-5、跳转到制定页面
inde.html
html
<body>
<h1>首页</h1>
<!-- 以/开头的路径:绝对路径(浏览器解析、服务器解析) -->
<!-- thymeleaf语法检测到是绝对路径,自动添加上下文路径,不怕部署路径变化。 -->
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
HelloController.java
java
@RequestMapping("/target")
public String toTarget(){
return "target";
}
再添加target.html即可。
四、@RequestMapping注解讲解
@RequestMapping
是用来 映射浏览器请求 URL 到后端控制器Controller类 的注解,是 SpringMVC 中的"路由"。
4-1、基本用法
java
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
当用户访问:http://localhost:8080/项目名/hello
就会调用这个方法,然后返回 "hello"
,通过视图解析器跳转到页面。
【注意】:
1、@RequestMapping注解可以放在
类上,也可以放在
方法上!
2、确保
@RequestMapping映射的URL在当前的project中是
唯一的!
4-2、常用属性详解:
属性名 | 作用 |
---|---|
value 或 path |
请求的 URL 路径(必写),类型是String[]数组 |
method |
限定请求方式(GET、POST 等),类型是:RequestMethod[]数组,若是不设置method属性,任何的请求方式都能匹配! |
params |
请求必须包含某些参数时才执行,类型:String[] 数组,多个params必须同时满足 |
headers |
请求头匹配时才执行 |
produces |
指定响应的内容类型(如 application/json ) |
consumes |
指定请求的数据类型(如 application/json ) |
1. 指定 GET 请求
java
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String getUser() {
return "user";
}
访问 /user
且必须是 GET 请求,否则报错。
2. 指定多个方法
java
@RequestMapping(value = "/user", method = {RequestMethod.GET, RequestMethod.POST})
支持 GET 和 POST。
3. 限定参数存在
java
@RequestMapping(value = "/search", params = "keyword")
只有请求中带有 keyword
参数才会匹配这个方法。
示例:
html
<form th:action="@{/testParams(password=1234)}" method="get">
<input type="submit" value="测试requestmapping注解的params参数">
</form>
java
@RequestMapping(
value = "/testParams",
params = {"!username", "password!=123456"}
)
public String testParams(){
return "success";
}
4. 映射类和方法组合路径(推荐做法)
java
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/add")
public String addUser() {
return "add";
}
@RequestMapping("/delete")
public String deleteUser() {
return "delete";
}
}
最终路径就是 /user/add
、/user/delete
5、请求头属性

6、SpringMVC支持ant风格的路径
Ant 风格路径 是 SpringMVC 中的一种通配符路径匹配规则,主要用于 @RequestMapping
的 value
属性中,用来更灵活地匹配 URL。
通配符 | 含义 | 示例 |
---|---|---|
? |
匹配任意的 单个字符 | /user? → 匹配 /user1 、/users (长度固定) |
* |
匹配任意数量的 字符 (0 个或多个) | /user* → 匹配 /user 、/user123 、/user_abc |
** |
匹配任意数量的 目录层级 | /a/**/b → 匹配 /a/b 、/a/x/b 、/a/x/y/z/b |
【注意】:SpringMVC 中,
**
只能用于/xx/**/yy
的结构中,不能直接写成/**
放在中间或结尾。✔️ 正确用法:
java@RequestMapping("/admin/**/page")
❌ 错误用法:
java@RequestMapping("/admin**page") // 无效 @RequestMapping("**/page") // 报错
4-3、和 @GetMapping / @PostMapping 的关系?
注解 | 等价写法 |
---|---|
@GetMapping("/xxx") |
@RequestMapping(value="/xxx", method=RequestMethod.GET) |
@PostMapping("/xxx") |
@RequestMapping(value="/xxx", method=RequestMethod.POST) |
@DeleteMapping |
用于 DELETE 请求 |
@PutMapping |
用于 PUT 请求 |
所以在 RESTful 风格中,推荐使用 @GetMapping
、@PostMapping
等简化注解。
@RequestMapping的派生注解
【注意】:
浏览器只能处理get和post请求,即使form表单有method属性,可以指定请求方式,也只有get和post两种!(put和delete请求怎么处理,见后面的内容)
4-4、springmvc支持路径中的占位符
这是 RESTful 风格中非常核心的一项功能。
SpringMVC 支持通过
{}
的形式在请求路径中定义占位符 ,然后通过@PathVariable
注解将 URL 中的路径变量绑定到方法参数上。
举个例子说明:
java
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/detail/{id}")
public String getUserById(@PathVariable("id") String id) {
System.out.println("查询用户 ID: " + id);
return "user_detail";
}
}
如果你访问:
http://localhost:8080/user/detail/123
就会打印:
查询用户 ID: 123
1、语法说明:
用法 | 说明 |
---|---|
/user/{id} |
{id} 是路径中的占位符 |
@PathVariable("id") |
将 {id} 的值绑定到参数上 |
2、常见变种:
(1)多个路径变量
java
@RequestMapping("/user/{userId}/order/{orderId}")
public String getOrder(@PathVariable("userId") String uid,
@PathVariable("orderId") String oid) {
// ...
}
访问:
/user/10/order/555
就会自动绑定:
-
uid = "10"
-
oid = "555"
(2)占位符名和参数名一致时,@PathVariable 可以省略参数名
java
@RequestMapping("/user/{id}")
public String getUserById(@PathVariable String id) {
// OK,变量名和参数名一致
}
(3)占位符 + 通配符
java
@RequestMapping("/file/{path}/**")
public String getFile(@PathVariable String path) {
// 捕捉一部分路径,同时保留通配符
}
匹配以
/file/xxx/...
开头的所有路径,xxx
这一段会被当作路径变量path
,**
表示后面还有任意多层路径。
(4)动态 RESTful 风格操作
你可以用路径来表示操作行为,例如:
java
// 删除用户
@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)
public void deleteUser(@PathVariable int id) {
// DELETE 操作
}
配合前端的 RESTful 请求或 Postman 测试非常方便。
3、与 @RequestParam 的区别
对比项 | @PathVariable |
@RequestParam |
---|---|---|
来源 | URL 的路径部分 | URL 的查询参数部分 |
示例 | /user/123 |
/user ?id=123 |
用法 | @PathVariable("id") |
@RequestParam("id") |
五、SpringMVC获取请求参数
5-1、servletapi获取请求参数(不推荐)
原生的获取方法,从HttpServletRequest中获取请求参数
请求参数通常来自:
-
URL 查询参数 :例如
/login?username=Tom&password=123
-
表单提交(POST) :例如
<form>
提交的数据 -
请求体(body):JSON、XML 等格式的原始数据
1、最常用的方式:getParameter()
示例:
html
<form th:action="@{/testParams/testRequestParams}" method="post">
username: <input type="text" name="username"><br>
password: <input type="text" name="password">
<input type="submit" value="测试testRequestParams">
</form>
java
@PostMapping("/testRequestParams")
public String testRequestParams(HttpServletRequest request){
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("username = " + username + "; password = " + password);
return "success";
}
-
无论是 GET 还是 POST 请求都可以使用
-
只能获取 key=value 结构的表单数据或 URL 参数
-
不能处理 JSON 请求体数据!!!
【注意】:
1、HttpServletRequest中的值是DispatcherServlet放入的。
2、这是原生的获取请求参数的方法,SpringMVC已经做了封装,不再建议使用!
5-2、通过控制器获取请求参数
直接,将Controller类中的方法里面的形参的参数名 = 请求参数的参数名
示例:
html
<form th:action="@{/testParams/testControllerParams}" method="post">
username: <input type="text" name="username"><br>
password: <input type="text" name="password">
<input type="submit" value="测试testRequestParams">
</form>

【备注】:当有多个同名的请求参数的时候,比如:复选框
html
<form th:action="@{/testParams/testControllerParams}" method="post">
username: <input type="text" name="username"><br>
password: <input type="text" name="password"><br>
hobby: <input type="checkbox" name="hobby" value="a">a
<input type="checkbox" name="hobby" value="b">b
<input type="checkbox" name="hobby" value="c">c<br>
<input type="submit" value="测试testRequestParams">
</form>
1、直接使用String获取(多个值逗号分离)
2、使用String[]获取



5-3、使用 @RequestParam
------ 获取URL参数或表单参数
@RequestParam是将请求参数和控制器方法的形参创建映射关系。
示例:
java
@PostMapping("/login")
public String login(@RequestParam("username") String username,
@RequestParam("password") String password) {
System.out.println(username + " - " + password);
return "success";
}
此时可以解决表单请求的参数名和controller方法里面的形参名不一致的问题!
@RequestParam
不能 用来直接获取 JSON 格式的请求体数据。
@RequestParam注解一共有3个属性:
用法 | 含义 |
---|---|
@RequestParam("xxx") |
从请求中取出名为 xxx 的参数 |
required = false |
表示该参数可以为空,默认是 true |
defaultValue |
没传参数,或传参为""时,用默认值(和required无关! ) |
5-4、@RequestHeader
@RequestHeader是将请求头信息和控制器方法的形参创建映射关系
@RequestHeader注解一共有三个属性:value、required、defaultValue,用法同@RequestParam
示例:
java
@GetMapping("/header")
public String testHeader(@RequestHeader("User-Agent") String userAgent) {
System.out.println("客户端浏览器信息:" + userAgent);
return "ok";
}
如果你想获取所有请求头,可以使用 HttpServletRequest
或 @RequestHeader Map
:
java
@GetMapping("/allHeaders")
public String allHeaders(@RequestHeader Map<String, String> headers) {
headers.forEach((k, v) -> System.out.println(k + ": " + v));
return "ok";
}
使用场景举例:
场景 | 请求头 | 用法 |
---|---|---|
判断浏览器类型 | User-Agent |
适配页面或功能 |
语言国际化 | Accept-Language |
根据浏览器语言返回不同语言的页面 |
认证 | Authorization |
Token 认证、JWT 登录 |
CORS 请求 | Origin 、Referer |
用于跨域校验或来源过滤 |
5-5、@CookieValue
@CookieValue是将cookie数据和控制器方法的形参创建映射关系
@CookieValue注解一共有三个属性:value、required、defaultValue,用法同@RequestParam。
示例:
java
@Controller
public class CookieController {
@RequestMapping("/readCookie")
@ResponseBody
public String readCookie(@CookieValue("username") String username,
@CookieValue(value = "token", defaultValue = "no-token") String token) {
return "用户名:" + username + ",Token:" + token;
}
}
5-6、通过pojo获取请求参数
通过 POJO(JavaBean)对象接收请求参数
相比一个个用 @RequestParam
接收参数,使用 POJO 可以自动封装多个参数,非常方便、清晰、结构化。
1、什么是 POJO 获取请求参数?
SpringMVC 会自动根据前端传来的请求参数名/URL参数,将它们填充进你定义的 JavaBean(POJO)对象中。
2、使用条件
只要满足下面两个条件,SpringMVC 就可以自动封装:
-
请求参数名(form 中的 name)/URL参数 和 JavaBean 的属性名相同
-
JavaBean 有 无参构造器 + setter 方法
3、示例
- 定义 POJO 类(如 User.java)
java
public class User {
private String username;
private String password;
private String role;
// 必须要有 setter 和 getter
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getRole() { return role; }
public void setRole(String password) { this.role = role; }
}
- 前端 HTML 表单
html
<form action="/user/login?role=admin" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
- Controller 中用 POJO 接收参数
java
@Controller
@RequestMapping("/user")
public class UserController {
@PostMapping("/login")
public String login(User user) {
// Spring 会自动把参数封装到 user 对象里
System.out.println("用户名: " + user.getUsername());
System.out.println("密码: " + user.getPassword());
System.out.println("角色: " + user.getRole());
return "success";
}
}
【注意】:省略的是:@ModelAttribute注解,SpringMVC 会默认使用,只要参数名匹配!
它的解析顺序大致如下:
先从请求 URL 中找参数
再从表单字段(POST)中找参数
两边都有,就以表单字段为准(POST 参数优先)
找到的参数会通过 JavaBean 的
setXxx()
注入到对象里
4、支持嵌套对象封装
你可以封装嵌套对象,比如:
java
public class Student {
private String name;
private Address address;
// getter/setter ...
}
public class Address {
private String city;
private String street;
// getter/setter ...
}
表单字段名需要使用点语法(Spring 自动识别):
html
<input name="name">
<input name="address.city">
<input name="address.street">
5、支持集合类型(List/Map)
如果你的类中有:
java
private List<String> hobbies;
你可以使用以下方式提交:
html
<input name="hobbies" value="唱歌">
<input name="hobbies" value="跳舞">
Spring 会自动将它封装成 List。
6、完整示例
功能目标
-
嵌套封装 :学生有地址信息(
Student
包含Address
) -
List 集合封装 :学生可以选多个兴趣爱好(
List<String>
) -
表单提交 → SpringMVC Controller → 自动封装 POJO → 打印输出
(1)、定义 POJO 类
Address.java
java
public class Address {
private String city;
private String street;
// getter 和 setter 必须有
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
}
Student.java
java
import java.util.List;
public class Student {
private String name;
private Address address;
private List<String> hobbies;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
public List<String> getHobbies() { return hobbies; }
public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
}
(2)、HTML 表单(studentForm.jsp
)
html
<form action="/student/register" method="post">
姓名:<input type="text" name="name"><br>
城市:<input type="text" name="address.city"><br>
街道:<input type="text" name="address.street"><br>
爱好:<br>
<input type="checkbox" name="hobbies" value="唱歌">唱歌<br>
<input type="checkbox" name="hobbies" value="跳舞">跳舞<br>
<input type="checkbox" name="hobbies" value="篮球">篮球<br>
<input type="submit" value="提交">
</form>
(3)、SpringMVC Controller(StudentController.java
)
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
@Controller
@RequestMapping("/student")
public class StudentController {
@PostMapping("/register")
public String register(Student student) {
// 输出接收到的学生信息
System.out.println("姓名: " + student.getName());
if (student.getAddress() != null) {
System.out.println("城市: " + student.getAddress().getCity());
System.out.println("街道: " + student.getAddress().getStreet());
}
if (student.getHobbies() != null) {
System.out.println("爱好: ");
for (String h : student.getHobbies()) {
System.out.println(" - " + h);
}
}
return "success"; // 视图名称
}
}
【注意】:
此时获取到的hobby的value是乱码的!因为是中文。
7、设置请求对象编码
乱码问题分为两种:
- get请求的乱码;
- post请求的乱码。
(1)、get请求的乱码
GET 请求的参数是放在 URL 地址栏里的,例如:http://localhost:8080/app?name=张三
这些参数在到达 Servlet
之前,Tomcat 已经解析好了 ,此时用的默认编码(早期是 ISO-8859-1
),你设置编码已来不及,乱码已经发生。
所以这是tomcat的问题,需要在tomcat的server.xml
中明确指定:
{Tomcat目录}/conf/server.xml

加上
URIEncoding="UTF-8"
就可以防止 GET 请求中文乱码。
(2)、post请求乱码
请求类型 | 参数位置 | 解决方式 |
---|---|---|
POST | 请求体 body | 使用 request.setCharacterEncoding("UTF-8") |
GET | URL 地址栏 | 设置 Tomcat 的 URIEncoding="UTF-8" |
【注意点】:必须在第一次获取参数之前设置编码!
一旦调用了以下任意方法:
java
request.getParameter()
request.getParameterMap()
request.getParameterNames()
request.getParameterValues()
Servlet 容器就会立即解析请求体,并把参数缓存起来。
如果你在调用之后再设置编码,就无效了,编码已经决定,不会重新解析请求体。
❌ 错误做法(设置编码太晚)
java
String name = request.getParameter("name"); // 已经触发解析
request.setCharacterEncoding("UTF-8"); // ✘ 已经没用了!
✅ 正确做法(先设置编码)
java
request.setCharacterEncoding("UTF-8"); // ✔ 先设置编码
String name = request.getParameter("name"); // 然后获取参数
但是应为此时我们用的是pojo获取请求参数,使用request.setCharacterEncoding("UTF-8");是无效的,应为dispatcherServlet已经解析了参数了!
所以用过滤器统一处理,因为,过滤器在servlet之前执行!
在web.xml中配置如下过滤器:
XML
<filter>
<filter-name>encodingFilter</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>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
5-7、【回顾】使用 @PathVariable
(获取 REST 风格路径参数)
java
@GetMapping("/user/{id}")
public String getUserById(@PathVariable("id") int id) {
System.out.println("id = " + id);
return "user";
}
5-8、使用 @RequestBody
(接收 JSON 数据)
java
@PostMapping("/user")
public String createUser(@RequestBody User user) {
System.out.println("user = " + user);
return "success";
}
-
会从 请求体中读取 JSON ,然后通过 Jackson 自动反序列化成
User
对象。 -
需要前端设置
Content-Type: application/json
。
需要前端发送 Content-Type: application/json
请求头,示例:
javascript
<!-- requestbody.html -->
<script>
function register() {
const user = {
username: "Alice",
email: "alice@example.com",
password: "123456"
};
fetch("/json/register", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(user)
}).then(response => {
if (response.ok) {
alert("Registered successfully!");
}
});
}
</script>
<button onclick="register()">Register via JSON</button>
五、SpringMVC 中的三种域对象
request
、session
、和servletContext
(application),它们统称为 "三大作用域对象"。
5-1、什么是域对象?
域对象(也叫作用域对象)是 Web 中用来 在不同范围内共享数据 的容器。
域对象 | 生命周期范围 | 使用场景 |
---|---|---|
request |
一次请求内有效 | 请求转发、表单处理 |
session |
一个用户会话内有效 | 登录状态、用户信息保存 |
servletContext |
整个 Web 应用范围内都有效(太大) | 全局参数、在线人数统计等 |
1、区分:什么是一"次请求",什么是一"次会话"
(1)、 什么是一"次请求"
一次请求 = 浏览器或客户端 发出的一次 HTTP 请求。它从你访问某个 URL 的那一刻开始,到服务器响应并返回结果为止。
判断是不是"一次请求":你可以在控制器方法中打印 request 对象的地址或哈希值:
java
@RequestMapping("/test")
public String test(HttpServletRequest request) {
System.out.println("request hash: " + request.hashCode());
return "success";
}
如果你在多个方法里都打了这个语句,只有同一个请求转发时(比如 forward:/page
),request.hashCode()
是相同的。
【注意】:
页面刷新或重新点击链接 → 就是新的请求!!!
即使访问的是同一个地址,但每点击一次或刷新一次,就是一个新的 request。
特点:生命周期短
-
请求来了就创建
-
响应完成就销毁
-
不同请求之间,
request
互不影响
(2)、一次会话(session)
一次会话 = 用户打开浏览器 → 访问网站 → 关闭浏览器或长时间不操作 → 会话结束。
浏览器不关、用户不断操作,这个会话就一直保持。
判断是不是"一次会话":打印 session ID
java
@RequestMapping("/checkSession")
public String checkSession(HttpSession session) {
System.out.println("session ID: " + session.getId());
return "session";
}
-
多次访问
/checkSession
,只要浏览器没关,session ID 不变,说明是同一个会话。 -
如果你关掉浏览器再访问,或等上20~30分钟,session ID 就会变,说明是新会话。
【注意】:
域名不同就不是同一个 session!
一般,同一个项目下共享 session!!!
情景:同一浏览器访问两个项目
http://localhost:8080/app1
http://localhost:8080/app2
虽然端口和浏览器一样,但项目上下文不同(app1 ≠ app2) ,默认是两个不同的 session,除非你显式配置 Cookie 的路径。
5-2、request
域对象
特点
-
生命周期:一次请求内有效
-
随着请求的完成而销毁(如访问页面、转发等)
-
适合存储:表单校验信息、错误提示、一次性数据传递
1、使用ServletAPI向request域对象共享数据
示例:
index.html页面:
html
<h2>test request scope value</h2>
<a th:href="@{/testRequestByServletApi}">set request attribute and then go to success page</a>
点击之后发送一次请求:http://localhost:8080/WsSpringMvc/testRequestByServletApi
java
@Controller
public class ScopeController {
@RequestMapping("/testRequestByServletApi")
public String testRequestByServletApi(HttpServletRequest request){
// 每一个域对象都有三种方法:
// setAttribute
// getAttribute
// removeAttribute
request.setAttribute("testRequestScope", "hello servletAPI");
return "successScope";
}
}
【注意】:
return "success"
是"请求转发" (forward)。在 Spring MVC 中,当你的控制器方法返回一个字符串(如
"success"
),默认行为是:
Spring 会将这个字符串当作视图名
然后交给视图解析器(ViewResolver)来处理
最终会使用请求转发(forward)到对应的页面
等价于:
javarequest.getRequestDispatcher("/WEB-INF/views/success.jsp").forward(request, response);
所以,这是一次请求转发,而不是重定向。
如果你想"重定向",需要显式写上:
javareturn "redirect:/someOtherPath";
返回值 | 行为 | 地址栏是否变化 | 请求是否共享 request 域 |
---|---|---|---|
"success" |
请求转发 | ❌ 不变 | ✅ 可以用 ${msg} 取值 |
"redirect:/xx" |
重定向 | ✅ 会变 | ❌ request 域不共享(已经不是一次请求了!) |
successScope.html页面
html
<body>
<h1>success</h1>
<p th:text="${testRequestScope}"></p>
</body>
【注意】:
在 Thymeleaf 中,
"${}"
表达式用于获取变量,但不同作用域(request、session、application)中的变量访问方式有所不同。
- Request 域(
HttpServletRequest
):
html<p th:text="${key}"></p>
- Session 域(
HttpSession
)
java<p th:text="${session.key}"></p>
- Application 域(
ServletContext
)
java<p th:text="${application.key}"></p>
2、使用ModelAndView向request域对象共享数据(Springmvc)
下面的2,3,4,5方式,都是Springmvc中提供的向request域对象共享数据的方法,最终原码都是包装成一个ModelAndView对象!
ModelAndView有model和view的功能:
- model主要用于向请求域共享数据;
- view用于设计视图,实现页面跳转!
示例:
java
@RequestMapping("/testModelAndViewApi")
public ModelAndView testModelAndViewApi(){
ModelAndView modelAndView = new ModelAndView();
// 处理model数据:即,向请求域request共享数据
modelAndView.addObject("testRequestScopeModelAndView", "hello modelAndView");
// 设置视图名称
modelAndView.setViewName("successScope");
return modelAndView;
}
【注意】:
返回值一定要是ModelAndView,因为要把视图返回给视图解析器!
3、使用Model向request域对象共享数据(Springmvc)

4、使用Map集合向request域对象共享数据(Springmvc)

map集合一般key就是string类型,value就是object类型!
5、使用ModelMap集合向request域对象共享数据(Springmvc)

5-3、Session域对象
使用方法:
java
@RequestMapping("/login")
public String login(HttpSession session) {
session.setAttribute("user", "Tom");
return "home";
}
-
获取 session:
HttpSession session
-
读取 session 数据:
session.getAttribute("user")
5-4、servletContext
(application)域对象
特点:
-
生命周期:整个 Web 应用运行期间有效
-
所有用户共享,全局作用域
-
适合存储:全局配置、网站访问量、缓存等
application域对象,范围太大了,用的最多的还是request和session!
使用方法:
java
@RequestMapping("/app")
public String applicationScope(HttpSession session) {
ServletContext context = session.getServletContext();
context.setAttribute("count", 100);
return "global";
}
也可以直接通过 @Autowired
注入:
java
@Autowired
ServletContext context;
5-5、总结一句话
你想用什么作用域对象(如 request、session、application),直接写在控制器方法参数中即可获取,Spring MVC 会自动注入,不用你手动 new 或额外配置。
示例:
java
@RequestMapping("/demo")
public String demo(HttpServletRequest request,
HttpSession session,
ServletContext context) {
request.setAttribute("reqData", "数据来自 request 域");
session.setAttribute("sessData", "数据来自 session 域");
context.setAttribute("appData", "数据来自 application 域");
return "success"; // 视图解析到 success.html 或 JSP
}