Spring Web MVC 是 Spring Framework Web 模块的核心组件 , 基于经典的 MVC (Model-View-Controller) 设及模式实现 , 是 Java 生态中主流的 Servlet 栈 Web 开发框架(运行在 Servlet 容器之上 , 如 Tomcat , Jetty)
通过解耦请求处理 , 业务逻辑 , 视图渲染等核心环节 , 简化 Java Web 应用开发 , 同时提供灵活的配置 , 强大的请求处理能力和丰富的扩展点 , 是开发传统服务端渲染 Web 应用 , RESTful API 的首选框架之一 , 也是 SpringBoot 中 Spring-Boot-Start-Web 的核心底层依赖
1. 核心设计理念
1.1 前端控制器模式
通过的那一入口 DispatcherServlet 接收所有的 HTTP 请求 , 统一分发至后续处理器 , 解耦请求入口与业务处理
1.2 组件化解耦
将请求处理流程拆分为多个独立组件(映射器 , 适配器 , 视图解析器等) , 组件间通过接口交互 , 可灵活替换或者自定义
1.3 注解驱动
通过简介的注解(如
@Controller、@RequestMapping)替代传统 XML 配置 , 大幅简化开发1.4 与 Spring 生态深度融合
天然支持 Spring 的依赖注入(DI) , 面向切面编程(AOP) , 事务管理等核心能力 , 业务层组件可直接注入 Web 层使用
2.核心概念
2.1MVC 模式

- **View(视图)**指在应用程序中专门用来与浏览器进行交互 , 展示数据的资源
- **Modek(模型)**是应用程序的主体部分 , 用来处理程序中数据逻辑的部分
- **Controller(控制器)**可以理解为一个分发器 , 用来决定对于视图发来的请求 , 需要用哪一个模型来处理 , 以及处理完后需要跳回到哪一个视图(连接视图和模型)
2.2 SpringMVC
基于 Servlet API 的 Web 框架,是 MVC 设计模式的具体实现,Spring Boot 通过引入 Spring Web 依赖即可使用 Spring MVC

