首页 前端知识 【SpringMVC】深入解析SpringBoot与jQuery全栈开发留言板:从@RequestBody到AJAX数据交互的完整实现(含Postman测试 JSON解析 页面初始化加载等核心知识点)

【SpringMVC】深入解析SpringBoot与jQuery全栈开发留言板:从@RequestBody到AJAX数据交互的完整实现(含Postman测试 JSON解析 页面初始化加载等核心知识点)

2025-03-23 11:03:18 前端知识 前端哥 528 35 我要收藏

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


留言板


需求界面如下图所示 :

  1. 输入留言信息,点击提交。后端把数据存储起来。
  2. 页面展示输入的留言墙的信息

在这里插入图片描述


1. 准备工作


把前端页面放在项目中(课件中提供)

码云地址:JavaEE进阶课程资料包

在这里插入图片描述


2. 约定前后端交互接口


2.1 需求分析


后端需要提供两个服务 :

  1. 提交留言:用户输入留言信息之后,后端需要把留言信息保存起来
  2. 展示留言:页面展示时,需要从后端获取到所有的留言信息

2.2 接口定义


(1) 获取全部留言

全部留言信息,我们用List来表示,可以用 JSON 来描述这个 List 数据。


请求:

在这里插入图片描述


响应:JSON 格式

在这里插入图片描述

  • 浏览器服务器发送一个 GET /message/getList 这样的请求,就能返回当前一共有哪些留言记录。

  • 结果以json的格式返回过来。


(2) 发表新留言

请求:body 也为 JSON 格式。

在这里插入图片描述


响应:JSON 格式

在这里插入图片描述

{
ok : 0
}
复制

我们期望浏览器服务器发送一个 POST /message/publish 这样的请求,就能把当前的留言提交给服务器。


3. 服务器代码


(1) 获取全部留言接口代码写法


定义留言对象 MessageInfo

在这里插入图片描述


创建 MessageController 类 ;

当客户端发送 JSON 格式的请求体(Content-Type为application/json)时,必须使用@RequestBody注解。

在这里插入图片描述


对拿到的对象属性进行校验

在这里插入图片描述


注意

虽然上面响应的 json 数据中 , ok 是没有双引号的,但是正规的 json 写法,属性名需要带双引号;

我们需要对对象中的字符串属性的双引号转义,如 \" 属性名 \"

在这里插入图片描述

JSON数据不能有空格,煮啵写到这里的时候还不知道,后面通过 deepseek 纠错才知道)


使用 produces

produces 声明了该方法的响应格式为 JSON,它不影响Spring如何解析请求体,只设置响应头的Content-Type

注意,如果这个方法的返回值是一个对象,就不需要使用 produces声明返回格式

在这里插入图片描述


因为我们还没有学到连接数据库的操作,所以我们先把数据存储在内存中;

使用List 来存储留言板信息

我们定义一个 List ,如果校验的请求对象数据校验成功,把请求的数据存储在 List 中:

在这里插入图片描述


我们再定义一个方法,用于拿到留言信息:

在这里插入图片描述


(2) 测试接口


重新启动程序,我们先调用 getList() 方法;

刚开始存储留言信息的 List 什么都没有,所以返回一个空的集合:

在这里插入图片描述


接下来,我们测试 publish 接口,下面是构造 JSON 数据为请求体的方法:

在这里插入图片描述


我们再来测试 getList 的接收功能:

在这里插入图片描述


(3) 通过调试讲解不使用 @RequestBody 的后果


如果在 publish() 接口中去掉 @RequestBody 会怎么样:

在这里插入图片描述


重新运行程序,发送请求:

在这里插入图片描述


@RequestBody 表示的是请求参数为 JSON,通过 Postman 响应可以看出,后端校验,发现数据错误,返回 ok:0:

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在调试过程中,程序的运行会卡在断点处,我们打开 Postman 查看发送请求,返回响应的过程:

在这里插入图片描述


在这里插入图片描述


produces 声明了该方法的响应格式为 JSON,与请求的数据解析方式无关。它不影响Spring如何解析请求体,只设置响应头的Content-Type

