目录
书接上文:Java EE 进阶:4.Spring Web MVC 入门(第三弹)~~
3.综合性练习
结合上述内容,我们可以做一些小案例
主要掌握知识点:
1.理解前后端交互过程
2.接口传参,数据返回,以及页面展示
3.1 加法计算器
需求:输入两个整数,点击”点击相加“按钮,显示计算结果
3.1.1 准备工作
创建 SpringBoot 项目:引入 Spring Web 依赖,把前端页面放在项目中
码云地址:JavaEE 进阶课程资料包
3.1.2 约定前后端交互接口
概念介绍
约定“前后端交互接口”是进行 Web 开发中的关键环节
接口又叫 API(Application Programming Interface),我们一般讲到接口或者 API,指的都是同一个东西
是指应用程序对外提供的服务的描述,用于交换信息和执行任务(与 JavaSE 阶段学习的[类和接口]中的接口是两回事)
简单来说,就是允许客户端给服务器发送哪些 HTTP 请求,并且每种请求预期获取什么样的 HTTP 响应
现在“前后端分离”模式开发,前端和后端代码通常由不同的团队负责开发,双方团队在开发之前,会提前约定好交互的方式,客户端发起请求,服务器提供对应的服务,服务器提供的服务种类有很多,客户端按照双方约定指定选择哪一个服务
接口,其实也就是我们前面网络模块讲的“应用层协议”,把约定的内容写在文档上,就是“接口文档”,接口文档也可以理解为是 应用程序的“操作说明书”
比如儿童电话玩具
按1:响应儿歌
按2:响应钢琴乐曲
按3:安抚睡眠
按4:交通工具音效
……
等等
但是这些操作说明,如果没有一个文档来说明,用户就不太清楚哪个按键对应哪个,所以商品一般会带一个说明书
这些按键,就是接口
这个“说明书”,就是 应用程序的“接口文档”
在项目开发前,根据需求先约定好前后端交互接口,双方按照接口文档进行开发
接口文档通常由服务提供方来写,交由服务使用方确认,也就是客户端
接口文档一旦写好,尽量不要轻易改变
如若需要改变,必须要通知另一方知晓并修改接口文档(服务提供方来写来改)
闲聊:
以后在公司中工作,针对每一个项目:
①提出需求
产品经理→编写需求文档→评审需求文档,这个评审,分为内部评审和外部评审,外部评审:前后端开发人员、测试人员、运维人员 等等相关人员一起“指指点点”
一开始产品经理的薪资没有开发人员高,但是干上个三五年了之后,就会比开发人员高不少了~~
②开发阶段
1)方案设计、评审
2)排期:
接口文档什么时候提供
什么时候开发完成
什么时候自测完成
什么时候联调
什么时候上线
3)提供接口文档
提供接口文档以及相应依赖(可能),这个接口也要评审(非正式)
各自进行开发
需求分析
加法计算器功能,对两个整数进行相加,需要客户端提供参与计算的两个数,服务端返回这两个整数计算的结果
基于以上分析,我们来定义接口
接口定义
接口定义
功能:两个数相加
路径:calc/add、calc/plus、add、plus 等都可以(建议 2~4级路径)
请求路径: calc/sum 请求方式: GET/POST 接口描述: 计算两个整数相加请求参数
参数:完成这个功能,需要哪些参数
参数名
类型
是否必须
备注
num1
Integer
是
参与计算的第一个数
num2
Integer
是
参与计算的第二个数
名字要有含义,不要使用 abc、aa、bb 等无含义的变量,不要使用拼音
示例:num1=5&num2=3
响应数据
返回类型:String、Integer、Long……
Content-Type: text/html 响应内容:计算机计算结果:8服务器给浏览器返回计算的结果
3.1.3 服务器代码
package com.bite.spring.demo; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA. * Description: * User: CoderYanger * Date: 2026-10-23 * Time: 17:45 */ @RequestMapping("/calc") //@RestController 表示返回数据 @Controller 表示返回视图 @RestController public class CalcController { @RequestMapping("/sum") public String sum(Integer num1,Integer num2){ if(num1==null||num2==null){ return "参数不合法,请检查后再提交"; } Integer sum=num1+num2; return "<h1>计算器计算结果:"+sum+"</h1>"; } }用 Postman 测试👇
发现自测没问题
闲聊:对于我们后端,用 Postman 或者 浏览器 自测没问题,那么 95%以上都是没问题的,剩下的不到 5% 可能是 浏览器 和 Postman 的一些展示上的问题,这时候通过抓包去看一下两者的 请求 是否 完全一致,当然,这些细微的差异我们后端都是不关注的,使用其中任意一个自测没问题我们就可以认为没问题了~~
3.1.4 调整前端页面代码
添加访问 url 和请求方式
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 复习:form是个表单域,用于提交数据--> <form action="calc/sum" method="post"> <!-- calc/sum :提交的URL,post:提交方式--> <h1>计算器</h1> <!-- 参数:key对应input的name值--> 数字1:<input name="num1" type="text"><br> 数字2:<input name="num2" type="text"><br> <input type="submit" value=" 点击相加 "> <!-- 提交按钮会把自己所在的表单域内的内容进行提交--> </form> </body> </html>
3.1.5 运行测试
启动服务,运行并测试
注意,右上角给出的访问方式不要点👇
不可以通过这些方式访问,如果不信就点进去看,发现只能查看页面,URL 也变了,这只能查看前端页面,并没有走咱们的后端👇
应该用我们自己服务提供的页面👇
下面我们分别用这两种方式测试一下👇
计算器前后端交互演示
3.2 用户登录
需求:用户输入账号和密码,后端进行校验密码是否正确
1.如果不正确,前端进行用户告知
2.如果正确,跳转到首页,首页显示当前登录用户
3.后续再访问首页,可以获取到登录用户信息
3.2.1 准备工作
把前端页面放在项目中(课件中提供)
码云地址:JavaEE 进阶课程资料包
3.2.2 约定前后端交互接口
需求分析
对于后端开发人员而言,不涉及前端页面的展示,只需要提供两个功能
1.登录首页:通过账号和密码,校验输入的账号密码是否正确,并告知前端
2.首页:告知前端当前登录用户,如果当前已有用户登录,返回登录的账号,如果没有,返回空
接口定义
校验接口
请求路径:/user/login 请求方式:POST 接口描述:校验账号密码是否正确请求参数
参数名
类型
是否必须
备注
userName
String
是
校验的账号
password
String
是
校验的密码
响应数据
Content-Type: text/html 响应内容: true //账号密码验证成功 false //账号密码验证失败查询登录用户接口
请求路径:/user/getLoginUser 请求方式:GET 接口描述:查询当前登录的用户请求参数
无
响应数据
Content-Type: text/html 响应内容: zhangsan返回当前登录的用户
3.2.3 实现服务器端代码
校验接口
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; } }StringUtiles.hasLength() 是 Spring 提供的一个工具方法,判断字符串是否有值
字符串为 null 或者“”时,返回 false,其他返回 true
public static boolean hasLength(@Nullable String str) { return str != null && !str.isEmpty(); }等我们后续接触多了,一看到 Utiles 就知道它是个工具类,这里有很多实用的工具👇
工具类的命名通常是你对于哪一块处理的,前面就加什么,比如说你对于 String ,对字符串的一个工具类,就是 StringUtils,如果你是对于日期的工具类,工具类就叫 DateUtils,然后你对于 Long 的处理,就叫 LongUtils,这也算我们一个不成文的命名规矩,但大家都知道,比如 NumberUtils、TypeUtils👇
查询登录用户接口
package com.bite.spring.demo; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA. * Description: * User: CoderYanger * Date: 2026-10-23 * Time: 20:03 */ @RequestMapping("/user") @RestController public class UserController { @RequestMapping("/login") public Boolean login(String userName,String password){ //参数校验 // if(userName!=null||userName==""||password==null||password==""){ // return false; // } // 上述代码写着太麻烦,我们有更简洁的写法👇 if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){ return false; } //校验用户名和密码是否正确 //还未学习数据库相关的操作,暂且把账号和密码写死 admin admin if("admin".equals(userName)&&"admin".equals(password)){ return true; } return false; } }注意点①:当然这种写法不是唯一的,比如上述代码可以写成👇,但还是建议写成上述代码(因为好看~~)
public Boolean login2(String userName,String password){ //参数校验 if(StringUtils.hasLength(userName)&&StringUtils.hasLength(password)){ if("admin".equals(userName)&&"admin".equals(password)){ return true; } } return false; }我们开发的过程中要求嵌套不能超过五层,层数多了人也会晕~~
其实别说五层了,四层基本都没法看了,所以我们要尽量减少嵌套~~
注意点②:为啥写成 "admin".equals(userName) 而不是 userName.equals("admin")??
因为 equals 会报空指针异常 NullpointException,当前面的值为 null 时,就会报空指针异常,但是后面那个为 null 就没关系,所以我们在去写的时候,通常把常量写在前面
答疑:
Q1:我们前面不是校验过了吗??
确实是,但是你能保证以后写代码都不忘记写校验吗??所以我们还是要养成习惯,避免忘写时出 Bug~~
Q2:校验不是应该前端做吗??
没错,但是后端也得干,参数校验前端后端都要干,前端校验的时候不考虑后端,后端校验的时候不考虑前端,各干各的事儿,前后端都得做,你不校验随便写个代码就扔给前端了,前端一看都运行不起来,肯定会骂你的,丢人~~
接下来我们自测一下👇
发现没问题,接下来再写获取登录用户信息的代码,总的代码👇
package com.bite.spring.demo; import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Created with IntelliJ IDEA. * Description: * User: CoderYanger * Date: 2026-10-23 * Time: 20:03 */ @RequestMapping("/user") @RestController public class UserController { @RequestMapping("/login") public Boolean login(String userName, String password, HttpSession session){ //参数校验 // if(userName!=null||userName==""||password==null||password==""){ // return false; // } // 上述代码写着太麻烦,我们有更简洁的写法👇 if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){ return false; } //校验用户名和密码是否正确 //还未学习数据库相关的操作,暂且把账号和密码写死 admin admin if("admin".equals(userName)&&"admin".equals(password)){ //密码正确 session.setAttribute("userName",userName);//放进session里 return true; } return false; } @RequestMapping("/getLoginUser") public String getLoginUser(HttpSession session){ String userName=(String)session.getAttribute("userName"); return userName; } // public Boolean login2(String userName,String password){ // //参数校验 // if(StringUtils.hasLength(userName)&&StringUtils.hasLength(password)){ // if("admin".equals(userName)&&"admin".equals(password)){ // return true; // } // } // return false; // } }由于一开始我们并没有设置 session,所以获取时是空的👇
set 的话,我们就通过登录来 set 了👇
接下来就能获取登录用户信息了👇
此时第二个接口我们也测试完成了~~
3.2.4 调整前端页面代码
1.调整登录页面 login.html
上面计算器的代码我们是用 form 表单进行提交的,但是它有一个缺点,就是页面一定会发生跳转,所以接下来我们学习用 Ajax 发起请求~~(重点)
啥是 Ajax 呢??👇ajax(Web数据交互方式)_百度百科
原生的 ajax 写起来非常麻烦,现在也没有多少人用了,所以我们学习用 JQuery 完成 Ajax 操作~~
对于前端而言,当点击登录按钮时,需要把用户输入的信息传递到后端进行校验,后端校验成功,则跳转到首页:index.html,后端校验失败,则直接弹窗
login.html 代码展示👇
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>登录页面</title> </head> <body> <h1>用户登录</h1> 用户名:<input name="userName" type="text" id="userName"><br> 密码:<input name="password" type="password" id="password"><br> <input type="button" value="登录" onclick="login()"> <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:{//请求参数 //ID前面加#,.val()拿到值 userName:$("#userName").val(),//取input框里的值 password:$("#password").val() }, //HTTP请求成功了,不关心给的响应是啥,调用回调函数,接收后端参数 success:function(result){//这个result名字随便定义 if(result){//后端返回的result是String,那就是String,后端返回的是JSON,那就是对象,就可以用.来使用了 //后端返回true,说明密码正确,跳转到指定页面 location.href="index.html"; //location.assign("index.html");//这行代码也可以完成页面跳转,了解即可 }else{ //密码错误 alert("密码错误,请确认"); } } }); } </script> </body> </html>复习:id 前加 #,class 前加 . ,取值和赋值都是 val(),参数里面方法没有值表示取值
上述代码有着对应关系👇
页面跳转的三种方式:
1.window.location.href="book_list.html";
2.window.location.assign("book_list.html");
3.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.调整首页代码
下面我们再把 index.html 代码写一下,然后一起测试👇
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>用户登录首页</title> </head> <body> 登录人: <span id="loginUser"></span> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script> <script> $.ajax({ url:"/user/getLoginUser",//因为是个对象,所以没顺序 type:"get", //没有传参,不写 data success:function(userName){ $("#loginUser").text(userName);//span标签使用text方式来赋值 } }); </script> </body> </html>
3.2.5 运行测试
自测演示👇
用户登录页面前后端交互演示
从上述视频中我们发现,当没有登录的时候,登录人是不显示的,账号和密码全正确了才能登录成功~~
注意:如果一直转圈圈,可能是 JQuery 还在加载,这时候可以把 JQuery 设置成本地的,否则后续的代码都需要 JQuery,是运行不起来的,而且其实在 浏览器 中我们也可以实现简单抓包👇
按下 F12 后,在网络部分,左边就是访问的一些东西,右边就是 Header 之类的~~
那如果我们登录之后把 Session 改一下👇
我们把开头的 4 改成 3 再来看一下👇
刷新后就发现找不到了👇
转载自 CSDN-专业IT技术社区
原文链接:https://blog.csdn.net/Miraitowa_6/article/details/168764615






