2.3 与 SpringBoot 的关系
SpringBoot 是快速开发工具 , SpringMVC 是 Web 功能的核心 , SpringBoot 通过引入 Spring Web 依赖集成 SrpingMVC
3.核心功能与关键注解
Spring MVC 的核心是建立连接 , 处理请求 , 生成响应 , 关键注解及用法如下
3.1 建立连接
java
package com.boop.demo01;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/User2")
@RestController
public class UserController2 {
@RequestMapping("/m1")
public String m1(){
return "m1";
}
@RequestMapping(value = "/m2",method = RequestMethod.GET)
//@GetMapping("/m2")
public String m2(){
return "m2";
}
@RequestMapping(value = "/m3",method = RequestMethod.POST)
//@PostMapping("/m3")
public String m3(){
return "m3";
}
}
① @RequestMapping()
使用 @RequestMapping("/User2")注册路由路径 , 可以修饰类和方法 , 访问路径为类路径+方法路径 , 支持 GET , POST 多种请求方式 ;
- 标识类 : 设置映射请求的请求路径的具体信息(类路径)
- 标识方法 : 设置映射请求的请求路径的具体信息(方法路径)
- 格式 : http://127.0.0.1:8080 类路径 方法路径
- 访问示例 : http://127.0.0.1:8080/User2/m1
② @RestController
起到标识作用 , @RestController = @Controller+@ResponseBody 标识控制器类 , 使方法返回数据而非视图
如果去掉 @RestController
程序会报 404
③ 指定 GET / POST 方法类型
注意: 如果 method 有多个参数 , 则需要用大括号括起来
3.2 使用 PostMan 传参
下载链接:https://www.postman.com/downloads/
java
package com.boop.demo01;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/request")
@RestController
public class RequestController {
@RequestMapping("/r1")
public String r1 (String keyword){
return "接收参数"+ keyword;
}
}
① 普通传参
使用查询字符串传参
②form-data
multipart/form-data : 是一种 http 请求内容的格式 , 常用于 提交包含二进制数据的请求
- 前端的使用方式 : 在 HTML 的
<form>标签中,需添加属性enctype="multipart/form-data",以此指定表单提交时使用该格式 ; 核心用途:专门用于提交图片、文件等二进制数据(普通文本数据也可兼容,但更适配二进制内容的传输)
- 对应的请求头 : 该格式对应的 HTTP 请求头
Content-Type值为multipart/form-data,用于告知服务器请求体的编码方式使用抓包工具
③x-www-form-urlencoded
form 表单 , 对应 Content-Type: application/x-www-from-urlencoded
④raw
可以上传任意格式的文本 , 可以上传 text,json,xml,html 等
3.3 请求
访问不同的路径 , 就是发送不同的请求 , 在发送请求时 , 可能会带一些参数 , 所以学习 Spring 的请求 , 主要是学习如何传递参数到后端以及后端如何接收
以下为完整代码 :
java
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import model.UserInfo;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@RequestMapping("/request")
@RestController
public class RequestController {
@RequestMapping("/r1")
public String r1 (String keyword){
return "接收参数"+ keyword;
}
@RequestMapping("/r2")
public String r2(int keyword){
return "接收参数"+keyword;
}
@RequestMapping("/r3")
public String r3(Integer keyword){
return "接收参数"+keyword;
}
@RequestMapping("/r4")
public String r4(String userName, String password) {
return "接收参数: userName:"+userName + ", password:"+password;
}
//传递对象
@RequestMapping("/r5")
public String r5(UserInfo userInfo){
return "接收参数 : userInfo = " +userInfo.toString();
}
//重命名参数
//从前端接收 key , 赋值给keyword
@RequestMapping("/r6")
public String r6(@RequestParam("key") String keyword){
return "接收参数 + keyword="+keyword;
}
// @RequestMapping("/r6")
// public String r6(@RequestParam(value = "key",required = false) String keyword){
// return "接收参数 + keyword="+keyword;
// }
//传递数组
@RequestMapping("/r7")
public String r7(String[] arr){
return "接收参数:arr=" +Arrays.toString(arr);
}
//传递集合
@RequestMapping("/r8")
public String r8(@RequestParam List<String> list){
return "接收参数:list="+list;
}
//传递JSON
@RequestMapping("/r9")
public String r9(@RequestBody UserInfo userInfo){
return userInfo.toString();
}
// @RequestMapping("/r9")
// public String r9( UserInfo userInfo){
// return userInfo.toString();
// }
//获取URL 中参数
@RequestMapping("/r10/{type}/{ID}")
public String r10(@PathVariable("type") String Booktype,//将URL中 type 与参数 Booktype 进行绑定
@PathVariable Integer ID){//每个参数前都需要加 @PathVariable
return "获取文章类型:"+Booktype+"获取文章ID:"+ID;
}
// @RequestMapping("/article/{articleID}")
// public String r10(@PathVariable Integer articleID){
// return "获取文章ID : "+articleID;
// }
//上传文件
@RequestMapping("/r11")
public String r11(@RequestParam("wxfile") MultipartFile file) throws IOException {
//获取从前端上传的原始文件名
String filename = file.getOriginalFilename();
//直接将内存中的文件流写入本地指定目录
file.transferTo(new File("D:/Temp/"+filename));
return "接收文件为:"+filename;
}
//获取Cookie
@RequestMapping("/r12")
public String r12(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for(Cookie cookie:cookies){
System.out.println(cookie.getName()+":"+cookie.getValue());
}
}
return "返回Cookie成功";
}
//获取Cookie
@RequestMapping("/r13")
public String r13(@CookieValue("Java") String str1){
return "从Cookie获取Java的Value值"+str1;
}
//存储Session
@RequestMapping("/setSession")
public String setSession(HttpServletRequest request){
//从cookie中获取sessionID , 根据sessionID 获取session对象
//如果sessionID不存在 , 则创建
HttpSession session = request.getSession();
//默认存储在内存中
//登录的用户名称
session.setAttribute("userName","zhangsan");
session.setAttribute("age",17);
return "设置session成功";
}
//存储Session
@RequestMapping("/setSession2")
public String setsess(HttpSession session) {
// 直接注入的Session,不存在则自动创建
session.setAttribute("username2", "java123");
return "session 存储成功";
}
//获取session
@RequestMapping("/getSession1")
public String getSession(HttpServletRequest request){
//从cookie中获取sessionID , 根据sessionID 获取session对象
HttpSession session = request.getSession(false);
//如果用户登录 , session有值 ; 未登录 , sessionID为null
if (session == null) {
return "用户未登录";
}else {
//从session中获取登录用户的信息
String userName = (String) session.getAttribute("userName");
return "登录用户为 : "+userName;
}
}
//获取Session
@RequestMapping("/getSession2")
public String getSession2(HttpSession session){
//从session中获取登录用户的信息
String userName = (String)session.getAttribute("userName");
return "登录用户为 : "+userName;
}
//获取Session
@RequestMapping("/getSession3")
public String getSession3(@SessionAttribute("userName") String userName) {
return "登录用户为 : " + userName;
}
//获取Header
@RequestMapping("/getheader1")
public String getheader1(HttpServletRequest request){
String UserAgent = request.getHeader("User-Agent");
return "User-Agent:"+UserAgent;
}
//获取Header
@RequestMapping("/getheader2")
public String getheader2(@RequestHeader("User-Agent") String userAgent){
return "userAgent:"+userAgent;
}
}
① 传递单个参数
使用 postman 发送请求并传参
java
@RequestMapping("/r1")
public String r1 (String keyword){
return "接收参数"+ keyword;
}
@RequestMapping("/r2")
public String r2(int keyword){
return "接收参数"+keyword;
}
@RequestMapping("/r3")
public String r3(Integer keyword){
return "接收参数"+keyword;
}
http://127.0.0.1:8080/request/r1?keyword=abc
http://127.0.0.1:8080/request/r2?keyword=123
http://127.0.0.1:8080/request/r3?keyword=123
注意 :
- 使用基本类型来接收参数时 , 参数必须传 , boolean 类型除外 , 否则报 500 错误
- 类型不匹配 , 则会报 400 错误
- 对于参数可能为空的数据建议使用包装类型
② 传递多个参数
java
@RequestMapping("/r4")
public String r4(String userName, String password) {
return "接收参数: userName:"+userName + ", password:"+password;
}
使用 postman 发送请求并传参http://127.0.0.1:8080/request/r4?userName=zhangsan&password=123456