@RequestBody的必要性

  • 当客户端发送 JSON 格式的请求体(Content-Type为application/json)时,必须使用@RequestBody注解。
  • @RequestBody告诉 Spring 使用 JSON解析器(如Jackson)将请求体反序列化为Java对象。
  • 如果没有该注解,Spring默认从请求参数URL参数表单数据)中绑定数据,而非请求体

4. 调整前端点击事件函数代码


(1) 使用 @ajax 进行前后端数据交互


修改 messagewall.html

在这里插入图片描述


我们使用 ajax 来让前后端对象属性交互:

JavaScript 中 varletconst 用于声明参数类型;

在这里插入图片描述


下图第五点的对应关系应该是 submit() 中的前三行参数,这三个参数通过 id 选择器去上面的样式中拿值:

在这里插入图片描述

data 属性用于传递数据,后端是使用 JSON接收数据(@RequestBody注解会以 JSON格式解析数据),前端也需要使用 JSON来发送数据;


(2) 将前端发送的数据由对象转成 JSON 字符串


在前端如何将发送的数据构造成JSON呢?

Data 中,我们先赋值为一个对象({}表示一个对象),对象中的属性为后端的请求参数,值为 submit() 前面定义的几个参数;

在这里插入图片描述


此时 Data 默认传的是一个对象,不是一个JSON 数据,我们需要把这个对象转成 JSON

在这里插入图片描述


方法一

在这里插入图片描述


在这里插入图片描述


方法二(推荐)

我们将对象单独抽离,将新定义的对象参数传入 stringify(),这样更美观且不容易写错:

在这里插入图片描述


(3) 前端声明传递的数据类型为 JSON


在这里插入图片描述


(4) 处理后端返回的 JSON 数据


后端返回的是 JSON 数据:

在这里插入图片描述

如果后端发送的值为 JSON,那么前端是可以直接把 JSON 数据当成对象使用的


使用 success 关键字,只要后端返回数据,就会执行 success 对应的 function

在这里插入图片描述


在这里插入图片描述


(5) 测试接口


重新运行程序,在浏览器中打开页面:http://127.0.0.1:8080/messagewall.html

在这里插入图片描述


提交数据

在这里插入图片描述


查看抓包结果:

在这里插入图片描述


数据内容格式转换的过程(前后端格式设置相同的过程):

在这里插入图片描述


后端没有指定响应返回数据的类型为 JSON

上面的 if …else … 部分修改:

在这里插入图片描述


假设我们后端没有约定返回格式为 JSON(消去 produces)的内容):

在这里插入图片描述


此时返回前端的数据是字符串,我们在前端打日志;

重新运行程序,刷新浏览器,在浏览器控制台观察输出结果:

在这里插入图片描述


查看抓包结果:

在这里插入图片描述


根本原因

  • 在前端,字符串无法像 JSON 一样解析成对象
  • 此时result.ok 就是字符串.属性,而不是对象.属性,就会在页面进行提交数据时,就会出现失败提示的弹窗;

直接原因

  • 这是后端返回数据,没有指定响应类型的结果;

在这里插入图片描述


如果要保持此时的后端不变,我们就需要在前端调用刚刚学到的 parse() 方法:

在这里插入图片描述


所以前后端是需要相互配合的,所以接口文档中要有清晰的边界划分,明确指定好数据的类型;


5. 在页面加载的时候获取数据


发布留言后,页面刷新,我们会发现数据丢失:

在学到这里的时候,煮啵运行代码,发现还是依旧出现失败弹窗,这时候我们就需要万能的 deepseek

在这里插入图片描述

在这里插入图片描述


所以我们刷新的时候,需要把之前的信息存储在留言列表中:

在这里插入图片描述


我们只需要在前端调用 getList 接口,在加载页面的时候,获取留言列表信息;

也就是一进入页面,就发送 ajax请求,来直接调用 getList接口,获取留言列表并且显示;

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


重新启动程序,刷新浏览器页面:

在这里插入图片描述


我们发送了两条数据,刷新页面 (不是重新启动程序)

在这里插入图片描述


此时我们每次提交的数据都会发送给服务器。每次打开页面的时候,页面都会从服务器加载数据。因此,即使关闭页面,数据也不会丢失。

  • 但是数据此时是存储在服务器的内存中(private List<Message> messages = new ArrayList<Message>();),一旦服务器重启,数据仍然会丢失。

  • 要想数据不丢失,需要把数据存储在数据库中,后面再讲。


