目录
[一. 加法计算器](#一. 加法计算器)
[1. 准备工作](#1. 准备工作)
[2. 约定前后端交互接口](#2. 约定前后端交互接口)
[3. 服务器端代码](#3. 服务器端代码)
[4. 运行测试](#4. 运行测试)
[二. 用户登录](#二. 用户登录)
[1. 准备工作](#1. 准备工作)
[2. 约定前后端交互接口](#2. 约定前后端交互接口)
[(1) 登录界面接口](#(1) 登录界面接口)
[(2) 首页接口](#(2) 首页接口)
[3. 服务器端代码](#3. 服务器端代码)
[4. 运行测试](#4. 运行测试)
[三. 留言板](#三. 留言板)
[1. 准备工作](#1. 准备工作)
[2. 约定前后端交互接口](#2. 约定前后端交互接口)
[3. 服务器端代码](#3. 服务器端代码)
[四. 图书管理系统](#四. 图书管理系统)
[1. 准备工作](#1. 准备工作)
[2. 约定前后端交互接口](#2. 约定前后端交互接口)
[3. 服务器端代码](#3. 服务器端代码)
[五. lombook 介绍](#五. lombook 介绍)
[六. 应用分层](#六. 应用分层)
一. 加法计算器
1. 准备工作
创建SpringBoot项目, 并引入SpringBoot依赖. 把前端页面的代码放到项目中.
前端代码:
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>
2. 约定前后端交互接口
由于现在大多是以 "前后端分离模式" 开发, 前后端代码通常由不同团队进行开发. 所以双方团队在开发之前, 会提前约定好前后端交互方式. 常用 "接口文档" 来描述它. (接口文档 也可以理解为"应用程序的说明书").
需求分析
加法计算器功的能是对两个整数进行相加. 需要客户端提供参与计算的两个数, 服务端返回这两个整数相加的结果.
接口定义
html
请求路径: clac / sum
请求方式: GET / POST
接口描述: 计算两个整数相加
请求参数:
响应数据:
html
Content-Type: text / html
响应内容: 计算机计算结果: x
3. 服务器端代码
java
@RestController
@RequestMapping("/calc")
public class CalcController {
@RequestMapping("/sum")
public String sum(Integer num1, Integer num2) {
int sum = num1 + num2;
return "<h1>计算机计算结果: "+sum+"</h1>";
}
}
4. 运行测试
运行main方法, 启动服务.
访问服务地址: http://127.0.0.1:8080/calc.html
二. 用户登录
1. 准备工作
创建SpringBoot项目, 并引入SpringBoot依赖. 把前端页面的代码放到项目中.
- index.html (登录界面) 代码:
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进行前后端交互
$.ajax({
//小括号中是一个对象,对象用大括号括起来
type:"post",
url:"/user/login",
data:{
"username":$("#userName").val(),
"password":$("#password").val()//通过Id获取值,给后端传递参数
},
success: function (result) {//参数名任意,用于接收后端返回的参数
if (result){
location.href = "/index.html"//跳转页面
}else {
alert("账号或密码有误");//弹窗
}
}
});
}
</script>
</body>
</html>
- login.html (首页) 代码:
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({
type : "get",
url : "/user/getLoginUser",
success:function (result) {
$("#loginUser").text(result);//给loginUser参数赋值为后端返回的result值
}
})
</script>
</body>
</html>
2. 约定前后端交互接口
需求分析
(1) 登录页面: 通过账号和密码, 校验输入的账号密码是否正确, 并告知前端.
(2) 首页: 告知前端当前登录用户. 如果当前已有用户登录, 返回登录的账号; 如果没有, 返回空.
接口定义
(1) 登录界面接口
接口定义:
html
请求路径: /user/login
请求方式: POST
接口描述: 校验账号密码是否正确.
请求参数:
响应数据:
html
Content-Type : text/html
响应内容:
账号密码正确:true
账号密码错误:false
(2) 首页接口
接口定义:
html
请求路径: /user/getLoginuser
请求方式: GET
接口描述: 显示当前登录用户的主页,主页上显示用户名.
请求参数: 无
响应数据:
java
Content-Type:text/html
响应内容: 登录的用户名.
3. 服务器端代码
(1) 登录界面接口
java
@RestController
@RequestMapping("/user")
public class LoginController {
@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;
}
//StringUtils.hasLength()是Spring提供的一个方法, 用于判断字符串是否有值.
//字符串为 null 或 "" 时, 返回false, 其他情况返回true.
}
(2) 首页接口
java
@RestController
@RequestMapping("/getLoginUser")
public class getLoginUser {
@RequestMapping("/")
public String getLoginUser(HttpSession session) {
//从Session中获取用户登录信息
String userName = (String) session.getAttribute("userName");
//如果用户已经登录, 则直接返回用户名
if (StringUtils.hasLength(userName)) {
return userName;
}
//否则什么都不返回
return "";
}
}
4. 运行测试
验证不成功:
验证成功:
三. 留言板
1. 准备工作
创建SpringBoot项目, 并引入SpringBoot依赖. 把前端页面的代码放到项目中.
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="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
load();//每次在重新加载页面之后,都要从后端的List中调动数据,保证上次添加的数据不会丢失
function load(){
$.ajax({
type: "get",
url:"message/getList",
success:function (result){
for (var message of result){
var divE = "<div>"+message.from +"对" + message.to + "说:" + message.say+"</div>";
$(".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",
contentType: "application/json",
//传递的值是json类型,data就是在向后端传递数据
data:JSON.stringify({
from : from,
to : to,
say : say//从前端参数的ID中获取对应的值传递给后端
}),
//后端返回结果
success:function (result) {
if (result){
//2. 构造节点
var divE = "<div>"+from +"对" + to + "说:" + say+"</div>";
//3. 把节点添加到页面上
$(".container").append(divE);
//4. 清空输入框的值
$('#from').val("");
$('#to').val("");
$('#say').val("");
}else{
alert("提交留言失败")
}
}
});
}
</script>
</body>
</html>
2. 约定前后端交互接口
需求分析
后端需要提供两个服务;
(1) 提交留言: 客户输入留言信息之后, 后端要把留言信息保存起来.
(2) 展示留言: 页面展示时, 需要从后端获取到所有的留言信息.
接口定义
获取全部留言
发表新留言
3. 服务器端代码
java
package com.example.demo;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
@RequestMapping("/message")
@RestController
public class MessageWall {
public List<MessageInfo> messageInfoList = new ArrayList<>();
@RequestMapping("/publish")
public Boolean messageController(@RequestBody MessageInfo messageInfo){
System.out.println(messageInfo); //打印日志
if (StringUtils.hasLength(messageInfo.from) &&
StringUtils.hasLength(messageInfo.to) &&
StringUtils.hasLength(messageInfo.say)){
messageInfoList.add(messageInfo);
return true; //都有长度,添加成功,返回true
}
// 否则 添加失败,返回false
return false;
}
@RequestMapping("/getList")
public List<MessageInfo> getList(){
return messageInfoList;
}
}
java
package com.example.demo;
import lombok.Data;
@Data
public class MessageInfo {
public String from;
public String to;
public String say;
}
四. 图书管理系统
1. 准备工作
创建SpringBoot项目, 并引入SpringBoot依赖. 把前端页面的代码放到项目中.
- 登录页面:
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 (result) {
if (result){
location.href = "book_list.html";
}else{
alert("账号或密码错误")
}
}
});
}
</script>
</body>
</html>
- 图书列表:
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>
</tbody>
</table>
<div class="demo">
<ul id="pageContainer" class="pagination justify-content-center"></ul>
</div>
<script>
getBookList();
function getBookList() {
$.ajax({
type: "get",
url: "/book/getList",
success: function (result) {
console.log(result);
if (result != null) {
var finalHtml = "";//构造字符串
for (var book of result) {
finalHtml += '<tr>';
finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="selectBook" class="book-select"></td>';
finalHtml += '<td>' + book.id + '</td>';
finalHtml += '<td>' + book.bookName + '</td>';
finalHtml += '<td>' + book.author + '</td>';
finalHtml += '<td>' + book.count + '</td>';
finalHtml += '<td>' + book.price + '</td>';
finalHtml += '<td>' + book.publish + '</td>';
finalHtml += '<td>' + book.statusCN + '</td>';
finalHtml += '<td><div class="op">';
finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';
finalHtml += '<a href="javascript:void(0)"οnclick="deleteBook(' + book.id + ')">删除</a>';
finalHtml += '</div></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>
2. 约定前后端交互接口
需求分析
登录: 用户输入账号和密码完成登录功能.
列表: 展示图书
接口定义
登录接口:
java
[URL]
POST /user/login
[请求参数]
name=admin&password=admin
[响应]
true //账号密码验证成功
false//账号密码验证失败
列表:
java
[URL]
POST /book/getList
[请求参数]
⽆
[响应]
返回图书列表
[
{
"id": 1,
"bookName": "活着",
"author": "余华",
"count": 270,
"price": 20,
"publish": "北京⽂艺出版社",
"status": 1,
"statusCN": "可借阅"
},
...
属性说明:
3. 服务器端代码
登录页面
java
package com.jrj.library;
import jakarta.servlet.http.HttpSession;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/user")
@RestController
public class Login {
@RequestMapping("/login")
public Boolean login(String name, String password, HttpSession session){
if (!StringUtils.hasLength(name) || !StringUtils.hasLength(password)){
return false;
}
if ("zhangsan".equals(name) && "123456".equals(password)){
session.setAttribute("userName",name);
return true;
}
return false;
}
}
图书列表
创建图书:
java
package com.jrj.library;
import lombok.Data;
@Data
public class BookInfo {//构造一本书所有的属性
public Integer id;
public String bookName;
public String author;
public Integer count;
public Integer price;
public String publish;
public Integer status;//1-可借阅,2-不可借阅
public String statusCN;
}
返回图书列表:
java
package com.jrj.library;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
@RequestMapping("/book")
@RestController
public class BookController {
@RequestMapping("/getList")
public List<BookInfo> getList(){
List<BookInfo> list = mockData();
for (BookInfo bookInfo:list){
if (bookInfo.status == 1){
bookInfo.setStatusCN("可借阅");
}else{
bookInfo.setStatusCN("不可借阅");
}
}
return list;
}
//模拟数据
private List<BookInfo> mockData(){
List<BookInfo> list2 = new ArrayList<>();
for (int i = 0; i < 5; i++) {
BookInfo bookInfo = new BookInfo();
bookInfo.setId(i);
bookInfo.setBookName("Java编程思想"+i);
bookInfo.setCount(1);
bookInfo.setPublish("机械工业出版社");
bookInfo.setPrice(new Random().nextInt(100));
bookInfo.setAuthor("高斯林");
bookInfo.setStatus(1);
list2.add(bookInfo);
}
return list2;
}
}
五. lombook 介绍
lombook是一个Java工具库, 通过添加注解的方式, 来简化Java开发.
使用方法:
也可直接使用 @Data注解, 只不过 @Data注解 比较粗暴:
@Data =
@Getter+@Setter+@ToString+@NoArgsConstructor +@RequiredArgsConstructor
六. 应用分层
为了不使我们的代码看起来比较杂乱, 我们使用应用分层来对代码进行分层管理.
Spring项目常见的三层应用分层:
① Controller (接口层) : 负责与外部做交互.
② Service (逻辑层) : 负责做逻辑处理.
③ Mapper / Dao (持久层) : 负责从数据库拿数据 (相当于数据库的客户端).
还有最底层的数据库 (DB) : 使用MySQL或Oracle (不在三层分层中).
MVC和三层架构的关系:
软件设计原则: 高内聚+低耦合