3.1 加法计算器
需求:输⼊两个整数,点击"点击相加"按钮,计算结果显示
3.1.1 准备工作
创建SpringBoot创建:引入SpringWeb依赖,把前端页面放在项目中

3.1.2 约定前后端交互接口
概念介绍
约定 "前后端交互接口" 是进行 Web 开发中的关键环节。接口又叫 API(Application Programming Interface),我们一般讲到接口或者 API,指的都是同一个东西。是指应用程序对外提供的服务的描述,用于交换信息和执行任务(与 JavaSE 阶段学习的 [类和接口] 中的接口是两回事)。简单来说,就是允许客户端给服务器发送哪些 HTTP 请求,并且每种请求预期获取什么样的 HTTP 响应。
现在 "前后端分离" 模式开发,前端和后端代码通常由不同的团队负责开发。双方团队在开发之前,会提前约定好交互的方式。客户端发起请求,服务器提供对应的服务。服务器提供的服务种类有很多,客户端按照双方约定指定选择哪一个服务。
接口,其实也就是我们前面网络模块讲的的 "应用层协议"。把约定的内容写在文档上,就是 "接口文档",接口文档也可以理解为是 应用程序的 "操作说明书"。
比如儿童电话玩具

按 1: 响应儿歌按 2: 响应钢琴乐曲按 3: 安抚睡眠按 4: 交通工具音效......等等
但是这些操作说明,如果没有一个文档来说明,用户就不太清楚哪个按键对应哪个,所以商品一般会带一个说明书这些按键,就是接口.这个 "说明书", 就是 应用程序的 "接口文档"
在项目开发前,根据需求先约定好前后端交互接口,双方按照接口文档进行开发.
接口文档通常由服务提供方来写,交由服务使用方确认,也就是客户端.接口文档一旦写好,尽量不要轻易改.如若需要改变,必须要通知另一方知晓.
需求分析
加法计算器功能,对两个整数进行相加,需要客户端提供参与计算的两个数,服务端返回这两个整数计算的结果
需求分析
加法计算器功能,对两个整数进行相加,需要客户端提供参与计算的两个数,服务端返回这两个整数计算的结果
基于以上分析,我们来定义接口
接口定义
1 请求路径: calc/sum23 请求方式: GET/POST45 接口描述:计算两个整数相加
请求参数:
| 参数名 | 类型 | 是否必须 | 备注 |
|---|---|---|---|
| num1 | Integer | 是 | 参与计算的第一个数 |
| num2 | Integer | 是 | 参与计算的第二个数 |
示例: num1=5&num2=3
响应数据:
1 Content-Type: text/html23 响应内容:计算机计算结果: 8
服务器给浏览器返回计算的结果
3.1.3 服务器代码
java
@RestController
@RequestMapping("/calc")
public class CalcController {
@RequestMapping("/sum")
public String sum(Integer num1,Integer num2){
Integer sum = num1+num2;
return "<h1>计算机计算结果: "+sum+"</h1>";
}
}
3.1.4 调整前端页面代码
添加访问 url 和请求方式
java
<form action="calc/sum" method="post">
<h1>计算器</h1>
数字1: <input name="num1" type="text"><br>
数字2: <input name="num2" type="text"><br>
<input type="submit" value=" 点击相加">
</form>
3.1.5 运行测试
启动服务,运行并测试


3.2 用户登录
需求:用户输入账号和密码,后端进行校验密码是否正确
- 如果不正确,前端进行用户告知
- 如果正确,跳转到首页。首页显示当前登录用户
- 后续再访问首页,可以获取到登录用户信息


