Java EE 进阶:4.Spring Web MVC 入门(第四弹)
目录
3.综合性练习
3.1 加法计算器
3.1.1 准备工作
3.1.2 约定前后端交互接口
概念介绍
需求分析
接口定义
请求参数
响应数据
3.1.3 服务器代码
3.1.4 调整前端页面代码
3.1.5 运行测试
3.2 用户登录
3.2.1 准备工作
3.2.2 约定前后端交互接口
需求分析
接口定义
校验接口
请求参数
响应数据
查询登录用户接口
请求参数
响应数据
3.2.3 实现服务器端代码
校验接口
查询登录用户接口
3.2.4 调整前端页面代码
1.调整登录页面 login.html
2.调整首页代码
3.2.5 运行测试
书接上文: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 再来看一下👇
刷新后就发现找不到了👇