注意 : 但有多个参数时 , 前后端进行参数匹配时 , 是以参数的名称进行匹配的 , 因此参数的位置是不影响后端获取参数的结果
③ 传递对象
参数比较多时 , 方法声明就需要很多形参 . 并且后续每次新增一个参数 , 也需要修改方法声明 ; 不妨把这些参数封装为一个对象
java
package model;
public class UserInfo {
private String name;
private int gender;
private int age;
public UserInfo() {
}
public UserInfo(String name, int gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getGender() {
return gender;
}
public void setGender(Integer gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "UserInfo{" +
"name='" + name + '\'' +
", gender=" + gender +
", age=" + age +
'}';
}
}
java
//传递对象
@RequestMapping("/r5")
public String r5(UserInfo userInfo){
return "接收参数 : userInfo = " +userInfo.toString();
}
使用 postman 发送请求并传参http://127.0.0.1:8080/request/r5?name=zhansan&gender=1&age=18

④ 后端参数重命名 @ResquestParam
**前面的传参都需要保持 后端参数 和 前端参数 命名统一 ;**如果参数命名不一致就会出现参数接收不到的情况 ; 这种情况需要使用@ResquestParam 来重命名后端参数值
java
//重命名参数
//从前端接收 key , 赋值给keyword
@RequestMapping("/r6")
public String r6(@RequestParam("key") String keyword){
return "接收参数 + keyword="+keyword;
}
使用 postman 发送请求并传参http://127.0.0.1:8080/request/r6?key=abc

注意 :
- 使用@ResquestParam 进行参数重命名时 , 请求参数只能和@ResquestParam 声明的名称一致 , 才能进行参数绑定
- 使用@ResquestParam 进行参数重命名时,参数就成了必传参数
- 设置成非必传参数
⑤ 传递数组
java
//传递数组
@RequestMapping("/r7")
public String r7(String[] arr){
return "接收参数:arr=" +Arrays.toString(arr);
}
方法 1:
传参时 , 参数名都相同 , 就会按数组接收
使用 postman 发送请求并传参: http://127.0.0.1:8080/request/r7?arr=abc&arr=hsa&arr=hja
方法 2:
直接传数组
使用 postman 发送请求并传参: http://127.0.0.1:8080/request/r7?arr=abc,def,hjk,plk
⑥ 传递集合
和数组类似 , 且需要使用@RequestParam
java//传递集合 @RequestMapping("/r8") public String r8(@RequestParam List<String> list){ return "接收参数:list="+list; }
⑦ 传递 JSON 数据 @RequestBody
使用@RequestBody 接收 请求体中的 JSON 数据
第一步 : 后端实现
java//传递JSON @RequestMapping("/r9") public String r9(@RequestBody UserInfo userInfo){ return userInfo.toString(); }第二步:使用 postman 来发送 JSON 请求参数
http://127.0.0.1:8080/request/r9
java{ "name": "张三", "gender": 1, "age": 18 }注意 : 如果去掉@RequestBody
⑧ 获取 URL 中参数 @PathVariable
pathvariable : 路径变量
作用 : 在请求 URL 路径上的数据绑定
java//获取URL 中参数 @RequestMapping("/article/{articleID}") public String r10(@PathVariable Integer articleID){ return "获取文章ID : "+articleID; }多个参数 :
java//获取URL 中参数 @RequestMapping("/r10/{type}/{ID}") public String r10(@PathVariable("type") String Booktype,//将URL中 type 与参数 Booktype 进行绑定 @PathVariable Integer ID){//每个参数前都需要加 @PathVariable return "获取文章类型:"+Booktype+"获取文章ID:"+ID; }使用 postman 发送请求http://127.0.0.1:8080/request/r10/Geography/122548
注意 :
- 每个参数前都需要加@PathVariable;
- 变量名称规范(不一致需要 对@PathVariable 加参数)
⑨ 上传文件 @RequestPart
java//上传文件 @RequestMapping("/r11") public String r11(@RequestParam("wxfile") MultipartFile file) throws IOException { //获取从前端上传的原始文件名 String filename = file.getOriginalFilename(); //直接将内存中的文件流写入本地指定目录 file.transferTo(new File("D:/Temp/"+filename)); return "接收文件为:"+filename; }使用 POSTMAN 发送请求 : http://127.0.0.1:8080/request/r11
本地目录上传成功
⑩ 获取 Cookie/Session
Cookie
是客户端浏览器 的轻量级文本数据,由服务器通过
Set-CookieHTTP响应头下发给客户端,客户端会将其保存,后续向同一服务器发送请求时,会自动通过CookieHTTP请求头携带该数据,实现客户端侧的会话标识。
- 存储位置:客户端浏览器(内存/本地文件,依Cookie属性而定);
- 核心作用:存储会话令牌(SessionId)、少量非敏感的用户信息;
- 特性:可被客户端修改/伪造,因此后端使用Cookie时必须做校验
Session
是服务器端 为每个客户端创建的专属会话对象 ,本质是一个哈希表(键值对) ,
Key为唯一的SessionId (服务器生成的字符串),Value为自定义的用户信息(如登录名、用户ID)。
- 存储位置:默认在服务器内存中;
- 核心作用:存储敏感的用户会话信息,避免在客户端明文传输;
- 核心流程 :
- 客户端首次请求服务器时,服务器创建Session并生成唯一SessionId,通过
Set-Cookie: JSESSIONID=xxx响应头下发给客户端;- 客户端将SessionId保存到Cookie中,后续请求时通过
Cookie: JSESSIONID=xxx携带;- 服务器通过请求中的SessionId匹配对应的Session对象,实现服务端侧的会话跟踪
Cookie 和 Session 区别
- Cookie 是客户端保存用户信息的一种机制 , Session 是服务器端保存用户信息的一种机制
- Cookie 和 Session 之间主要通过 SessionID 关联起来 , SessionID 是 Cookie 和 Session 之间的桥梁
- Cookie 和 Session 经常会在一起配合使用(完全可以用 Cookie 来保存一些数据在客户端 ; Session 中的 SessionID 也可以不通过 Cookie/Set-Cookie 传递)
获取 Cookie
Spring MVC 基于 Servlet API 构建 , 内置 HttpSevletRequest/HttpServletResponse 对象 , 可直接在方法参数中声明使用 , 也可以通过注解式的简介获取方式;
方法一 : 通过
HttpServletRequest获取
java//获取Cookie @RequestMapping("/r12") public String r12(HttpServletRequest request){ Cookie[] cookies = request.getCookies(); if (cookies != null) { for(Cookie cookie:cookies){ System.out.println(cookie.getName()+":"+cookie.getValue()); } } return "返回Cookie成功"; }
- 通过 HttpServletRequest.getCookie()获取 所有 Cookie 数组 , 需遍历数组并判空 , 根据 Cookie 的 getName()匹配目标 Cookie
- 必须对 cookies 数组做判空处理 , 否则客户端未携带 cookie 时 , 会抛出 NullPointerException
使用 postman 发送请求http://127.0.0.1:8080/request/r12
方法二 : 通过
@CookieValue注解直接绑定
java//获取Cookie @RequestMapping("/r13") public String r13(@CookieValue("Java") String str1){ return "从Cookie获取Java的Value值"+str1; }
- 通过@CookieValue 注解指定 Cookie 名称 , 直接将目标 Cookie 的值绑定到方法参数 , 简化遍历操作 (注解默认必传)
- 或者设置为非必传 @CookieValue( value ="Java", required =false)
- 缺点 是 一次只能处理一个
使用 postman 发送请求(和方法一一样的 cookie)http://127.0.0.1:8080/request/r13
存储 Session
Session 是服务器端的机制 , 需要先存储才能获取 ; Session 也是基于 HttpServletRequest 来存储和获取的
方法一 : 通过 HttpServletRequest 获取 Session 后存储
java//存储Session @RequestMapping("/setSession") public String setSession(HttpServletRequest request){ //从cookie中获取sessionID , 根据sessionID 获取session对象 //如果sessionID不存在 , 则创建 HttpSession session = request.getSession(); //默认存储在内存中 //登录的用户名称 session.setAttribute("userName","zhangsan"); session.setAttribute("age",17); return "设置session成功"; }使用 Postman 来发送请求http://127.0.0.1:8080/request/setSession
使用抓包工具抓取
方法二 : 直接在方法参数中注入 HttpSession
java//存储Session @RequestMapping("/setSession2") public String setsess(HttpSession session) { // 直接注入的Session,不存在则自动创建 session.setAttribute("username2", "java123"); return "session 存储成功"; }
获取session
方法一 : 通过 HeepServletRequest 获取 Session 后存储
java//获取session @RequestMapping("/getSession1") public String getSession(HttpServletRequest request){ //从cookie中获取sessionID , 根据sessionID 获取session对象 HttpSession session = request.getSession(false); //如果用户登录 , session有值 ; 未登录 , sessionID为null if (session == null) { return "用户未登录"; }else { //从session中获取登录用户的信息 String userName = (String) session.getAttribute("userName"); return "登录用户为 : "+userName; } }使用 postman 发送请求http://127.0.0.1:8080/request/getSession1
Objetc.getAttritube(String name) : 返回在该 session 会话中具有指定名称的对象 , 如果没有指定名称的对象 , 则返回 null
方法二 : 通过
@SessionAttribute注解直接绑定
java//获取Session @RequestMapping("/getSession2") public String getSession2(HttpSession session){ //从session中获取登录用户的信息 String userName = (String)session.getAttribute("userName"); return "登录用户为 : "+userName; }使用 postman 发送请求http://127.0.0.1:8080/request/getSession2
方法三 : 直接注入 HttpSession 对象查询
java//获取Session @RequestMapping("/getSession3") public String getSession3(@SessionAttribute("userName") String userName) { return "登录用户为 : " + userName; }使用 postman 发送请求http://127.0.0.1:8080/request/getSession3
⑪ 获取 Header
方法一 : 通过 HttpServletRequest 获取
java//获取Header @RequestMapping("/getheader1") public String getheader1(HttpServletRequest request){ String UserAgent = request.getHeader("User-Agent"); return "User-Agent:"+UserAgent; }
- 使用 postman 发送请求http://127.0.0.1:8080/request/getheader1
- 通过 Fiddler 观察 , 获取的 User-Agent 是否正确
方法二 : 通过注解@RequestHeader 的参数值为 Http 请求报头中的"Key"
java//获取Header @RequestMapping("/getheader2") public String getheader2(@RequestHeader("User-Agent") String userAgent){ return "userAgent:"+userAgent; }使用 postman 发送请求http://127.0.0.1:8080/request/getheader2



































