前后端交互学习笔记
一、这一章在讲什么
这一章主要讲 Spring Boot 中前后端如何通过 HTTP 进行交互。前端请求某个地址,比如 /list,后端通过 @RequestMapping 找到对应的 Controller 方法并执行。Controller 方法可以读取资源文件、解析数据、封装成 Java 对象集合。最后通过 @ResponseBody 或 @RestController 把返回值写入 HTTP 响应体,并由 Spring 自动转换成 JSON 返回给前端。前端拿到 JSON 后,再把数据显示到页面上。
二、核心概念
1. @RequestMapping
- 它是什么:Spring MVC 中用来绑定请求路径和 Controller 方法的注解。
- 有什么作用:让前端访问某个地址时,后端知道应该执行哪个 Java 方法。
- 它的原理:Spring 启动时会扫描 Controller 中的映射关系,比如:
java
@RequestMapping("/list")
public List<User> list() {
return userList;
}
当前端请求 /list 时,Spring 就会找到并执行 list() 方法。
- 初学者容易混淆的点 :
@RequestMapping("/list")不是调用方法,而是建立"请求地址"和"方法"的对应关系。
2. @ResponseBody
- 它是什么:一个告诉 Spring"方法返回值直接作为响应内容返回"的注解。
- 有什么作用:避免 Spring 把返回值当成页面名,而是直接把数据返回给前端。
- 它的原理:方法返回对象或集合时,Spring 会借助 JSON 转换器,把 Java 对象转换成 JSON,再写入 HTTP 响应体。
- 初学者容易混淆的点 :
@ResponseBody的核心不是"转 JSON",而是"写入响应体"。对象能变 JSON,是 Spring 消息转换器继续完成的。
3. @RestController
- 它是什么:专门用于写接口的 Controller 注解。
- 有什么作用:让类中所有方法默认都把返回值作为响应体返回,适合前后端分离开发。
- 它的原理:
text
@RestController = @Controller + @ResponseBody
所以使用 @RestController 后,方法上通常不用再单独写 @ResponseBody。
- 初学者容易混淆的点 :
@Controller更偏向返回页面,@RestController更偏向返回数据。
4. resources/static
- 它是什么:Spring Boot 中默认存放静态资源的目录。
- 有什么作用:用来放浏览器可以直接访问的资源,比如 HTML、CSS、JS、图片等。
- 它的原理 :Spring Boot 默认会把
resources/static下的文件作为静态资源暴露出来。 - 初学者容易混淆的点 :
resources/static里的资源主要给前端直接访问;而user.txt这种文件如果是后端通过getResourceAsStream()读取,更像是后端内部使用的数据资源。
5. JSON 数据返回
- 它是什么:后端把 Java 对象或集合转换成前端容易识别的数据格式。
- 有什么作用:前端一般不能直接使用 Java 对象,所以后端需要返回 JSON。
- 它的原理 :Controller 返回
List<User>,Spring 会把它转换成类似这样的 JSON 数组:
json
[
{
"id": 1,
"username": "admin",
"age": 18
}
]
- 初学者容易混淆的点 :Java 里的
List<User>是后端对象集合;JSON 是通过 HTTP 返回给前端的数据格式。
三、重难点
1. 前端请求 /list,为什么会执行 list() 方法
结论: 因为 @RequestMapping("/list") 把请求地址和 list() 方法绑定起来了。
原因: Spring MVC 会维护一张"请求路径 -> 方法"的映射表。当前端访问 /list 时,Spring 就查表找到对应方法。
比喻: @RequestMapping 像门牌号,前端按门牌号找房间,Spring 负责带它进入正确的方法。
2. @Controller 和 @RestController 的区别
结论: @Controller 常用于返回页面,@RestController 常用于返回数据。
原因: @RestController 自带 @ResponseBody,所以方法返回值会直接写入响应体。
小例子:
java
@Controller
public class DemoController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
这里 "hello" 可能被当成页面名。
java
@RestController
public class DemoController {
@RequestMapping("/hello")
public String hello() {
return "hello";
}
}
这里 "hello" 会直接返回给前端。
3. List<User> 为什么能返回 JSON
结论: 因为 @ResponseBody / @RestController 让返回值进入响应体,Spring 再把对象集合转换成 JSON。
原因: HTTP 响应不能直接传 Java 对象,所以 Spring 会使用 JSON 转换器进行序列化。
比喻: Java 对象像后厨做好的菜,JSON 像打包盒。前端拿不到"后厨对象",只能拿到打包后的数据。
4. resources/static 和 user.txt 的区别
结论: static 通常放前端直接访问的静态资源;user.txt 在这里是后端读取后加工的数据文件。
原因: static 目录由 Spring Boot 默认暴露给浏览器访问;getResourceAsStream("user.txt") 是后端代码主动读取类路径资源。
比喻: static 像摆在门口的宣传单,谁都可以直接拿;user.txt 像后厨原材料,要加工后才端给客人。
5. map() 的作用
结论: 这里的 map() 是把一行字符串转换成一个 User 对象。
原因: user.txt 读出来后是 List<String>,前端需要的是结构化数据,所以要封装成 List<User>。
小例子:
text
"1,admin,123456,张三,18,2024-01-01 10:20:30"
↓ map()
User 对象
最后整体完成:
text
List<String> -> List<User>
四、代码理解
最小代表性代码
java
@RestController
public class UserController {
@RequestMapping("/list") // 关键行 1:把 /list 请求映射到 list() 方法
public List<User> list() throws Exception {
// 关键行 2:读取 resources 下的 user.txt 文件
InputStream in = this.getClass()
.getClassLoader()
.getResourceAsStream("user.txt");
// 关键行 3:按 UTF-8 读取每一行文本
ArrayList<String> lines = IoUtil.readLines(
in,
StandardCharsets.UTF_8,
new ArrayList<>()
);
// 关键行 4:把每一行字符串转换成 User 对象
List<User> userList = lines.stream().map(line -> {
String[] parts = line.split(",");
Integer id = Integer.parseInt(parts[0]);
String username = parts[1];
String password = parts[2];
String name = parts[3];
Integer age = Integer.parseInt(parts[4]);
LocalDateTime updateTime = LocalDateTime.parse(
parts[5],
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
);
return new User(id, username, password, name, age, updateTime);
}).collect(Collectors.toList());
// 关键行 5:返回 List<User>,Spring 会转换成 JSON
return userList;
}
}
每一步在做什么
- 前端请求
/list。 @RequestMapping("/list")找到list()方法。- 后端读取
user.txt文件。 - 把文本按行读成
List<String>。 - 每一行用
split(",")拆成多个字段。 - 把字符串字段转换成对应类型,比如
Integer、LocalDateTime。 - 每一行封装成一个
User对象。 - 所有
User对象收集成List<User>。 - Controller 返回
List<User>。 - Spring 自动转成 JSON 返回给前端。
语法规则总结
java
@RequestMapping("/list")
表示把 /list 请求交给当前方法处理。
java
line.split(",")
表示按逗号拆分字符串。
java
Integer.parseInt(parts[0])
表示把字符串转成整数。
java
LocalDateTime.parse(str, formatter)
表示按指定格式把字符串转成时间对象。
java
stream().map(...).collect(Collectors.toList())
表示把集合中的每个元素转换后,再收集成新的集合。
五、易错点
-
把
@Controller和@RestController混为一谈
@Controller返回字符串可能是页面名,@RestController返回字符串就是响应内容。 -
以为
@ResponseBody本身就是 JSON 转换器它的核心作用是写入响应体,对象转 JSON 是 Spring 消息转换器完成的。
-
把
resources/static和普通资源文件混淆
static是给浏览器直接访问的静态资源;user.txt在这里是后端读取并加工的数据。 -
日期格式大小写写错
yyyy-MM-dd HH:mm:ss中,MM是月份,mm是分钟,不能乱写。 -
认为前端能直接拿到 Java 对象
前端收到的是 JSON,不是后端内存里的
User对象。
六、记忆口诀 / 通俗比喻
text
前端发请求,Mapping 找方法;
Controller 做处理,ResponseBody 回数据;
对象变 JSON,前端再渲染。
text
@Controller 找页面,
@RestController 给数据。
text
static 是前台展示区,
user.txt 是后厨原材料。
text
map 不是地图,是转换:
一行文本进来,一个对象出去。
七、应用
在实际开发中,前后端经常这样配合:前端页面需要用户列表,于是发送请求 /list;后端 Controller 查询数据库或读取数据文件,把数据封装成 User 对象集合;然后通过 @RestController 返回 JSON;前端拿到 JSON 后,用表格、列表等形式展示出来。
比如后台管理系统中的"用户列表""商品列表""订单列表",本质上都是类似流程:
text
前端请求接口 -> 后端处理数据 -> 返回 JSON -> 前端渲染页面
这章的代码虽然是从 user.txt 读取数据,但真实项目里通常会换成从数据库查询数据,整体交互思路不变。
八、最终总结
这一章的核心是理解前后端交互:前端通过 HTTP 请求地址,后端通过 @RequestMapping 找到方法并执行。@ResponseBody 或 @RestController 决定返回值会作为响应数据返回,而不是当成页面名。后端可以读取资源文件或数据库,把数据封装成 Java 对象集合,再由 Spring 转成 JSON。前端最终拿到 JSON 数据并渲染页面。