Spring Boot & Spring Data JPA – Complete Course(2) - NoTe0x004
写在前面
这一系列是我在学习他人的优质课程(博客文章、视频课程等)时所做的学习笔记,根据我自身的水平来进行学习,同时会进行思维的发散,补充原文中没有提到或者有错误的地方。同时也会进行经常性的更新和整理,让它和我的当下的状态更加契合。
本篇是这个SpringBoot视频教程的第二部分,主要讲的就是Spring REST API,视频的时长大概在1小时左右,应该会比上一期稍微短一点?
OverView
REST是Representational State Transfer(表示层状态转移)的缩写,它是一种软件架构,定义了用于创建Web服务的约束集合的样式,这些网络服务通常被称为RESTful API,它是一种设计思路,由Roy Fielding于2000年在他的博士论文中定义。其核心思想是将网络资源视为对象,它们可以通过标准的HTTP方法来访问,例如GET、POST、PUT、DELETE等。REST同时规定了下面的原则:
- 客户端-服务器架构,这一原则确立了二者之间相互独立,他们可以相互互动,但是双方都可以独立开发和更新。
- 无状态。每一个HTTP请求都应该包括二者通信所需的所有信息,服务器不应该在请求期间存储任何数据(现在存也是存在Redis等外挂数据库,并不存在Tomcat的内存中)
- 可缓存。服务器必须明文指出返回的数据是否可缓存。
- 分层系统。系统架构允许多层级的用户。客户端不需要知道他最终连接的是哪一层服务器。
- 按需编码(可选)。服务器在返回数据的同时,可以发送一些可执行代码,让客户端在本地临时执行,以此来动态扩展客户端的功能。
- 统一界面。他有四个指导原则:资源识别、通过表征操作资源、自我描述信的信息、作为应用状态的超媒体(HATEOS)——据说这个原则能够实现的也不是很多,因为太理想化了。
Resource Design
在设计RESTful API时,我们最好遵循以下原则:
- API端点的资源应该始终是复数名词,如果要用ID精确查找,那么就在URL里传入。例如
GET /accounts、GET /accounts/1、DELETE /accounts/2都是合法的。 - 如果是嵌套资源,应该通过以下方式访问:
GET /accounts/1/payments/56。 - 使用HTTP方法来指定对资源的操作,例如GET、POST等进行增删改查。可以总结成下面的表格
| 资源路径 | GET | POST | PUT | DELETE |
|---|---|---|---|---|
/accounts |
获取所有账户 | 创建新账户 | 批量更新所有账户 | 删除所有账户 |
/accounts/1 |
获取 ID为1的账户 | 错误 | 更新ID为1的账户 | 删除 ID为1的账户 |
/accounts/1/payments |
获取ID为1的账户的所有支付记录 | 为ID为1的账户创建新支付记录 | 批量更新ID为1的账户的所有支付记录 | 删除ID为1的账户的所有支付记录 |
HTTP Methods
这一部分他准备介绍主要的HTTP方法,让我们能够设计RESTful API。
- GET,可以从服务器中获取资源,它是只读的,这意味着它不会影响资源的状态。
- POST,用于向服务器发送数据以创建新资源,数据包含在请求体中
- PUT,用于更新现有资源,若资源不存在则创建,数据包含在请求体中。
- DELETE,用于删除资源。
- PATCH,用于对资源进行部分修改,和PUT不同,后者更适合全面更新,而前者适合部分更新。
- OPTIONS,这个方法用于检查Web服务器的功能,服务器会返回一个响应头,你可以用来检查是否支持跨域等。
- HEAD,这个方法和GET类似,但是只返回响应头。适合在下载之前检查资源是否存在。
Response Status Codes
在这之后视频又讲了HTTP状态码。它是三位数代码,作为HTTP响应的一部分返回,表示请求的结果。
- 1XX,信息性响应
- 2XX,成功,例如
200 OK成功的标准响应、201 CREATED请求成功了并创建了新的资源、204 NO CONTENT服务器成功处理了请求且没有额外内容,一般是对删除请求的响应,或者不愿意返回任何信息时。 - 3XX,重定向,例如
304 NOT MODIFIED是一种用于缓存目的的特殊响应类型,当客户端向服务器发送请求时,如果资源自从给定日期以来未被修改就会返回这个状态码,这样你就可以节省带宽。 - 4XX,客户端错误,例如
404 BAD REQUEST服务器因语法错误而无法理解请求(格式错误或参数无效)401 UNAUTHORIZED用户没有足够的特权,或者用户未认证、403 FORBIDDEN客户端没有请求所需的权限(服务器不愿意说具体理由的时候也可以用这个) - 5XX,服务端错误,例如
500 INTERNAL SERVER ERROR当出现问题时给出的通用错误信息,意味着服务器本身出现了问题但是不会告诉你具体错误、503 SERVICE UNAVALIABLE表示服务当前不可用,只是暂时的,通常会包括一个时间告诉你需要等多久才能发起新的请求。
Example
下面的代码是一个PaymentRestController类的代码,它展示了SpringBoot中是如何实现RESTful API的。
1 |
|
这个类中有一个方法叫做initiatePayment,返回的是一个ResponseEntity的泛型类,也就是响应实体。方法上的@PostMapping注解表示要调用这个方法需要用POST方法访问/payments地址,然后请求的参数作为请求体传给了方法的实参。在业务代码结束后,如果我们要返回结果的地址的话,我们就需要创建一个URI,利用ReponseEntity.created()方法返回的是201状态码,然后返回一个响应体。
如果我们要指定Controller方法的响应状态,就可以用@ResponseStatus注解,这样当HTTP请求执行成功时,Spring就会让服务器返回对应注解中的状态。
In Action
那么介绍部分结束了之后,我们就可以开始写代码了。我们只需要保留SpringPracticeApplication.java这一个类即可,只保留初始的SpringBoot启动代码。
1 | // SpringPracticeApplication.java |
接下来,我们直接在SpringPracticeApplication.java所在目录中创建一个Controller类,命名为FirstController。同时添加@RestController注解(要确保你的POM文件中有)spring-boot-starter-web依赖。我们首先尝试写一个GET方法,只需要在方法前面写上GetMapping注释。
1 | // FirstController.java |
直接在浏览器中输入localhost:8080,就可以看到返回的结果了。在老版本的SpringBoot中,如果你不写的话它是访问不到的。为了保险期间还是应该给@GetMapping注解加上参数最好了。
1 | // FirstController.java |
现在如果你再直接输入localhost:8080的话,那就会显示Whitelabel Error Page。在正确的Hello页面里,我们通过浏览器调试工具,找到对应的网络请求,可以看到有很多的属性。

