通过本文我们将:
- 学习常见的 Spring Web MVC 注解
- 能够使用 Spring MVC 来完成基础的功能开发
- 了解 MVC 和三层架构的设计模式
- 掌握企业开发中的一些命名规范
文章目录
- [一、什么是 Spring Web MVC?](#一、什么是 Spring Web MVC?)
-
- [1.1 MVC 定义](#1.1 MVC 定义)
- [1.2 什么是 Spring MVC?](#1.2 什么是 Spring MVC?)
- [二、Spring MVC 入门](#二、Spring MVC 入门)
-
- [2.1 项目准备](#2.1 项目准备)
- [2.2 建立连接](#2.2 建立连接)
-
- [2.2.1 @RequestMapping 注解的介绍](#2.2.1 @RequestMapping 注解的介绍)
- [2.2.2 @RequestMapping 注解的使用](#2.2.2 @RequestMapping 注解的使用)
- [2.2.3 @RequestMapping 是 GET 还是 POST 请求?](#2.2.3 @RequestMapping 是 GET 还是 POST 请求?)
- [2.3 Postman 的介绍](#2.3 Postman 的介绍)
-
- [2.3.1 下载安装 Postman](#2.3.1 下载安装 Postman)
- [2.3.2 创建请求](#2.3.2 创建请求)
- [2.3.3 参数传递介绍](#2.3.3 参数传递介绍)
- [2.4 请求](#2.4 请求)
-
- [2.4.1 传递单个参数](#2.4.1 传递单个参数)
- [2.4.2 传递多个参数](#2.4.2 传递多个参数)
- [2.4.3 传递对象](#2.4.3 传递对象)
- [2.4.4 后端参数重命名(后端参数映射)](#2.4.4 后端参数重命名(后端参数映射))
- [2.4.5 传递数组](#2.4.5 传递数组)
- [2.4.6 传递集合](#2.4.6 传递集合)
- [2.4.7 传递 JSON 数据](#2.4.7 传递 JSON 数据)
-
- [JSON 的语法介绍](#JSON 的语法介绍)
- [JSON 字符串和 Java 对象相互转换](#JSON 字符串和 Java 对象相互转换)
- [JSON 优点](#JSON 优点)
- [传递 JSON 对象](#传递 JSON 对象)
- [2.4.8 获取 URL 中参数 @PathVariable](#2.4.8 获取 URL 中参数 @PathVariable)
- [2.4.9 上传文件 @RequestPart](#2.4.9 上传文件 @RequestPart)
- [2.4.10 获取 Cookie/Session](#2.4.10 获取 Cookie/Session)
-
- [回顾 Cookie](#回顾 Cookie)
一、什么是 Spring Web MVC?
官方对于 Spring MVC 的描述如下:
- Spring Web MVC is the original web framework built on the Servlet API and has been included in the Spring Framework from the very beginning. The formal name, "Spring Web MVC," comes from the name of its source module (spring-webmvc), but it is more commonly known as "Spring MVC".
中文意为:
Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架,自 Spring Framework 诞生之初就已包含其中。其正式名称"Spring Web MVC"源自其源码模块的名称(spring-webmvc),但更常被称为"Spring MVC"。
那什么是 Servlet 呢?
- Servlet 是一种运行在 Web 服务器或应用服务器上的程序,它充当客户端请求与服务器资源之间的中介。Servlet 使得开发人员可以通过 Java 编写的程序来动态生成 Web 内容、处理表单数据、管理状态信息以及与 Web 服务器上的数据库和应用程序交互。
- Servlet 是一种实现动态页面的技术。准确来讲 Servlet 是一套 Java Web 开发的规范,或者说是一套 Java Web 开发的技术标准。但是只有规范并不能做任何事情,必须要有人去实现它。所谓实现 Servlet 规范,就是真正编写代码去实现 Servlet 规范提到的各种功能,包括类、方法、属性等。Servlet 规范是开放的,除了 Sun 公司,其它公司也可以实现 Servlet 规范,目前常见的实现了 Servlet 规范的产品包括 Tomcat、Weblogic、Jetty、Jboss、WebSphere 等,它们都被称为 "Servlet 容器"。Servlet 容器用来管理程序员编写的 Servlet 类。
现在我们大概知道:Spring Web MVC 是一个 Web 框架,并且可以称之为 "Spring MVC"。
但是我们又有一个疑问:什么是 MVC?
1.1 MVC 定义
MVC 是 Model View Controller 的缩写,它是软件工程中的一种软件架构设计模式,把软件系统分为 模型、视图 和 控制器 三个基本部分。
#mermaid-svg-ZOTzsZxfnikQqYKM{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZOTzsZxfnikQqYKM .error-icon{fill:#552222;}#mermaid-svg-ZOTzsZxfnikQqYKM .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZOTzsZxfnikQqYKM .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZOTzsZxfnikQqYKM .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZOTzsZxfnikQqYKM .marker.cross{stroke:#333333;}#mermaid-svg-ZOTzsZxfnikQqYKM svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZOTzsZxfnikQqYKM p{margin:0;}#mermaid-svg-ZOTzsZxfnikQqYKM .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster-label text{fill:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster-label span{color:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster-label span p{background-color:transparent;}#mermaid-svg-ZOTzsZxfnikQqYKM .label text,#mermaid-svg-ZOTzsZxfnikQqYKM span{fill:#333;color:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM .node rect,#mermaid-svg-ZOTzsZxfnikQqYKM .node circle,#mermaid-svg-ZOTzsZxfnikQqYKM .node ellipse,#mermaid-svg-ZOTzsZxfnikQqYKM .node polygon,#mermaid-svg-ZOTzsZxfnikQqYKM .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZOTzsZxfnikQqYKM .rough-node .label text,#mermaid-svg-ZOTzsZxfnikQqYKM .node .label text,#mermaid-svg-ZOTzsZxfnikQqYKM .image-shape .label,#mermaid-svg-ZOTzsZxfnikQqYKM .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZOTzsZxfnikQqYKM .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZOTzsZxfnikQqYKM .rough-node .label,#mermaid-svg-ZOTzsZxfnikQqYKM .node .label,#mermaid-svg-ZOTzsZxfnikQqYKM .image-shape .label,#mermaid-svg-ZOTzsZxfnikQqYKM .icon-shape .label{text-align:center;}#mermaid-svg-ZOTzsZxfnikQqYKM .node.clickable{cursor:pointer;}#mermaid-svg-ZOTzsZxfnikQqYKM .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZOTzsZxfnikQqYKM .arrowheadPath{fill:#333333;}#mermaid-svg-ZOTzsZxfnikQqYKM .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZOTzsZxfnikQqYKM .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZOTzsZxfnikQqYKM .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZOTzsZxfnikQqYKM .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZOTzsZxfnikQqYKM .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZOTzsZxfnikQqYKM .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster text{fill:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM .cluster span{color:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZOTzsZxfnikQqYKM .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZOTzsZxfnikQqYKM rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZOTzsZxfnikQqYKM .icon-shape,#mermaid-svg-ZOTzsZxfnikQqYKM .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZOTzsZxfnikQqYKM .icon-shape p,#mermaid-svg-ZOTzsZxfnikQqYKM .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZOTzsZxfnikQqYKM .icon-shape .label rect,#mermaid-svg-ZOTzsZxfnikQqYKM .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZOTzsZxfnikQqYKM .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZOTzsZxfnikQqYKM .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZOTzsZxfnikQqYKM :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Model(模型)
Controller(控制器)
View(视图)
- 请求
- 选择模型进行处理
- 返回处理结果
- 选择响应模板
填充数据后返回
界面显示
人机交互
选择处理模型
选择视图
处理业务逻辑
处理数据
- View(视图):指在应用程序中专门用来与浏览器进行交互,展示数据的资源。
- Model(模型):是应用程序的主体部分,用来处理程序中数据逻辑的部分。
- Controller(控制器):可以将其理解为一个分发器,负责调解视图和模型。对于视图发来的请求选择哪个模型来处理以及处理完毕后的数据返回哪个视图。
1.2 什么是 Spring MVC?
MVC 是一种架构设计模式,也是一种思想,而 Spring MVC 则是对 MVC 思想的具体实现。
除此之外,Spring MVC 还是一个 Web 框架。即------ Spring MVC 是一个实现了 MVC 模式的 Web 框架。
因此我们需要关注的是:
- MVC 模式
- Web 框架
其实,Spring MVC 我们之前已经使用过了,在创建 Spring Boot 项目的时候,我们勾选的 Spring Web 框架指的就是 Spring MVC 框架。
Spring Web 的介绍是:
- Build web, including RESTful, applications using Spring MVC. Uses Apache Tomcat as the default embedded container.
- 译为:(Spring Boot)使用 Spring MVC 构建 Web 应用程序,包括 RESTful 应用。默认采用 Apache Tomcat 作为嵌入式容器。
其实很容易看出,Spring Boot 是实现 Spring MVC 的一种方式。
我们知道,Spring Boot 可以通过添加依赖实现不同的功能,因此也可以通过添加 Spring Web MVC 框架,来实现 Web 功能。
不过,Spring Boot 在实现 MVC 的时候,结合自身项目的特点,做了点改变:
#mermaid-svg-tOoKH6ru5JelZvzJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-tOoKH6ru5JelZvzJ .error-icon{fill:#552222;}#mermaid-svg-tOoKH6ru5JelZvzJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-tOoKH6ru5JelZvzJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-tOoKH6ru5JelZvzJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-tOoKH6ru5JelZvzJ .marker.cross{stroke:#333333;}#mermaid-svg-tOoKH6ru5JelZvzJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-tOoKH6ru5JelZvzJ p{margin:0;}#mermaid-svg-tOoKH6ru5JelZvzJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster-label text{fill:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster-label span{color:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster-label span p{background-color:transparent;}#mermaid-svg-tOoKH6ru5JelZvzJ .label text,#mermaid-svg-tOoKH6ru5JelZvzJ span{fill:#333;color:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ .node rect,#mermaid-svg-tOoKH6ru5JelZvzJ .node circle,#mermaid-svg-tOoKH6ru5JelZvzJ .node ellipse,#mermaid-svg-tOoKH6ru5JelZvzJ .node polygon,#mermaid-svg-tOoKH6ru5JelZvzJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-tOoKH6ru5JelZvzJ .rough-node .label text,#mermaid-svg-tOoKH6ru5JelZvzJ .node .label text,#mermaid-svg-tOoKH6ru5JelZvzJ .image-shape .label,#mermaid-svg-tOoKH6ru5JelZvzJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-tOoKH6ru5JelZvzJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-tOoKH6ru5JelZvzJ .rough-node .label,#mermaid-svg-tOoKH6ru5JelZvzJ .node .label,#mermaid-svg-tOoKH6ru5JelZvzJ .image-shape .label,#mermaid-svg-tOoKH6ru5JelZvzJ .icon-shape .label{text-align:center;}#mermaid-svg-tOoKH6ru5JelZvzJ .node.clickable{cursor:pointer;}#mermaid-svg-tOoKH6ru5JelZvzJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-tOoKH6ru5JelZvzJ .arrowheadPath{fill:#333333;}#mermaid-svg-tOoKH6ru5JelZvzJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-tOoKH6ru5JelZvzJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-tOoKH6ru5JelZvzJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tOoKH6ru5JelZvzJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-tOoKH6ru5JelZvzJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tOoKH6ru5JelZvzJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster text{fill:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ .cluster span{color:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-tOoKH6ru5JelZvzJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-tOoKH6ru5JelZvzJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-tOoKH6ru5JelZvzJ .icon-shape,#mermaid-svg-tOoKH6ru5JelZvzJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-tOoKH6ru5JelZvzJ .icon-shape p,#mermaid-svg-tOoKH6ru5JelZvzJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-tOoKH6ru5JelZvzJ .icon-shape .label rect,#mermaid-svg-tOoKH6ru5JelZvzJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-tOoKH6ru5JelZvzJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-tOoKH6ru5JelZvzJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-tOoKH6ru5JelZvzJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Model(模型)
Controller(控制器)
View(视图)
- 请求
- 选择模型进行处理
- 返回处理结果
- 选择响应模板
选择视图
填充数据后返回响应
5. 返回响应
界面排版布局
展示模型数据
接收用户请求
选择处理模型
选择视图
浏览器
处理业务逻辑
处理数据
二、Spring MVC 入门
我们学习的 Spring MVC 是一个 Web 框架,当用户在浏览器的地址栏中输入 URL 并按回车时,我们的 Spring MVC 项目就可以接收到用户发送来的请求,并给予响应。
我们学习的重点是 "如何通过浏览器和用户程序进行交互",主要是以下三个方面:
- 建立连接: 将用户/浏览器和 Java 程序连接起来,即通过访问一个 URL 地址来对应到我们的 Spring 程序。
- 请求: 用户请求的时候会带一些参数,在程序中要想办法获取到这些参数,所以请求这块主要是获取参数的功能。
- 响应: 业务逻辑执行完毕之后,要将执行后的结果返回给用户。
比如用户去银行存款:
- 建立连接:去柜台
- 请求:带着银行卡、身份证去存款
- 响应:银行返回一张存折
掌握了以上三个功能就相当于掌握了 Spring MVC。
2.1 项目准备
Spring MVC 项目的创建和 【JavaEE】Spring Boot 快速上手 一文中的过程相同,在创建的时候只需要选择 Spring Web 依赖即可。(具体操作可以点击连接移步至文章阅读)
2.2 建立连接
2.2.1 @RequestMapping 注解的介绍
在 Spring MVC 中我们使用 @RequestMapping 来实现 URL(地址)路由映射,作为浏览器连接 Spring 程序的入口。
- 路由映射:当用户访问一个 URL 时,将用户的请求对应到程序中的某个类的某个方法的过程就叫路由映射。
我们创建 UserController 类,实现用户通过浏览器和程序交互的功能:
java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@RequestMapping("/hello")
public String hello() {
return "Hello World!";
}
}
在方法 hello 的上方我们添加了一个注解 @RequestMapping,括号内是映射的路径。
@RequestMapping 是 Spring MVC 应用程序中最常被用到的注解之一,它是用来注册接口的路由映射的,说直白点就是标识方法的门牌号。当服务收到请求,路径为 "/hello" 的请求就会调用 hello 这个方法并执行(方法名和路径名无需一致)。
当程序启动之后,我们在浏览器中的 URL 栏输入:http://127.0.0.1:8080/hello,然后点击回车:

那么,@RestController 有什么作用呢?当我们将该注解删去后再运行、访问,就会得到如下结果:

在一个项目中,会有很多类(自己写的类或者外部引入的类),并且每个类有可能有很多方法,那么 Spring 程序就会将所有类挨个扫描。
如果某个类加了注解 @RestController,Spring 就会优先扫描这个类,看看是否有 @RequestMapping。(此注解的作用当然不止这一点,往后再详细讲)
2.2.2 @RequestMapping 注解的使用
我们说回 @RequestMapping,该注解 既可以修饰类,也可以修饰方法。
@RequestMapping修饰一个类:设置映射请求的请求路径的初始信息@RequestMapping修饰一个方法:设置映射请求的请求路径的具体信息
当该注解同时修饰类又修饰方法时,访问的路径为:类路径 + 方法路径。
java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping("/hello")
public String hello() {
return "Hello World!";
}
}
注意:
@RequestMapping的 URL 路径最前面也可以不加/(斜杠符号),Spring 程序启动时,会进行判断,若路径前面没有/会自动拼接上。- 通常情况下我们都是加上
/的。
java
@RequestMapping("user")
@RestController
public class UserController {
@RequestMapping("hello")
public String hello() {
return "Hello World!";
}
}
启动项目后,访问地址:http://127.0.0.1:8080/user/hello,结果如下:

可以看到,成功通过浏览器访问我们的 Spring 项目了~
对于 @RequestMapping 的 URL 路径,我们也可以设置多层路径,访问时依然为:类路径 + 方法路径。
java
@RequestMapping("/user/example")
@RestController
public class UserController {
@RequestMapping("/hello/world")
public String hello() {
return "Hello World!";
}
}
例如,现在我将类路径改为:/user/example;方法路径改为:/hello/world,启动项目之后通过浏览器输入:http://127.0.0.1:8080/user/example/hello/world

可以发现,依然是可以访问的~
2.2.3 @RequestMapping 是 GET 还是 POST 请求?
@RequestMapping 既支持 GET 请求,又支持 POST 请求。 其他请求也是支持的。
如果我们需要指定请求方式,可以显式指定 @RequestMapping:
java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
@RequestMapping(value = "/hello", method = RequestMethod.POST)
public String hello() {
return "Hello World!";
}
}
value 中的值就是路径,method 的值就是指定的请求方法,我们这里指定为 POST 方法,那么只能通过 POST 请求来访问这个方法。
也可以使用 @PostMapping 来修饰 hello 方法,表示该方法只能通过 POST 请求来访问:
java
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class UserController {
@PostMapping("/hello")
public String hello() {
return "Hello World!";
}
}
同理,若要指定 GET 请求或是其他请求,也可以用以上两种方式来指定。
2.3 Postman 的介绍
上面我们测试后端的方法主要采用的是 "通过浏览器" 这一方法,必要时还需要写前端代码,这太过麻烦了。
随着互联网的发展、项目难度的增加,企业也按照开发的功能,把开发人员分成不同的团队:界面显示交给 "前端开发工程师",业务逻辑的实现交给 "后端开发工程师",实现前后端分离。
这样一来,后端开发不需要写前端的代码,但是也需要测试自己写的程序,怎么办呢?
通过专业的接口测试工具即可,我们在这里介绍的就是 Postman。
2.3.1 下载安装 Postman
下载链接:Postman 官网

点击下载安装即可,安装完成后可选择不更新。
2.3.2 创建请求
点击 "create collection",然后点击右键创建一个 HTTP 请求:

2.3.3 参数传递介绍
-
普通传参 (即通过 URL 上的查询字符串来传参)
学习 HTTP 时,我们知道 URL 能够访问互联网上的某一个资源,并且知道 URL 中
?符号的后面部分就是查询字符串,URL 的格式如下:
我们通过 Postman 填入参数,就会自动帮我们将参数拼接到 URL 的查询字符串中:

-
form-data (完整表示为:multipart/form-data)
表单提交的数据,在 form 标签中加上
enctyped="multipart/form-data",通常用于提交图片/文件,对应Content-Type:multipart/form-data
-
x-www-form-urlencoded
form 表单,对应
Content-Type:application/x-www-form-urlencoded
-
raw
可以上传任意格式的文本,可以上传
text、json、xml、html等
2.4 请求
访问不同的 URL 路径,就是发送不同的请求。
在发送请求的时候,可能会带一些参数,因此我们学习 Spring 的请求,主要是学习 如何传递参数到后端 以及 后端如何接收这些参数。
我们主要通过 浏览器 和 Postman 来模拟参数的传递。
- 后端开发人员无需过度关注如何传递参数,了解即可,实际开发中以 Postman 测试为主
2.4.1 传递单个参数
接收单个参数,在 Spring MVC 中直接使用方法中的参数即可:
java
@RestController
@RequestMapping("/param")
public class ParamController {
@RequestMapping("/m1")
public String method1 (String name) {
return "接收到参数name: " + name;
}
}
运行项目后,通过浏览器输入 URL:http://127.0.0.1:8080/param/m1?name=spring。

可以看到,后端程序成功拿到了参数 name 的值。
- Spring MVC 会根据方法的参数名,在 URL 的查询字符串中找到对应的参数,然后赋值给该方法的参数。
- 若 URL 上查询字符串的参数名与方法参数名不一致,就无法获取到:
还有一个必须要注意的点:使用基本类型(除了布尔类型 boolean)来接收参数时,输入的 URL 的查询字符串中必须要有参数,否则会报 500 错误(当参数的类型与传的参数不匹配时,会报 400 错误)。
下面给出例子,以便体会。
java
@RequestMapping("/m1/int")
public Object methodGetInt (int age) {
return "接收到参数age: " + age;
}
-
正常传递 age 参数
通过浏览器访问 http://127.0.0.1:8080/param/m1/int?age=1:

通过 Fiddler(关于该抓包工具在文章【网络原理】HTTP 协议和 HTTPS 协议 中有详细介绍)观察请求和响应情况:HTTP 的响应状态码为 200,表示正常响应;
Content-Type为text/html:
-
不传递 age 参数
通过浏览器输入:http://127.0.0.1:8080/param/m1/int,响应情况:

此时的 HTTP 响应状态码为 500,表示服务端出错,这时候要尝试观察程序的错误日志并解决:

一般看日志堆栈信息的首行,报错信息显示:int 类型的参数 "age" 虽然是可选的,但由于被声明为基本类型而不能转换为空值,考虑将其声明为对应基本类型的包装类型。 我们根据错误信息解决对应的错误即可。
-
传递的参数与方法参数类型不匹配
我们通过浏览器访问:http://127.0.0.1:8080/param/m1/int?age=abc,观察响应情况:

可以发现,HTTP 响应状态码为 400,说明是客户端出错,URL 地址不正确。由于方法参数是 int 类型的,这里 URL 中的参数值 "abc" 是字符串类型,显然不匹配,因此报错。
对于包装类型,如果访问时不传入对应的参数,Spring 接收到的数据则是 null,不会报错,因此企业开发中对于参数可能为空的数据,建议使用包装类型。
2.4.2 传递多个参数
接收多个参数和接收单个参数一样,直接通过方法的参数来接收:
java
@RequestMapping("/m2")
public Object method2 (String name, String password) {
return "接收到参数name: " + name + ", password: " + password;
}
启动程序后通过浏览器访问:http://127.0.0.1:8080/param/m2?name=admin\&password=123456:
后端程序正确地拿到了两个参数的值。

当有多个参数传递时,是以参数的名称进行匹配的,所以参数的位置不会影响参数的获取。

2.4.3 传递对象
如果参数比较多,方法声明就需要有很多参数,而且如果后续还需要增加参数,也必须同步修改方法声明。
因此我们可以将这些参数封装为一个对象,在方法声明处将对象作为参数。
Spring MVC 也可以自动实现对象参数的赋值。
下面给出一个例子。
java
public class Person {
private int id;
private String name;
private String password;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
传递对象的 controller 代码实现:
java
@RequestMapping("/m3")
public Object method3 (Person person) {
return person.toString();
}
通过浏览器访问:http://127.0.0.1:8080/param/m3?id=5\&name=zhangsan\&password=123456,观察响应情况:

Spring 会根据参数的名称自动绑定到对象的各个属性上,从而对属性进行赋值。如果某个属性未传递,则会赋值为 null(基本类型则赋值为默认的初始值,如 int 初始值为 0)。
2.4.4 后端参数重命名(后端参数映射)
在某些特殊的情况下,前端传递的参数 key 和我们后端接收的 key 可以不相同。
比如,前端传递了一个 time 给后端,而后端使用 createTime 字段来接收,这样就会出现参数无法正常接收到的情况。
我们可以使用 @RequestParam 来重命名前后端的参数,使得参数可以匹配上。
@RequestParam是 Spring 框架中用于处理 HTTP 请求参数的注解。@RequestParam允许将 请求参数绑定到 controller 的方法参数上,无论是查询参数、表单参数还是多个参数都可以。
下面给出一个例子。
java
@RequestMapping("/m4")
public Object method4 (@RequestParam("time") String createTime) {
return "接收到参数createTime: " + createTime;
}
启动程序之后,通过浏览器访问 http://127.0.0.1:8080/param/m4?time=2026-08-23:

Spring 可以正确地将浏览器传递的参数 time 绑定到了后端参数 createTime 上。
若我们访问时的参数不是 time 而是 createTime 呢?
即通过浏览器访问 http://127.0.0.1:8080/param/m4?createTime=2026-08-23:

查看错误日志:

可以看到,导致无法正确匹配到参数。
总结:
- 使用
@RequestParam进行参数重命名时,请求参数只能和@RequestParam声明的 名称一致 才能正确绑定参数并进行赋值 - 使用
@RequestParam进行参数重命名时,参数是必传参数
非必传参数设置
如果我们的的实际业务中,前端的参数是一个非必传参数,该如何解决上面出现的问题呢?
我们查看 @RequestParam 的具体实现:
java
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
boolean required() default true;
String defaultValue() default "\n\t\t\n\t\t\n\ue000\ue001\ue002\n\t\t\t\t\n";
}
可以发现有一个属性 required 有一个默认值 true,这表示被该注解修饰的参数默认情况下是必传的。
我们在使用该注解的时候将 required 属性改成 false 即可,表示被修饰的参数是非必传参数。
java
@RequestMapping("/m4")
public Object method4 (@RequestParam(value = "time", required = false) String createTime) {
return "接收到参数createTime: " + createTime;
}
- 在使用
@RequestParam时如果没有指定属性(key),默认就是value(即 @RequestParam("time") 中,"time" 默认赋值给属性value),如果需要赋值多个属性就必须显式指定
2.4.5 传递数组
Spring MVC 可以自动绑定数组参数并进行赋值。
下面给出一个例子。
java
@RequestMapping("/m5")
public Object method5 (String[] arrayParam) {
return Arrays.toString(arrayParam);
}
启动程序,通过浏览器输入:http://127.0.0.1:8080/param/m5?arrayParam=zhangsan\&arrayParam=lisi\&arrayParam=wangwu:
得到响应如下:

通过 Postman 访问:

可以看到,都可以实现参数的绑定并赋值。
2.4.6 传递集合
和数组参数类似,一个请求 URL 的查询字符串中可以设置多个参数名,并且需要使用 @RequestParam 绑定参数关系。
- 默认情况下是将请求 URL 中查询字符串参数名相同的多个值封装到数组中,如果要封装到集合,则要使用
@RequestParam来绑定参数关系。
例如:
java
@RequestMapping("/m6")
public Object method6 (@RequestParam List<String> listParam) {
return "size: " + listParam.size() + ", listParam: " + listParam;
}
启动程序并访问,访问的方式与数组一致,可以通过浏览器输入:
- http://127.0.0.1:8080/param/m6`?listParam=zhangsan&listParam=lisi&listParam=wangwu`
- http://127.0.0.1:8080/param/m6`?listParam=zhangsan%2Clisi%2Cwangwu`
- http://127.0.0.1:8080/param/m6`?listParam=zhangsan,lisi,wangwu`

2.4.7 传递 JSON 数据
我们先来介绍一下 JSON:
- JSON 是 JavaScript Object Notation(JavaScript 对象表示法)的缩写,是一种轻量级的数据交互格式。
- JSON 基于 ECMAScript(欧洲计算机协会指定的 js 规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
JSON 本质是字符串,主要负责在不同的语言中传递和交换数据。JSON 也可以是客户端和服务端进行交互的一种数据格式
注意:
- JSON 和 JavaScript 其实并没有关系,只是语法相似。
JSON 的语法介绍
下面给出一个 JSON 格式的数据,并短暂介绍一下 JSON 的语法:
json
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
"powers": [
"Radiation resistance",
"Turning tiny",
"Radiation\nblast"
]
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
"powers": [
"Million tonne punch",
"Damage resistance",
"Superhuman\nreflexes"
]
},
{
"name": "Eternal Flame",
"age": 1000000,
"secretIdentity": "Unknown",
"powers": [
"Immortality",
"Heat Immunity",
"Inferno",
"Teleportation",
"Interdimensional travel"
]
}
]
}
也可以将其压缩:
- {"squadName":"Super hero squad","homeTown":"Metro City","formed":2016,"secretBase":"Super tower","active":true,"members":{"name":"Molecule Man","age":29,"secretIdentity":"Dan Jukes","powers":\["Radiation resistance","Turning tiny","Radiation\\nblast"},{"name":"Madame Uppercut","age":39,"secretIdentity":"Jane Wilson","powers":"Million tonne punch","Damage resistance","Superhuman\\nreflexes"},{"name":"Eternal Flame","age":1000000,"secretIdentity":"Unknown","powers":"Immortality","Heat Immunity","Inferno","Teleportation","Interdimensional travel"}]}
- JSON 数据是以
键值对(Key/Value)形式存储的,键(Key)和值(Value)之间以冒号':'来分隔。JSON 数据的各个键值对之间以逗号','来分隔 - 值(Value)可以是对象,也可以是数组,数组中可以包含多个对象
- 对象用
{}来表示;数组用[]来表示 对象:是一个用大括号{}保存的、无序的 键值对 集合。一个对象以左括号{开始,右括号}结束。每个键(Key)后跟着一个冒号':',键值对之间以逗号','分隔。数组:是一个用中括号[]保存的、值(Value) 的有序集合。一个数组以左中括号[开始,右中括号]结束,每个值(Value)之间用 逗号','分隔。
JSON 字符串和 Java 对象相互转换
JSON 本质上是一个字符串,通过文本来存储和描述数据。
Spring MVC 框架也集成了 JSON 的转换工具,我们可以直接使用,来完成 JSON 字符串和 Java 对象的相互转换。
- 本质上是 jackson-databind 提供的功能,Spring MVC 框架中已经把该工具包引入,直接使用即可。
- 若脱离 Spring MVC 使用,则需要手动引入依赖:
xml<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.5</version> </dependency>
- JSON 转换工具包有很多,jackson-databind 只是其中的一个。
我们编写 common-util-JSONUtils 的代码:
java
public class JSONUtils {
// jackson-databind提供的转换类
private static ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws JsonProcessingException {
Person object = new Person();
object.setId(5);
object.setName("zhangsan");
object.setPassword("123456");
// 对象转为JSON字符串
String jsonStr = objectMapper.writeValueAsString(object);
System.out.println("JSON字符串为:" + jsonStr);
// JSON字符串转为对象
Person person = objectMapper.readValue(jsonStr, Person.class);
System.out.println("转换的对象id:" + person.getId() +
",name:" + person.getName() + ",password:" + person.getPassword());
}
}
使用
ObjectMapper对象提供的两个方法,就可以完成对象和 JSON 字符串的相互转换:
writeValueAsString:将 Java 对象转为 JSON 字符串readValue:将 JSON 字符串转为 Java 对象
JSON 优点
- 简单易用:语法简单,易于理解和编写,可以快速地进行数据交换
- 跨平台支持:JSON 可以被多种编程语言解析和生成,可以在不同的平台和语言之间进行数据交换和传输
- 轻量级:相较于 XML 格式,JSON 数据格式更加轻量级,传输数据时占用带宽较小,可以提高数据传输速度
- 易于扩展:JSON 的数据结构灵活,支持嵌套对象和数组等复杂的数据结构,便于扩展和使用
- 安全性:JSON 数据格式时一种纯文本格式,不包含可执行代码,不会执行恶意代码,因此具有较高的安全性
基于以上特点,JSON 在 Web 应用程序种被广泛使用,如前后端数据交互、API 接口数据传输等。
传递 JSON 对象
接收 JSON 对象时,需要在方法的参数处使用 @RequestBody
@RequestBody作用是请求绑定正文的数据,请求参数必须写在请求正文中。
后端实现:
java
@RequestMapping("/m7")
public Object method7 (@RequestBody Person person) {
return person.toString();
}
启动程序之后,通过 Postman 来发送 JSON 数据

如果我们将 @RequestBody 去掉,再次启动程序并发送请求:

2.4.8 获取 URL 中参数 @PathVariable
@PathVariable 注解主要作用在请求 URL 路径上的数据绑定,表示默认传递的参数写在 URL 上,Spring MVC 能够从上面获取到。
HTTP 请求的参数可以放在:
- URL 的资源路径中,如 http://127.0.0.1:8080/param/m8/666/Jackson
- URL 的查询字符串中,如 http://127.0.0.1:8080/param/m8?id=666\&userName=Jackson
- 请求报头(header) 中
- 请求正文(body) 中
后端实现代码:
java
@RequestMapping("/m8/{id}/{name}")
public String method8 (@PathVariable Integer id, @PathVariable("name") String userName) {
return "解析参数:id 为" + id + ", name 为" + userName;
}
启动程序之后通过浏览器发送请求:http://127.0.0.1:8080/param/m8/666/Jackson

或者使用 Postman 发送请求:

- 如果方法参数名称和需要绑定的 URL 中的变量名称一致时,可以不用给
@PathVariable的属性赋值,如上例的 id- 如果方法参数名称和需要绑定的 URL 中的变量名称不一致时,就需要给
@PathVariable的属性赋值,如上例的 userName
2.4.9 上传文件 @RequestPart
@RequestPart 是 Spring 框架中用于处理 multipart/form-data 请求的注解,常用于接收文件和复杂对象(如 JSON 或 XML)。它允许开发者在同一个接口中同时处理文件和其他参数。
接下来我们实现后端代码:
java
@RequestMapping("/m9")
public String getfile (@RequestPart("file")MultipartFile file) throws IOException {
// 获取文件名称
String fileName = file.getOriginalFilename();
// 文件上传到指定路径
file.transferTo(new File("C:/temp/" + file.getOriginalFilename()));
return "接收到的文件名称为:" + fileName;
}
然后在自己电脑的 C 盘创建一个名为 temp 的空文件夹(否则会抛异常),启动程序之后,通过 Postman 发送请求:

查看电脑中的文件:

2.4.10 获取 Cookie/Session
回顾 Cookie
HTTP 协议自身是属于 "无状态" 协议。
- "无状态" 指的是:默认情况下 HTTP 协议的客户端和服务器之间的这次通信和下次通信之间没有直接的联系。每个请求都是独立的,服务器不会保留任何之前请求的状态信息。
但是,实际开发中,我们很多时候是需要知道请求之间的关联关系的,例如登录一个网站,关闭网站之后再次访问这个网站时登陆状态还能保持(服务器能够知道该请求是否已经登录过)。
文章到这里就告一段落啦,若有错误请尽管指出~
完

