前后端“谈恋爱”全流程曝光!一篇爽文带你偷窥它们如何偷偷传数据,3分钟打通任督二脉!
接口名称、方法【请求路径】calc/sum【请求⽅式】GET/POST【接⼝描述】计算两个整数相加【请求路径】【请求⽅式】POST【接⼝描述】校验账号密码是否正确【请求路径】【请求⽅式】GET【接⼝描述】获取留言。
我们在四个小案例中,能学到以下知识:
1. 理解前后端交互过程
2. 接⼝传参,数据返回,以及⻚⾯展⽰
目录

我们这篇博客将会完成前3个期,也就是立项期、设计期、生产期。
我们将会用 需求分析、接口定义、代码实现 来简单带过这三个期,最主要是为了让大家明白前后端的交互。
啥是需求分析?
答:开发团队需要跟客户沟通,根据需要来开发,需要也就是需求分析,这个东西是用来做什么的,简单的流程是怎么样的,也就是对软件的期望。
啥是接口定义?
这个接口并不是我们学面向对象的那个接口,我们管接口又叫API,简单来说就是我们写代码的时候,需要明白的一些东西,比如传参的变量名,url,要请求什么样的http请求,需要接受什么http请求。
为什么要有接口文档?
因为前后端是分离的,所以我们需要提前约定好,那就可以单独开发,双方都做好之后就一起整合到一起,方便又快。
接口的组成一般有如下几点:
- 接口名称:即接口的名称或标识符,用于区分不同的接口。
- 接口方法:即接口所提供的方法,包括 GET、POST、PUT、DELETE 等。
- 接口地址:即接口的访问地址。
- 请求参数:即接口所需要的输入参数,包括参数名称、参数类型、参数说明等。
- 响应参数:即接口所返回的输出结果,包括返回值的类型、名称、说明等。
一、计算器(前后端交互)
需求:输⼊两个整数,点击"点击相加"按钮,显⽰计算结果
需求分析
加法计算器功能,对两个整数进⾏相加,需要客⼾端提供参与计算的两个数,服务端返回这两个整数计算的结果
接口定义
接口名称、方法
【请求路径】
calc/sum
【请求⽅式】
GET/POST
【接⼝描述】
计算两个整数相加
请求参数
| 参数名 | 类型 | 是否必须 | 备注 |
| num1 | Integer | 是 | 两个数相加的第一个数 |
| num1 | Integer | 是 | 两个数相加的第二个数 |
比如:num1=5&num2=8
响应数据
【Content-Type】
text/html
【响应内容】
计算机计算结果 : 8
代码实现
后端,我们通过前端传值num1和num2,然后直接计算,前端访问的路径就是[请求路径]calc/sum,[请求⽅式]GET/POST是都可以传,[Content-Type]text/html就是普通的字符串,[响应内容]就是咱们return的值。
@RequestMapping("calc")
@RestController
public class CalcController {
@RequestMapping("sum")
public String sum(@RequestParam Integer num1,@RequestParam Integer num2){
int sum=num1+num2;
return "计算机计算结果:"+sum;
}
}
前端,我们放在static中,通过form表单发送数据给后端,input输入num1和num2,这样点击submit就会传到action的[请求路径]calc/sum上
<!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 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>
</body>
</html>
我们运行后端之后,通过浏览器访问:http://127.0.0.1:8080/login.html