我们看看@ResponseStatus的源代码。对于源代码的讲解会用//注释来编写,同时源代码中的注释也已经全部翻译为中文了。
1 | // ResponseStatus.java |
而HttpStatus是一个枚举类,例如201就是HttpStatus.CREATED。那么假如我们还有一个方法映射到/hello-2,我希望他正常访问时返回的是202,那么只需要在@ResponseStatus注解中传入即可。
1 | // FirstController.java |
重新运行应用,观察变化,我们会发现响应的状态代码确实变成202了。

接下来我们尝试创建一个POST endpoint。写好对应的注释,然后编写方法传参,接收一个message作为参数,然后直接将其显示出来。
1 | // FirstController.java |
直接在浏览器中输入/post显然是不行的,因为通过地址栏访问的全都是GET方法,此时对于/post返回的状态码是405。这个时候作者开始教我们如何使用Postman了。由于我们之前有过使用APIFox的经历,因此这边直接给他卸载了,装上Postman了。装完之后,我们直接发送一个空的Post请求到/post,会发现输出的结果是Request accepted and message is null,这是因为我们根本没有传入message变量。我们需要在URL的Body里面添加上对应的message。

不对啊,怎么还是null?说明这个参数根本没传进来,我们需要告诉编译器,这个参数是在Request body位置的,因此我们需要给参数添加对应的注释@RequestBody,这意味着这个参数是在我们的请求体中。
1 | // FirstController.java |
现在我们再次尝试就发现正常了。当我们将HTTP请求发送给Spring时,它会将请求报文转换成指定的JAVA对象。当然请求体中改用JSON也是可以的。

我们会发现输出的结果是
Request accepted and message is {
“message”: “baobao”
}
它只是把这个JSON对象直接转成String了。如果我们需要接收很复杂的对象的话,我们应该首先创建一个类来承接这个对象。在main函数所在目录下新建一个类Order,同时定义基本的成员变量。
1 | // Order.java |
对应的Controller代码也需要进行更改来承接这个类。
1 | // FirstController.java |
同时对应的Postman请求也要做修改。

但是我们添加断点调试会发现,为什么所有的成员变量都是null呢?这是因为我们传入的是一个JSON字符串,Spring没有将它反序列化为一个对象,因此才没有传入任何属性。