3.2.1 约定前后端交互接口
需求分析
对于后端开发人员而言,不涉及前端页面的展示,只需要提供两个功能
- 登录页面:通过账号和密码,校验输入的账号密码是否正确,并告知前端
- 首页:告知前端当前登录用户,如果当前已有用户登录,返回登录的账号,如果没有,返回空
接口定义
1. 校验接口
1 请求路径: /user/login
2
3 请求方式: POST
4
5 接口描述: 校验账号密码是否正确
请求参数:
| 参数名 | 类型 | 是否必须 | 备注 |
|---|---|---|---|
| userName | String | 是 | 校验的账号 |
| password | String | 是 | 校验的密码 |
响应数据:
java
Content-Type: text/html
响应内容:
true //账号密码验证成功
false//账号密码验证失败
2. 查询登录用户接口
java
请求路径: /user/getLoginUser
请求方式: GET
接口描述: 查询当前登录的用户
2. 查询登录用户接口
java
请求路径: /user/getLoginUser
请求方式: GET
接口描述: 查询当前登录的用户
**请求参数:**无
响应数据:
java
1 Content-Type: text/html
2
3 响应内容:
4 zhangsan
返回当前登录的用户
3.2.2 实现服务器端代码
1. 校验接口
java
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user")
public class LoginController {
/**
* 校验用户账号和密码是否正确
* @param userName
* @param password
* @param session
* @return
*/
@RequestMapping("/login")
public boolean login(String userName, String password, HttpSession session)
{
//账号或密码为空
if(!StringUtils.hasLength(userName) ||
!StringUtils.hasLength(password)){
return false;
}
//校验账号密码是否正确
//理论上应该从数据库中获取账号密码,校验是否正确,但当前还没讲数据库的操作,先把账号密码固定写死
if (!"zhangsan".equals(userName) || !"123456".equals(password)){
return false;
}
//密码验证成功,把用户名存储在Session中
session.setAttribute("userName",userName);
return true;
}
}
注意事项:setAttribute()
一、"存密码 + 对应读取" 的完整逻辑
以你的登录场景为例:
-
存储密码 :登录成功后,用固定 Key
loginPwd把密码存到 Session 里javascript// 登录接口中存储:Key是"loginPwd",Value是用户输入的密码(比如"123456") session.setAttribute("loginPwd", password); -
读取密码 :后续需要密码时,用同一个 Key
loginPwd从 Session 中读取javascript// 其他接口中读取:通过Key"loginPwd"获取对应的密码值 String savedPwd = (String) session.getAttribute("loginPwd");
二、为什么用 "固定 Key" 就能对应上?
Session 是键值对(Key-Value)映射,就像你用 "标签(Key)" 给物品(Value)做标记:
- 存的时候,给密码贴一个固定标签
loginPwd; - 取的时候,只要找这个标签
loginPwd,就能拿到对应的密码 ------ 这就是 "对应上" 的核心逻辑。
示例:
如果不用固定 Key(即不加双引号,用userName这类变量当 Key),确实需要保证存储和读取时userName的值完全一致且同一变量值只能存一次
第一次存的是lisi,到匹配的时候必须是一样的
StringUtils.hasLength()是 Spring 提供的一个工具方法,判断字符串是否有值字符串为 null 或者 "" 时,返回 false, 其他返回 true
java
public static boolean hasLength(@Nullable String str) {
return str != null && !str.isEmpty();
}
2. 查询登录用户接口
java
/**
* 返回登录用户信息
* @param session
* @return
*/
@RequestMapping("/getLoginUser")
public String getLoginUser(HttpSession session){
//从Session中获取用户登录信息
String userName = (String)session.getAttribute("userName");
//如果用户已经登录,则直接返回用户登录
if (StringUtils.hasLength(userName)){
return userName;
}
return "";
}
3.2.3 调整前端页面代码
1. 调整登录页面 login.html
对于前端而言,当点击登录按钮时,需要把用户输入的信息传递到后端进行校验,后端校验成功,则跳转到首页 index.html, 后端校验失败,则直接弹窗
java
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
function login() {
$.ajax({
type: "post",
url: "/user/login",
data: {
"userName": $("#userName").val(),
"password": $("#password").val()
},
success: function (result) {
if (result) {
location.href = "/index.html"
} else {
alert("账号或密码有误.");
}
}
});
}
</script>
页面跳转的三种方式:
window.location.href = "book_list.html";window.location.assign("book_list.html");window.location.replace("book_list.html");
以上写法,通常把 "window." 省略,比如 window.location.href = "book_list.html"; 写成 location.href = "book_list.html";三者区别参考:location.assign ()、location.href、location.replace (url) 的不同 - 阿里云开发者社区
2. 调整首页代码
首页代码比较简单,只显示当前登录用户即可.当前登录用户需要从后端获取,并显示到前端
java
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
$.ajax({
type: "get",
url: "/user/getLoginUser",
success: function (result) {
$("#loginUser").text(result);
}
});
</script>
3.2.4运行测试

多次刷新http://127.0.0.1:8080/index.html 发现依然可以获取到登录⽤⼾
如果重启服务器,则登录人显示:空
缓存问题;
我们在测试代码的时候我们肯定是先进行使用postman进行测试接口的正确性,如果我们确认了后端是没有问题的,我们就可以看看是不是前端的问题。
我们找到这个网页,查看代码

可是我们的代码是这个样的

与他写的这个不符合,所以我们可以摁住 ctrl + F5 强制刷新游览器页面(跳过游览器的缓存)
还有另一种解决方法就是:在这个url后面加上随机的查询字符串
我们在刷新页面的时候通常会遇到灭有发生改变,这时候我们可以考虑是游览器缓存的问题
删除缓存的游览器记录即可

然后再点击刷新,就会出现了

加随机查询字符串为什么可以预防呢?
判断 URL 是否相同------ 如果 URL 完全一致,浏览器会直接返回本地缓存的结果;如果 URL 不同(哪怕只是多了一个无关的查询参数),浏览器会认为是 "新请求",重新向服务器发起请求,从而拿到最新的资源 / 接口数据。
方式 1:拼接时间戳(最常用,简单无重复)
javascript
$.ajax({
type: "post",
// 拼接时间戳:new Date().getTime() 生成当前毫秒数,每次都不同
url: "userLogin/login2?t=" + new Date().getTime(),
data: {
userName: userName,
password: password
},
success: function (result) {
// 原有逻辑...
},
error: function (err) {
// 原有逻辑...
}
});
方式 2:拼接随机数(效果一样)
url: "userLogin/login2?random=" + Math.random(),
| 场景 | 是否适合用这个方法 | 补充说明 |
|---|---|---|
| 前端 JS/CSS/HTML 静态资源缓存 | ✅ 非常适合 | 比如 <script src="xxx.js?t=123"> |
| AJAX 接口请求缓存 | ✅ 适合 | 解决接口返回旧数据的问题 |
| Postman 测试接口 | ❌ 没必要 | Postman 默认不会缓存请求结果 |
| 后端接口本身的逻辑 | ❌ 不影响 | 随机参数只是 "防缓存标识",后端不会解析(也不需要解析) |
方法三:临时方法 勾选「Disable cache」(禁用缓存)
- 打开你的登录页面,按
F12或右键→「检查」,调出开发者工具; - 切换到
Network(网络)标签页; - 在标签页的顶部 / 底部,找到并勾选「Disable cache」(禁用缓存)选项(部分版本显示为「禁用缓存 (停用开发者工具后失效)」)。
- 勾选后,只要开发者工具不关闭,浏览器刷新页面 / 发起 AJAX 请求时,不会使用本地缓存,会直接从服务器获取最新的资源(HTML/JS/CSS)和接口数据;
- 一旦关闭开发者工具,或者取消勾选,浏览器就会恢复正常的缓存逻辑。