127.0.0.1是我们的本机
8080是我们idea的端口号
login.html是前端的名字
为什么访问的是login.html而不是calc/login?
答:因为我们得有人赋值给num1和num2,才能进行计算。login.html有form表单给我们赋值
二、用户登录(Session用法)
这里有两个接口,一个是检验用户登录是否正确的接口,一个是查询登录用户的接口
需求分析
后端开发⼈员⽽⾔, 不涉及前端⻚⾯的展⽰, 只需要提供两个功能:
1. 登录⻚⾯: 通过账号和密码, 校验输⼊的账号密码是否正确, 并告知前端
2. ⾸⻚: 告知前端当前登录⽤⼾. 如果当前已有⽤⼾登录, 返回登录的账号, 如果没有, 返回空
接口定义
1.校验接口
【请求路径】
/user/login
【请求⽅式】
POST
【接⼝描述】
校验账号密码是否正确
请求参数
| 参数名 | 参数类型 | 是否必传 | 备注 |
|
userName |
String | 是 | 校验的账号 |
| password | String | 是 | 校验的密码 |
响应数据
【Content-Type】
text/html
【响应内容】
true //账号密码验证成功
false//账号密码验证失败
2.查询登录用户接口
【请求路径】
/user/getLoginUser
【请求⽅式】
GET
【接⼝描述】
查询当前登录的⽤⼾
【请求参数】
无
【响应数据】
【Content-Type】
text/html
【响应内容】
zhangsan
代码实现
【后端】
1.我们通过前端传值userName和password,
然后直接计算,前端访问的路径就是[请求路径]/user/login,
[请求⽅式]POST所以我们需要在RequestMapping定义method为RequestMethod.POST,[Content-Type]为true或者false所以返回值为boolean,
[响应内容]就是咱们return的值。
getUser这个方法也是同理。只要根据接口定义就可以写出来了。
2.HttpSession是Session接口,如果没有赋值,则会自动创建一个空的session,来存储咱们的用户信息。如果重启服务器,session会丢失。
为什么需要Session?
答:因为http是无状态的,你换到别的网址,你的信息就没有保存了,所以我们需要手动设置session来存储,不然就获取不到了。
@RequestMapping("/user")
@RestController
public class LoginController {
@RequestMapping(value = "/login",method = RequestMethod.POST)
public boolean login(@RequestParam String userName,
@RequestParam String password,
HttpSession session){
if(!StringUtils.hasLength(userName)||!StringUtils.hasLength(password)){
return false;
}if("admin".equals(userName)&&"admin".equals(password)){
session.setAttribute("userName",userName);
return true;
}
return false;
}
@RequestMapping(value = "/getLoginUser",method =RequestMethod.GET)
public String getUser(HttpSession session){
String userName= (String) session.getAttribute("userName");
return userName;
}
}
【前端】
1.这里的jQuery文件直接可以上百度搜索,然后另存为,复制到static文件夹里面就好了。
2.重要的是有个Ajax,前端传值并非只能靠form表单,ajax它是前端的一个传值给后端的,它是异步的。
啥是异步?
答:就是可以和后端一起执行,比如邮箱的登录页面,我们输入一个邮箱名,它会给我们显示,这个邮箱名有人注册了,请换一个,这个就是异步,
它会把这个名字发送给后端,然后后端调用数据库,数据库发现有人了,就返回给前端说有人了,让你换一下,这个是可以一起进行的。
ajax语法:
$.ajax({
type:"http[请求⽅式]",
url:"后端的[请求路径]",
data:{
后端数据:$("#前端id名").val(),
.....
},
success:function(后端返回来的结果){
... //(如果成功的业务)
}
});
这里的data里面的后端数据,也就是传值给后端的请求参数,
通过type[请求⽅式] 和对应后端的url[请求路径],就可以传给后端了,如果要传的值是class,就是 . 如果的id就是#。
注意修改了前端之后,一定要按ctrl+f5强刷,然后看看f12有没有修改的代码有没有同步上来。并且Jquery的文件,有些是起不来作用的,不行就再换一个Jquery文件,网上大把。
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="./js/jquery.min.js"></script>
<script>
function login() {
$.ajax({
type: "post",
url: "user/login",
data: {
userName: $("#userName").val(),
password: $("#password").val()
},
success: function (ret) {
if (ret) {
location.href = "index.html";
} else {
alert("账号或密码错误");
}
}
});
}
</script>
</body>
</html>
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="./js/jquery.min.js"></script>
<script>
$.ajax({
type: "get",
url: "user/getLoginUser",
success: function (ret) {
$("#loginUser").text(ret);
}
});
</script>
</body>
</html>
我们运行后端之后,通过浏览器访问:http://127.0.0.1:8080/login.html ,点击登录,就会跳转到index.html了


