🙉专栏推荐:Java入门知识🙉
🐹今日诗词:二十五弦弹夜月,不胜清怨却飞来🐹
⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏
⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏
目录
加法计算器
前端页面
这里的计算器是前后端交互的方式, 单纯的前端也可以实现, 但是就达不到练习的目的了
准备工作: 我们先搭建一个简单的页面, 代码和效果如下:
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> </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请求,并且每种请求预期获取什么样的HTTP响应, 不能请求A, 你给我返回B, 请求响应必须正确的
- 现在"前后端分离"模式开发,前端和后端代码通常由不同的团队负责开发.双⽅团队在开发之前,会提前 约定好交互的方式
- 把约定的内容写在⽂档上,就是"接⼝⽂档",接 ⼝⽂档也可以理解为是应⽤程序的"操作说明书
因此后端代码这样写
javaimport org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/calc") public class CalcController { @RequestMapping("/sum") public String sum(Integer num1, Integer num2) { Integer sum = num1 + num2; return "计算结果: " + sum; } }
效果演示
用户登录
约定前后端交互接口
login方法(登录)
首先就是参数效验, 用户名和密码肯定不能为null或者空
参数效验: 1. 可以用if进行多次效验判断(麻烦一点)
2. 使用StringUtils类的hasLength方法进行效验(推荐)
这是登录效验代码
java@RequestMapping("/login") public Boolean login(String username, String password, HttpSession session) { //参数效验(null和空) if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) { return false; } //效验账号密码是否正确 //这里使用硬编码方式演示, 数据库操作效验密码不方便 //假设账号密码是: "zhangsan" "123456" if ("zhangsan".equals(username) && "123456".equals(password)) { //设置Session, 需要创建Session session.setAttribute("username", username); return true; } return false; }
测试一下接口有没问题
查询用户登录接口
java @RequestMapping("/getUserInfo") public String getUserInfo(HttpSession session) { String username = (String) session.getAttribute("username"); return username==null?"":username; }
这样后端接口就写好了, 接下来搞定前端
前端页面
需要用到****Ajax
Ajax,全称是Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)
作用:
- 异步:用户在等待服务器响应时可以继续操作界面,提高了用户体验。
- 无需刷新:局部更新页面,不需要重新加载整个页面。
- 数据交换格式:虽然名字中包含 XML,但 Ajax 可以使用多种数据格式,包括 JSON、HTML 等,不仅限于 XML
同步操作和异步操作
举例解释二者区别
比如去买饭, 我要卖蛋炒饭和奶茶, 正常情况下是买完蛋炒饭, 等老板做完然后去买奶茶
这种情况就是同步操作
异步操作就是: 我先预购蛋炒饭, 然后我去买奶茶, 等蛋炒饭做好了老板通知去拿就可以了
登录界面
通过Ajax, 登录成功进行页面跳转(重定向), 登录失败就提示错误
<!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="jquery-3.7.0.min.js"></script> <script> function login() { $.ajax({ url: "/user/login", //指定请求的URL地址 type: "post", //指定请求的类型 data: { //指定要发送的数据, 这里的数据是从表单中获取的用户名和密码 "userName": $("#userName").val(), // 获取用户名输入框的值 "password": $("#password").val() // 获取密码输入框的值 }, //指定请求成功时的回调函数 success: function (result) { // 如果服务器返回的结果为 true,进行页面跳转 if (result) { location.href = "index.html"; //重定向到index.html页面 } else { alert("密码错误"); //如果结果为 false,弹出密码错误的提示 } } }); } </script> </body> </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="jquery-3.7.0.min.js"></script> <script> $.ajax({ url: "user/getUserInfo", type: "get", success: function (userName) { $("#loginUser").text(userName); } }); </script> </body> </html>
留言板
约定前后端接口
设计思路:
点击提交, 要把数据拼接到留言板下方,
同时需要把数据提交到后端, 交给后端存储, 我们可以通过一个链表存储
并且第一使用留言板, 还要把以前的留言显示在下面(从后端拿到数据并显示在页面上)
因此我们要设计两个接口
- message/public接口: 收集前端提交的数据
- message/getList接口: 返回数据到前端
因此我们可以这样约定前后端接口
public接口
java@RequestMapping(value = "/public", method = RequestMethod.POST) public Boolean publish(@RequestBody MessageInfo messageInfo) { list.add(messageInfo); System.out.println("日志: 后端存储数据成功"); return true; }
getList接口
我们来测试一下接口是否正确
这样后端的代码就没问题了, 接下来我们来写, 前端页面如何通过接口来获取后端数据的代码
前端获取后端数据的代码
分成两步:
首先将以前的留言记录显示到下面, 不能每次打开都要重新留言
由于html代码从上向下执行, 所以这串逻辑代码必须写在script的开头
创建新的留言, 将新的留言数据交给后端保存, 同时将留言显示到下方
显示留言记录
保存并显示新的留言
我们来验证一下效果吧
所有代码
留言板所有代码
html<!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="jquery-3.7.0.min.js"></script> <script> // $.ajax( { url: "message/getList", type: "get", success: function(messages) { if(messages != null) { for(var message of messages) { var tmp = "<div>" + message.from +"对" + message.to + "说:" + message.say +"</div>"; $(".container").append(tmp); } } } } ); //获取留言数据 function submit(){ let from = $("#from").val(); let to = $("#to").val(); let say = $("#say").val(); //不为空 if(from == "" || to == "" || say == ""){ return; } //保存并显示新的留言 $.ajax({ url: "message/public", type: "post", contentType: "application/json", data: JSON.stringify ( { "from": from, "to": to, "say": say } ), success: function(result) { if(result) { //保存成功 //将留言信息显示到页面上 let message = "<div>" + from +"对" + to + "说:" + say +"</div>"; $(".container").append(message); //清空输入信息 $("#from").val(""); $("#to").val(""); $("#say").val(""); } else { //保存失败 alert("留言失败"); } } }); } </script> </body> </html>
后端代码
Message对象代码
javaimport lombok.Data; @Data public class MessageInfo { private String from; private String to; private String say; }
后端接口代码
javaimport org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/message") public class MessageController { private List<MessageInfo> list = new ArrayList<MessageInfo>(); @RequestMapping(value = "/public", method = RequestMethod.POST) public Boolean publish(@RequestBody MessageInfo messageInfo) { list.add(messageInfo); System.out.println("日志: 后端存储数据成功"); return true; } @RequestMapping(value = "/getList", method = RequestMethod.GET) public List<MessageInfo> getList() { System.out.println("日志: 前端获取数据成功"); return list; } }
图书管理系统
界面
约定前后端接口
我们先来写登录接口: 判断账号密码是否正确, 首先要有账号密码的属性
java
import lombok.Data;
@Data
public class UserInfo {
private String username;
private String password;
}
hasLength()方法: 参数为null或者长度为空, 返回false
equal()方法: 判断二个参数是否相等
java@RestController @RequestMapping("/user") public class UserController { @RequestMapping("/login") public String login(String username, String password) { //判断账号或密码是否为空或者长度为0, 为空或0,方法返回false if (!StringUtils.hasLength(username) || !StringUtils.hasLength(password)) { return "账号或密码不能为空"; } //硬编码方式 if (!"zhangsan".equals(username) || !"123456".equals(password)) { return "账号或密码错误"; } return ""; } }
图书列表: getList接口
我们通过链表存储图书, 先创建图书的属性
状态码, 因为图书状态只有可借阅和不可借阅两种情况, 所以可以用数字代替中文, 企业开发用状态码, 显示成借阅和不可借阅是前端的事情
java@Data public class BookInfo { private Integer bookId; // 图书id private String bookName; // 书名 private String author; // 作者 private Integer number; // 数量 private BigDecimal price;// 定价 private String publishName;// 出版社 private Integer status; // 状态码, 因为图书状态只有可借阅和不可借阅两种情况, 企业开发用状态码, 变成中文是前端的事情 private String statusCN; // (可有可无)状态码对应的中文, 现在我们写项目前后端都是自己, 需要显示一下 }
getList接口, 以及接口测试
javapackage com.white.demo; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Random; @RestController @RequestMapping("/book") public class BookController { private List<BookInfo> list = new ArrayList<BookInfo>(); @RequestMapping("/getList") public List<BookInfo> getList() { list = mockData(); //mock测试(模拟测试) return list; } private List<BookInfo> mockData() { //mock测试(从数据库调用数据进行测试), for (int i = 0; i < 15; i++) { //由于咱们没数据库, 所以使用mockData方法模拟数据库 BookInfo bookInfo = new BookInfo(); bookInfo.setBookId(i); bookInfo.setBookName("书名: " + i); bookInfo.setAuthor("作者: " + i); bookInfo.setNumber(3*i+1); bookInfo.setPrice(new BigDecimal(new Random().nextInt(100))); bookInfo.setPublishName("出版社: " + i); bookInfo.setStatus(i%2==0?1:2); bookInfo.setStatusCN(i%2==0?"可借阅":"不可借阅"); list.add(bookInfo); } return list; } }
使用postman测试
前端页面
我们要实现从后端拿到数据放到前端, 通过ajax拿到数据后, 如何展示页面呢?
使用HTML的话, 只能一个一个的拼接
拼接方法:
1. 先只写一对 单引号''
例如:
var tmp = '<tr>123<tr>';
2. 然后把123替换成一对 单引号, 变成这样
tmp = '<tr>''<tr>'; (中间两个单引号)
3.在中间两个单引号之间加上两个+号, 变成这样
tmp = '<tr>'++'<tr>';
4. 再两个 + 号中间填上属性变量即可
tmp = '<tr>'+要替换的变量+'<tr>';
比如这种形式: tmp = '<tr>'+bookId+'<tr>';
拼接结果就是前面两个单引号是一对
根据上述方法, 可以得到以下界面
运行结果
应用分层(重点)
应用分层是一种设计架构, 将代码分为多个独立的层次, 可以提高代码的可阅读性, 可维护性、可扩展性和灵活性, 并且代码出现问题非常容易找到出错的部分
应用三层一般分为三层:表现层(Controller),业务逻辑层(Service),数据层(Dao), 有时候还会加入实体类层(model, pojo, DTO, VO.....)
表现层(Controller)
作用: 比如用户登录例子, 表现层获取用户的输入(如用户名和密码),将这些数据传递给业务逻辑层
业务逻辑层(Service)
作用: 对用户登录的账户密码进行效验的代码属于业务逻辑层, 效验成功, 调用数据层的数据, 将页面展示出来
数据层(Dao)
作用: 接收业务逻辑层, 存储数据, 或者返回数据给业务逻辑层, 数据层一般不会调用表现层, 业务逻辑层,
三者调用关系
表现层:创建一个业务逻辑层对象,逻辑层去执行获取的操作
业务逻辑层:创建一个数据层对象,通过数据层对象调用数据库中的数据
数据层:存储数据,提供一个接口方法,让业务逻辑层调用
那我们现在来对代码进行分层吧
首先创建4个包, 用于待会存放分层的代码
我们来对这串代码进行应用分层
表现层:创建一个业务逻辑层对象,逻辑层去执行获取的操作
业务逻辑层:创建一个数据层对象,通过数据层对象调用数据库中的数据
数据层:存储数据,提供一个接口方法,让业务逻辑层调用