6. 完整代码


前端代码:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>留言板</title>
<style>
.container {
width: 350px;
height: 300px;
margin: 0 auto;
/* border: 1px black solid; */
text-align: center;
}
.grey {
color: grey;
}
.container .row {
width: 350px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
}
.container .row input {
width: 260px;
height: 30px;
}
#submit {
width: 350px;
height: 40px;
background-color: orange;
color: white;
border: none;
margin: 10px;
border-radius: 5px;
font-size: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>留言板</h1>
<p class="grey">输入后点击提交, 会将信息显示下方空白处</p>
<div class="row">
<span>谁:</span> <input type="text" name="" id="from">
</div>
<div class="row">
<span>对谁:</span> <input type="text" name="" id="to">
</div>
<div class="row">
<span>说什么:</span> <input type="text" name="" id="say">
</div>
<input type="button" value="提交" id="submit" onclick="submit()">
<!-- <div>A 对 B 说: hello</div> -->
</div>
<script src="js/jquery-3.7.1.min.js"></script>
<script>
function load(){
$.ajax({
type: "get",
url: "/message/getList",
success: function (messages){
// 成功拿到响应数据,就遍历列表并且打印
if(messages!=null && messages.length > 0){
var finalHTML = "";
// 注意 js 的 for 循环写法
for(var message of messages){
// 每次遍历到一个元素,都把单个信息拼接在 item 中
var item = "<div>"+message.from +"对" + message.to + "说:" + message.message+"</div>";
// 在把单个信息,拼接到最终显示的 finalHTML 中
finalHTML += item;
}
// 把留言列表显示在页面下端
$(".container").append(finalHTML);
}
}
});
}
// 调用封装方法
load();
function submit(){
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from== '' || to == '' || say == '') {
return;
}
var data = {
from: from,
to: to,
message: say
}
$.ajax({
type: "post",
url: "/message/publish",
contentType : "application/json",
data: JSON.stringify(data),
success : function (result){
if(result.ok == 1){
//2. 构造节点
var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else {
// 失败
alert("留言发布失败");
}
}
});
}
</script>
</body>
</html>
复制

后端代码:


MessageInfo:

package com.example.springmvc_demo;
import lombok.Data;
@Data
public class MessageInfo {
private String from; // 谁
private String to; // 对谁
private String message; // 说什么
}
复制

MessageController:

package com.example.springmvc_demo;
import com.example.springmvc_demo.MessageInfo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RequestMapping("/message")
@RestController
// 操作数据, 不操作视图
public class MessageController {
private List<MessageInfo> messageInfoList = new ArrayList<>();
@RequestMapping(value = "/publish" , produces = "application/json")
public String publish(@RequestBody MessageInfo messageInfo){
// 对拿到的对象属性进行校验
if(!StringUtils.hasLength(messageInfo.getFrom())
|| !StringUtils.hasLength((messageInfo.getTo()))
|| !StringUtils.hasLength(messageInfo.getMessage()))
{
// 失败,返回0
return "{\"ok\":0}";
}
// 校验成功, 把传递的请求存储到 List 中
messageInfoList.add(messageInfo);
return "{\"ok\":1}";
}
@RequestMapping("/getList")
public List<MessageInfo> getList(){
return messageInfoList;
}
}
复制

在这里插入图片描述

在这里插入图片描述

转载请注明出处或者链接地址:https://www.qianduange.cn//article/24267.html
标签
评论
发布的文章

【Linux笔记】基础IO(上)

2025-03-27 13:03:40

大家推荐的文章
会员中心 联系我 留言建议 回顶部
娴忚鍣ㄥ崌绾ф彁绀猴細鎮ㄧ殑娴忚鍣ㄧ増鏈緝浣庯紝寤鸿鎮ㄧ珛鍗冲崌绾т负鐭ヤ簡鏋侀€熸祻瑙堝櫒锛屾瀬閫熴€佸畨鍏ㄣ€佺畝绾︼紝涓婄綉閫熷害鏇村揩锛�绔嬪嵆涓嬭浇
复制成功!