三、留言板(前后端JSON相关操作)
需求:1. 输⼊留⾔信息, 点击提交,后端把数据存储起来. 2. ⻚⾯展⽰输⼊的表⽩墙的信息
需求分析:
1. 输⼊留⾔信息, 点击提交. 后端把数据存储起来.
2. ⻚⾯展⽰输⼊的表⽩墙的信息
接口定义
1.获取全部留言
请求
【请求路径】
/message/getList
【请求⽅式】
GET
【接⼝描述】
获取留言
响应数据
注意哦,这个是JSON格式的
[
{
"from": "⿊猫",
"to": "⽩猫",
"message": "喵"
},{
"from": "⿊狗",
"to": "⽩狗",
"message": "汪"
}, //...
]
浏览器给服务器发送⼀个 GET /message/getList 这样的请求, 就能返回当前⼀共有哪些留⾔ 记录. 结果以 json 的格式返回过来.
2.发表留言
请求
body也为JSON格式
【请求⽅式】
POST
【请求路径】
/message/publish
【请求参数】
{
"from": "⿊猫",
"to": "⽩猫",
"message": "喵"
}
响应
{
ok:1
}
我们期望浏览器给服务器发送⼀个 POST /message/publish 这样的请求, 就能把当前的留⾔提交给服务器.
代码实现
因为传递的是json对象,所以我们首先要有一个MessageInfo对象,我们直接返回。MessageInfo对象List就好了,因为Spring引入了注解,可以在return返回值的时候直接帮我们转换成Json对象。
这里有个注解是@Data,这个是引入lombok依赖,这样像这些set和get方法,它都可以自动帮我们生成。其他的只要按照接口定义来写代码就是ok的了,请看代码。
为什么这里不需要session,而上个案例要session呢?
答:因为上个案例不是同个页面,这个案例的html只有一个页面,所以不需要用session。
@RequestMapping("/message")
@RestController
public class MessageController {
public List<MessageInfo> list=new ArrayList<>();
@RequestMapping(value = "/getList",method = RequestMethod.GET)
public List<MessageInfo> getList(){
return list;
}
@RequestMapping(value = "/publish",method = RequestMethod.POST)
public boolean publish(MessageInfo messageInfo){
if(StringUtils.hasLength(messageInfo.getFrom())
||StringUtils.hasLength(messageInfo.getTo())
||StringUtils.hasLength(messageInfo.getMessage())){
list.add(messageInfo);
return true;
}else return false;
}
}
BookInfo
@Data
public class MessageInfo {
private String from;
private String to;
private String message;
}
【前端】
我们有两个需要写Ajax的地方,一个是展示List,一个是发送message。
我们先看发送message,其他的都是按接口定义就能写,需要注意的是我们点击发送了之后不会直接显示值在上面,而是要点刷新,
所以我们需要写divE把它接上去,这里的值是前端的值,input输入框的值,因为后端没有传值过来,传的是true和false。
展示List我们依旧是用的Ajax,返回来的是一个list,里面装的是很多个MessageInfo,所以我们用迭代把他们拿出来。因为后端传值过来,所以我们需要写message而不是say。
<!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.min.js"></script>
<script>
$.ajax({
type: "get",
url: "message/getList",
success: function (ret) {
if (ret != null) {
for (var messageInfo of ret) {
//2. 构造节点
var divE = "<div>" + messageInfo.from + "对" + messageInfo.to + "说:" + messageInfo.message + "</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
}
}
}
});
function submit() {
//1. 获取留言的内容
var from = $('#from').val();
var to = $('#to').val();
var say = $('#say').val();
if (from == '' || to == '' || say == '') {
return;
}
$.ajax({
type: "post",
url: "message/publish",
data: {
from: from,
to: to,
message: say
},
success: function (ret) {
if (ret) {
alert("添加成功");
//2. 构造节点
var divE = "<div>" + from + "对" + to + "说:" + say + "</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
} else alert("添加失败");
}
});
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}
</script>
</body>
</html>