实际上,Spring底层的Jackson库是通过反射来读取属性的,当反序列化时,Jackson会默认寻找public的setter方法或者public的构造器或者字段,而在序列化时,Jackson会默认去找pubilc的getter方法或者public字段。不过除此之外,你还可以通过@JsonProperty注解来让它打破这些规则,例如
1 | public class User { |
不过我们还是更推荐走这种默认的反序列化方式。跟着视频中修改这个类,添加getter和setter,顺便重写一下toString方法。
1 | // Order.java |
现在就正确了,可以看到输出的是
Request accepted and order is Order{customerName=’baobao’, productName=’apple’, quantity=10}
假如说前端传入的JSON键名想要和后端接收到的不同呢?就可以用到我们上文中提到的@JsonProperty注解了。在这个注解的源码中告诉了我们这个注解的功能和用法
1 | // JsonProperty.java |
添加了注解的类就像这样:
1 | // Order.java |
这时候如果你在JSON中用原先的键名,那么就和之前一样都是null了。
在Java14引入了“记录(Record)”特性,它是一种不可变的、透明的、用于存储数据的载体,核心目的是为了解决编写数据类时的大量模板代码,可以说算是一种语法糖了。但是它也有一些限制。
- 不能继承其他类,可以实现接口。
- 所有字段都是final,没有setter也无法修改。
- 只有一个默认的全参构造器,如果要校验的话在大括号中要写一个紧凑构造器(没有参数列表)
- 所有字段不能是transient。
新建java文件的时候,在idea中,我们可以直接选择新建一个记录,然后直接在括号里给出字段就行了。同时也给controller添加一个访问的方法。
1 | // OrderRecord.java |
也能得到正确的结果。
接下来我们看如何使用路径来传参,例如我想访问http://localhost:8080/hello/baobao如何让controller中的方法来处理这个请求,只需要在Mapping的链接里加上大括号然后写上变量名就行了,同时给参数加上一个@PathVariable注解。注意保持一致。
1 | // FirstController.java |
但是通常情况下,URL一半是不用驼峰命名的,最好还是叫/hello/{user-name},给注解直接传参就行了,即
1 | // FirstController.java |
都会正常输出my value = baobao。
接下来我们再看如何将参数作为请求参数传递,即?xxx=xxx&yyy=yyy这类的在请求链接里的参数。只需要在方法的形参中加入@RequestParam注解即可。注解的参数是你想要的变量名称,如果不给的话就和形参名保持一致。
1 | // FirstController.java |
现在就可以访问localhost:8080/hello?user-name=baobao&last-name=b了。原视频作者在这里运行出现了错误,这是因为他之前的getMapping还有一个指向hello的无参的方法,这就重了所以才会报错。同时作者这里讲了路径变量和请求参数的用法:一般来讲路径变量代表着某种资源的值,而请求参数用于传输上下文信息或者查询参数,和路径剥离。
接下来视频开始给我们讲原理了。下面就是Mapping的原理图。

- 发送请求,第一个接受请求的对象是Dispatchaer Servelet。
- dispatcher Servelet会转发请求到HandlerMapping类,映射Handler mapping对象。
- Handler Mapping 会尝试寻找映射的Controller,然后参考Mapping Registry。
- 如果找到的话会把方法返回给Handler Mapping。
- 他会将请求转发给所需的Controller。
- 执行业务代码。
- 业务代码的响应会回到Controller。
- Controller会把响应反馈给Dispatcher Servelet。
- Servelet会把结果返回给用户。
Mapping Registry要求路径或HTTP方法必须唯一,如果路径和方法均相同的话就会有冲突,它无法确定要用哪一个,抛出BeanCreationException告诉你Cannnot map ‘xxx’ method ‘yyy’。虽然说两个方法名称不同,但是他们的路径和方法都相同,但是Spring也会将其视作冲突并无法构建。
总结
这一部分主要讲述了如何编写和构建高效的RESTful API,可以说是SpringBoot的核心中的核心,毕竟这就是后端主要的功能。接下来的部分应该讲的是JPA等数据库操作,这个就要等到下次再说了。
参考文献
- 标题: Spring Boot & Spring Data JPA – Complete Course(2) - NoTe0x004
- 作者: Baobao0824
- 创建于 : 2026-05-20 14:22:32
- 更新于 : 2026-05-20 14:22:32
- 链接: https://blog.baobao0824.top/学习笔记NoTe/NT-0x004/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。