四、图书管理(综合性案例)
需求:1. 登录: ⽤⼾输⼊账号,密码完成登录功能 2. 列表展⽰: 展⽰图书
需求分析
1.用户登录
【URL】
POST /user/login
【请求参数】
name=admin&password=admin
【响应】
true //账号密码验证成功
false//账号密码验证失败
2.图书列表
【URL】
POST /book/getList
【 请求参数 】
⽆
【 响应 】
返回图书列表
[
{
"id": 1,
"bookName": " 活着 ",
"author": " 余华 ",
"count": 270,
"price": 20,
"publish": " 北京⽂艺出版社 ",
"status": 1,
"statusCN": " 可借阅 "
},
...
]
字段说明
| id | 图书id |
| bookName | 图书名称 |
| author | 作者 |
| count | 数量 |
| publish | 图书出版社 |
| price | 定价 |
| status | 图书状态 1-可借阅 0-不可借阅 |
| statusCN | 图书状态中文含义 |
【后端】
UserController和BookInfo咱们就不说了,没啥含金量
ListController中我们有个mockList方法,这是一个伪造数据,很常用,因为我们现在没有数据库来调用,所以我们先自己伪造一些数据。
BookInfo
@Data
public class BookInfo {
private Integer id;
private String name;
private String author;
private Integer number;
private BigDecimal price;
private String publish;
private String publishCN;
private Integer status;
}
UserController
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/login",method = RequestMethod.POST)
public boolean login(String name,String password){
if(StringUtils.hasLength(name)&&StringUtils.hasLength(password)){
if("admin".equals(name)&&"admin".equals(password)){
return true;
}
}
return false;
}
}
ListController
@RestController
@RequestMapping("book")
public class ListController {
@RequestMapping(value = "/getList",method = RequestMethod.POST)
public List<BookInfo> getList(){
List<BookInfo> list=mockList();
for(BookInfo info:list){
if(info.getStatus()==1){
info.setPublishCN("可借阅");
}else info.setPublishCN("不可借阅");
}
return list;
}
private List<BookInfo> mockList() {
List<BookInfo> list=new ArrayList<>();
for(int i=1;i<=15;i++){
BookInfo info=new BookInfo();
info.setId(i);
info.setName("书名"+i);
info.setAuthor("作者"+i);
info.setNumber(new Random().nextInt(70));
info.setPrice(new BigDecimal(new Random().nextInt(70)+10));
info.setPublish("出版社"+i);
info.setStatus(i%5);
list.add(info);
}
return list;
}
}
【前端】
login.html前面的案例经常有,我们就跳过了。
book_list.html,我们看Ajax的请求,与之前案例不一样的是,我们捏造的数据需要传到页面上去,每一条都要捏造,所以我们用字符串拼接的形式,最后html填到tbody上。
如果是text的话,就只有文字,css那些显示不出来。location.href=""是前端要跳转url的函数。
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/login.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>
<div class="container-login">
<div class="container-pic">
<img src="pic/computer.png" width="350px">
</div>
<div class="login-dialog">
<h3>登陆</h3>
<div class="row">
<span>用户名</span>
<input type="text" name="userName" id="userName" class="form-control">
</div>
<div class="row">
<span>密码</span>
<input type="password" name="password" id="password" class="form-control">
</div>
<div class="row">
<button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
</div>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script>
function login() {
$.ajax({
type: "post",
url: "user/login",
data: {
name: $("#userName").val(),
password: $("#password").val()
},
success: function (ret) {
if (ret) {
location.href = "book_list.html";
} else {
alert("密码或用户名错误");
}
}
});
}
</script>
</body>
</html>
book_list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图书列表展示</title>
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/list.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/bootstrap.min.js"></script>
<script src="js/jq-paginator.js"></script>
</head>
<body>
<div class="bookContainer">
<h2>图书列表展示</h2>
<div class="navbar-justify-between">
<div>
<button class="btn btn-outline-info" type="button" onclick="location.href='book_add.html'">添加图书</button>
<button class="btn btn-outline-info" type="button" onclick="batchDelete()">批量删除</button>
</div>
</div>
<table>
<thead>
<tr>
<td>选择</td>
<td class="width100">图书ID</td>
<td>书名</td>
<td>作者</td>
<td>数量</td>
<td>定价</td>
<td>出版社</td>
<td>状态</td>
<td class="width200">操作</td>
</tr>
</thead>
<tbody id="tbody">
</tbody>
</table>
<div class="demo">
<ul id="pageContainer" class="pagination justify-content-center"></ul>
</div>
<script>
getBookList();
function getBookList() {
$.ajax({
type: "post",
url: "book/getList",
success: function (ret) {
if (ret != null) {
var finalHtml = "";
for (var bookinfo of ret) {
finalHtml += '<tr>';
finalHtml += '<td><input type="checkbox" name="selectBook" value="' + bookinfo.id + '" id="selectBook" class="book-select"></td>';
finalHtml += '<td>' + bookinfo.id + '</td>';
finalHtml += '<td>' + bookinfo.name + '</td>';
finalHtml += '<td>' + bookinfo.author + '</td>';
finalHtml += '<td>' + bookinfo.number + '</td>';
finalHtml += '<td>' + bookinfo.price + '</td>';
finalHtml += '<td>' + bookinfo.publish + '</td>';
finalHtml += '<td>' + bookinfo.publishCN + '</td>';
finalHtml += '<td>';
finalHtml += '<div class="op">';
finalHtml += '<a href="book_update.html?bookId=' + bookinfo.id + '">修改</a>';
finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + bookinfo.id + ')">删除</a>';
finalHtml += '</div>';
finalHtml += '</td>';
finalHtml += '</tr>';
}
$("#tbody").html(finalHtml);
}
}
});
}
//翻页信息
$("#pageContainer").jqPaginator({
totalCounts: 100, //总记录数
pageSize: 10, //每页的个数
visiblePages: 5, //可视页数
currentPage: 1, //当前页码
first: '<li class="page-item"><a class="page-link">首页</a></li>',
prev: '<li class="page-item"><a class="page-link" href="javascript:void(0);">上一页<\/a><\/li>',
next: '<li class="page-item"><a class="page-link" href="javascript:void(0);">下一页<\/a><\/li>',
last: '<li class="page-item"><a class="page-link" href="javascript:void(0);">最后一页<\/a><\/li>',
page: '<li class="page-item"><a class="page-link" href="javascript:void(0);">{{page}}<\/a><\/li>',
//页面初始化和页码点击时都会执行
onPageChange: function (page, type) {
console.log("第" + page + "页, 类型:" + type);
}
});
function deleteBook(id) {
var isDelete = confirm("确认删除?");
if (isDelete) {
//删除图书
alert("删除成功");
}
}
function batchDelete() {
var isDelete = confirm("确认批量删除?");
if (isDelete) {
//获取复选框的id
var ids = [];
$("input:checkbox[name='selectBook']:checked").each(function () {
ids.push($(this).val());
});
console.log(ids);
alert("批量删除成功");
}
}
</script>
</div>
</body>
</html>


DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)