# 前言

在此次教程中,我会教大家如何写一套前后端分离图书管理系统:

前端技术栈:
HTML5+CSS3+JavaScript
后端技术栈:
Java+SpringBoot+MySQL

适合人群:未来做前端或后端或全栈有兴趣的技术人员

系统环境:
操作系统:Windows 10
前端工具:Visual Studio Code
后端工具:IDEA
数据库:MySQL 5.7.26
环境搭建:PHPStudy

本项目采用 MVC 模式书写

注意!!!本章节含有大量 CV 代码,慎重!!!只是简单的一些对数据库的处理操作,看看就行

# 已知 BUG

1. 使用 MySQL 8 + 此项目在此项目有bug
BUG 产生原因
因为在 MySQL 8 中, 已将 groups 添加为关键字,所以导致查询,插入,修改图书表字段 groups 时会发生报错
修改 BUG 方式
将图书表的 groups 字段修改为 bookgroups 字段
前端图书管理页面,把 input 输入框为 groups 的输入框改为 bookgroups
后端 Book 实体类 groups 改为 bookgroups

# 什么是 MVC 模式?

3536e1b2e57bcf8226b5dbd2d7ed06c8

引用 runoob 对 MVC 的介绍 源地址

# 零、项目图片

# 登录页面

ed616d47690377dddacd3f5e7edac430

# 图书管理页面

f78ec6fae8006caf469106f1579f05d6

# 借阅图书页面

111fe1a4fe2e7e8e6101f124f2fb613b

# 归还图书页面

e52d02c7421cf0cf0b3963910fcfe917

# 超时查询页面

bab33de96b6deb446129e9112984169f

# 用户管理页面

1a3a4ef18d606ab89fbbc87b59fe3ef6

# 一、项目结构

9876e3861958ecd39d6459807ea6242e

a7b35e20671e48972301fe7654ce4e17

368d3feff7153caf88cefd86ba9d2bc6

# 二、从 0 到 1 (0 -> 1)

# 首先是

选择一个合适的硬盘创建自己的项目文件夹,在项目文件夹里创建 HTML5 和 SpringBoot 文件夹
c4a8e9aaeee03b60bc4ec193ae8b7dde
HTML5 文件夹用于存放前端显示页面
SpringBoot 文件夹用于存放后端服务器代码

以上两个文件夹也可以按照自己喜欢的名字来进行创建,本篇教程之后会以这两个文件夹创建文件,请注意自己的文件存放位置

# 数据库设置

首先创建 library 数据库

create database library default character set utf8 collate utf8_general_ci;

然后进入 library 数据库里

use library;

创建图书表

CREATE TABLE `books` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `groups` varchar(255) NOT NULL DEFAULT '',
  `name` varchar(255) NOT NULL DEFAULT '',
  `author` varchar(255) NOT NULL DEFAULT '',
  `press` varchar(255) NOT NULL DEFAULT '',
  `price` double(10,2) NOT NULL DEFAULT '0.00',
  `quantity` int(5) NOT NULL DEFAULT '0',
  `ISBN` varchar(13) NOT NULL DEFAULT '',
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8;

在图书表里添加书本

INSERT INTO `books` VALUES (1,'地理','房龙地理','房龙','文汇出版社',29.01,10,'9780000000001'),(2,'地理','地理学与生活','[美] 阿瑟·格蒂斯 ','世界图书出版公司',49.00,10,'9780000000002'),(3,'地理','古老阳光的末日','Thom Hartmann','上海远东出版社',20.00,10,'9780000000003'),(4,'法律','洞穴奇案','[美] 萨伯','生活.读书.新知三联书店',18.00,10,'9780000000004'),(5,'法律','西窗法雨','刘星','法律出版社',24.00,10,'9780000000005'),(6,'法律','审判为什么不公正','[英] 卡德里','新星出版社',49.50,10,'9780000000006'),(7,'军事','亮剑(舒适阅读版)','都梁','北京联合出版公司',45.00,10,'9780000000007'),(8,'军事','二战记忆 安妮日记','[德] 安妮·弗兰克','人民文学出版社',23.00,10,'9780000000008'),(9,'军事','亮剑','都梁','解放军文艺出版社',25.00,10,'9780000000009'),(10,'历史','历史是什么?','爱德华·霍列特·卡尔','商务印书馆',19.00,10,'9780000000010'),(11,'历史','中国史学史','金毓黻','商务印书馆',19.00,10,'9780000000011'),(12,'历史','史记选','[清] 储欣','商务印书馆',48.00,10,'9780000000012'),(13,'计算机','Java从入门到精通 ','明日科技','清华大学出版社',69.00,10,'9780000000013'),(14,'计算机','C++从入门到精通','李伟明','清华大学出版社',49.00,10,'9780000000014'),(15,'计算机','PHP从入门到精通','千锋教育高教产品研发部','清华大学出版社',59.00,10,'9780000000015');

创建用户表

CREATE TABLE `users` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `groups` varchar(255) NOT NULL DEFAULT 'user',
  `username` varchar(255) NOT NULL DEFAULT '',
  `password` varchar(255) NOT NULL DEFAULT '',
  `gender` varchar(255) NOT NULL DEFAULT '',
  `id_card` int(8) NOT NULL DEFAULT '0',
  `phone` varchar(11) NOT NULL DEFAULT '0',
  `identity` varchar(255) NOT NULL DEFAULT '学生',
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

插入一条管理员用户数据

INSERT INTO `users` VALUES (1,'admin','Admin','123456','男',0,0,'管理员');

Admin 是用户名
123456 是密码

可以自行修改用户名或密码,之后执行登录操作时需要用到

创建借书表

CREATE TABLE `borrow` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL DEFAULT '',
  `ISBN` varchar(13) NOT NULL DEFAULT '',
  `username` varchar(255) NOT NULL DEFAULT '',
  `id_card` varchar(8) NOT NULL DEFAULT '',
  `phone` varchar(11) NOT NULL DEFAULT '',
  `time` date NOT NULL DEFAULT '1970-01-01',
  `r_time` date NOT NULL DEFAULT '1970-01-01',
  PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

存放借阅的图书信息

or

你可以选择下载此文件来自动导入到数据库中
网盘链接
提取码: 6666

# 创建 SpringBoot 项目

新建一个项目
1dcf874a76ccb4f2bc9981041e24601b
选择 Spring Initializr 项目
d19d3837d4b090efd600efd84201f579
设置以下信息
28ea460da99c565bf49731a81b27733a
Group:组名
一般格式为 com. 公司名。项目名。模块名 没有公司名就用自己的名字
Artifact:工程名
Type:项目类型
Language:使用语言
Packaging:包装类型
Java Version:JDK 版本
Version:项目版本
Name:项目名
Description:项目描述
Package:包

选择 Spring 要添加的组件
Lombok
e6dc5fcfdb645fd2e9e1cb4b9095800d
Spring Web
a980432998c8e3c5d8fcc350cdcf8bf6
Spring Data JPA 和 MySQL Driver
f619a0d2bcd65d676914b008c8237c3f
选择刚才创建的 SpringBoot 文件夹
ba60d2f2b08aa138021ef64bbd24ed0d
在 pom.xml 文件下添加 JSONObject 依赖

<!--		JSONObject-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.28</version>
</dependency>
<!--		JSONObject 依赖 -->
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>

e297cf92e5ce4002c6f6f03978a94bdc

构建过程中最好使用代理构建项目

如果您的项目构建失败,您可以通过下面的链接下载我已经构建好的项目来开发

项目链接
提取码: 77tr

# 配置数据库连接文件

先删除 src 下的 application.properties 文件
ac1e92c7549c860892c2d5cd2c058d8b
在这里我用 yml 格式连接数据库
在 resources 文件夹新建一个 application.yml 文件
在文件里写入以下代码

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/library?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
    username: root #用户名
    password: 123456 #密码
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
server:
  port: 8181 #服务器端口

以上就创建完了 SpringBoot 项目

# 三、登录页面

# 前端

创建完成后,就可以开始写第一个页面
在 HTML5 文件夹创建 index.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>
    
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
</html>

分别在 css 文件夹和 js 文件夹创建 index.css 和 index.js
然后在 index.html 文件里引用这两个文件

<link rel="stylesheet" href="library/css/index.css">
<script src="library/js/index.js">

接下来创建一个登录面板

<div class="login-pane">
        <form method="post" class="login-form">
            <h3>图书管理系统</h3>
            <input type="text" name="username" id="username" class="username-text" placeholder="用户名">
            <input type="password" name="password" id="password" class="password-text" placeholder="密码">
            <input type="submit" value="登录" class="login-button btn btn-primary" id="login-button">
        </form>
    </div>

在 index.css 写样式代码 美化登录面板

*{
    margin:0;
    padding: 0;
    outline: none;
}
html,body{
    width: 100%;
    height: 100%;
}
body{
    display: flex;
    justify-content: center;
    align-items: center;
    background-color: rgb(249,249,249);
}
.login-pane{
    display: flex;
    justify-content: center;
    align-items: center;
    width: 375px;
    height: 500px;
    background-color: #fff;
    border-radius: 4px;
    box-shadow: 1px 1px 10px #b8b8b8;
}
.login-pane .login-form h3{
    text-align: center;
    margin-bottom: 50px;
}
.login-pane .login-form input{
    display: block;
    text-align: center;
    width: 250px;
    padding-top: 4px;
    padding-bottom: 4px;
    margin-bottom: 16px;
    border: 1px solid gainsboro;
    border-radius: 4px;
}
.login-pane .login-form .login-button{
    padding-top: 4px;
    padding-bottom: 4px;
    width: 250px;
}

给登录面板绑定事件
在 index.js 写入

$(function(){
    // 判断用户是否登录过
    var is_login = $.cookie("username");
    if(is_login != null && is_login != "" && is_login != ''){
        window.location.replace("/library/library.html");
    }
    // 获取表单组件
    var username = $('.username-text');
    var password = $('.password-text');
    var login_button = $('.login-button');
    // 登录按钮点击事件
    login_button.click(function (e) { 
        e.preventDefault();
        // 判断输入框
        if(username.val() == ""){
            alert("请输入用户名");
        }
        else if(password.val() == ""){
            alert("请输入密码");
        }
        else{
            // 事件执行
            $.ajax({
                type: "post",
                url: "http://这里填你电脑的本地IP:这里填你SpringBoot服务端的端口/nav/login",
                data: {"username":username.val(),"password":password.val()},
                dataType: "json",
                success:function(data){
                    // 如果后端返回的 code 值为 1 则登录成功
                    if(data.code == "1"){
                        alert("登录成功");
						$.cookie("username",data.username);
                        window.location.replace("/library/library.html");
                    }
                    // 如果后端返回的 code 值为 0 则登录失败
                    if(data.code == "0"){
                        alert("账号或密码错误");
                    }
                },
                error:function(data){
                    // 如果前端与后端交互出问题则报错
                    alert("系统错误");
                }
            });
        }
    });
});

# 后端

现在,登录页面就已经制作完成,现在开始制作后端登录模型

在 SpringBoot 项目中创建以下包与文件
f65f4e9c1bb0215a77f68ef0c1500797
包:
config ------------ 配置类
controller --------- 控制类
entity -------------- 实体类
repository -------- 储存类

类:
CrosConfig ------------ 解决跨域问题
UsersHandler ---------- 用户操作
Users --------------------- 用户实体
UsersRepository ------- 用户存储库

注意!这里的 Users 最好是对应上数据库的 users 表名,不然对数据库的操作会报错

在 CrosConfig 下写入

package com.ksamar.library.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CrosConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") // 映射
                .allowedOriginPatterns("*") // 允许的模式
                .allowedMethods("GET","HEAD","POST","PUT","DELETE","OPTIONS") // 允许的请求
                .allowCredentials(true) // 允许凭据
                .maxAge(3600) // 最大请求
                .allowedHeaders("*"); // 允许的标头
    }
}

在 UsersHandler 写入

package com.ksamar.library.controller;
import com.alibaba.fastjson.JSONObject;
import com.ksamar.library.entity.Users;
import com.ksamar.library.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
@RestController
@RequestMapping("/nav") // 这里是请求地址如 果要用这个类的方法就需要使用 http://ip/nav 请求地址
public class UsersHandler {
    @Autowired
    private UsersRepository usersRepository; // 用户存储库 用来装用户的数据
    // 用户登录
    @PostMapping("/login") // 这里是登录的请求地址和上面一样在 /nav 后面加上 /login 就能请求了
    public Object findOne(Users users){
        Example<Users> userExample = Example.of(users) ; // 封装表单传过来的数据
        Optional<Users> userOptional = usersRepository.findOne(userExample); // 与数据库交互 去寻找表单所提交的用户存不存在
        JSONObject jsonObject = new JSONObject(); // 创建一个空 JSONObject 对象
		//0 代表登录失败 1 代表登录成功
        // 判断这个用户是否存在
        if (userOptional.isPresent()){
            Users userTemp = userOptional.get(); // 获取用户数据
			// 判断这个用户是不是管理组的
            if(userTemp.getGroups().equals("admin")){
            	// 判断用户提交的用户名和数据库的是否一致
				if(users.getUsername().equals(userTemp.getUsername())){
					// 判断用户提交的密码和数据库的是否一致
                    if(users.getPassword().equals(userTemp.getPassword())){
                        jsonObject.put("code","1");
                        jsonObject.put("username",userTemp.getUsername());
                    }
                    else{
                        jsonObject.put("code","0");
                    }
                }
                else{
                    jsonObject.put("code","0");
                }
            }
            else{
                jsonObject.put("code","0");
            }
        }
        else{
            jsonObject.put("code","0");
        }
        return jsonObject;
    }
}

在 Users 里写入

package com.ksamar.library.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Data
public class Users {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO) // 设置 Id 自增
    // 这里就是与数据库对应字段就可以了 Integer 代表 int  String 代表 varchar
    private Integer id;
    private String groups;
    private String username;
    private String password;
    private String gender;
    private String id_card;
    private String phone;
    private String identity;
}

在 UsersRepository 里写入

package com.ksamar.library.repository;
import com.ksamar.library.entity.Users;
import org.springframework.data.jpa.repository.JpaRepository;
// 这里实现用户存储的接口
public interface UsersRepository extends JpaRepository<Users,Integer> {
}

b7e09bfe83a54977cfd4ef3925fd5ea1
运行一下 SpringBoot 然后打开之前写的登录页面就能食用了
最后,在 library 文件夹下新建一个 library.html 登录页面就制作完成了
是不是很简单呢?

当然,使用Cookie的方式存储用户登录是不安全的行为

# 登录是如何实现的?

首先是从 View 视图页面获取用户输入的表单信息,点击表单按钮后,表单信息利用 Controller 把信息传送 到后端的 Model 里,然后这些信息在 Model 里进行数据处理,数据处理完之后,再从后端的 Model 里面,返回一个 json 文件给 Controller,然后 Controller 接收到 Model 的 json 返回文件,就去处理 json 文件里的信息,然后用 View 展示处理后的界面。
8c80b7226540cf3d7203b105de2b2050

# 四、图书管理页面

弄好了登录页面后,登录成功将会切到图书管理页面
要做的工作:
#. 判断用户登录状态
1. 图书管理页面
2. 借阅图书页面
3. 归还图书页面
4. 超时查询页面
5. 用户管理页面

# 判断用户登录状态

Web 进行登录操作时,登录成功后,用户的 cookie 信息会存留在浏览器里,用来判断用户登录,用户操作等等

在 JS 文件夹下创建 library.js 文件
在下面写入判断用户 cookie 登录信息

$(function(){
    // 获取 cookie 判断用户登录状态
    var is_login = $.cookie("username");
    if(is_login == null || is_login == "" || is_login == ''){
        alert("请登录!");
        window.location.replace("/index.html");
    }
});

这样就可以简易的实现判断用户是否处于登录状态
如果登录了,就可以访问当前页面,如果没有登录,则跳回登录页面让用户进行登录操作

# 前端

# 显示图书数据

这个是普遍后台的 UI 界面 (至少是我认为的
8bfd2495b8ca01a70f540e6f6e377dab
library.html 里写入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="/library/css/library.css">
</head>
<body>
    <div class="main">
        <div class="manage-nav bg-primary">
            <nav class="navbar bg-primary navbar-dark">
                <ul class="navbar-nav">
                  <li class="nav-item active">
                    <a class="nav-link" href="/library/library.html">图书管理</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="#">借阅图书</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="#">归还图书</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="#">超时查询</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="#">用户管理</a>
                  </li>
                  <li class="nav-item">
                    <a class="nav-link" href="#">退出系统</a>
                  </li>
                </ul>
              </nav>
        </div>
        <div class="main-pane">
            <div class="user-nav">
                <p class="username">Admin</p>
            </div>
            <div class="info-pane">
                <div class="search-pane">
                    <button class="btn btn-success add-button">添加书籍</button>
                    <input type="text" name="search" id="search" placeholder="请输入搜索的内容">
                    <button class="btn btn-primary search-button">搜索</button>
                </div>
                <table class="table table-hover">
                    <thead>
                      <tr>
                        <th>Id</th>
                        <th>组名</th>
                        <th>书名</th>
                        <th>作者</th>
                        <th>出版社</th>
                        <th>价格(人民币)</th>
                        <th>数量(本)</th>
                        <th>ISBN号码</th>
                        <th>操作</th>
                      </tr>
                    </thead>
                    <tbody>
                    </tbody>
                  </table>
            </div>
        </div>
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/library/js/library.js"></script>
</html>

在 css 文件夹创建 library.css 文件 写入

*{
    margin:0;
    padding: 0;
    outline: none;
}
html,body,.main{
    width: 100%;
    height: 100%;
}
/* 主页面样式 */
.main{
    display: flex;
}
/* 侧边导航栏样式 */
.manage-nav{
    display: flex;
    justify-content: center;
    position: fixed;
    min-width: 256px;
    max-width: 256px;
    height: 100%;
    text-align: center;
}
/* 面板样式 */
.main-pane{
    margin-left: 256px;
    width: 100%;
    height: 100%;
}
/* 用户导航栏样式 */
.user-nav{
    display: flex;
    align-items: center;
    justify-content: flex-end;
    position: fixed;
    min-width: calc(100% - 256px);
    height: 64px;
    background-color: rgb(248, 248, 248);
}
.user-nav .username{
    padding: 0;
    margin: 0;
    margin-right: 64px;
}
/* 信息面板样式 */
.info-pane{
    margin-top: 64px;
    min-width: calc(100% - 256px);
    min-height: calc(100% - 64px);
    height: calc(100% -  64px);
    background-color: white;
}
.info-pane .search-pane{
    display: flex;
    justify-content: center;
    width: 100%;
    height: 32px;
    margin-bottom: 16px;
}
.info-pane .search-pane button{
    margin-right: 32px;
    padding: 0;
    padding-left: 16px;
    padding-right: 16px;
}
.info-pane .search-pane #search{
    width: 400px;
    padding-left: 12px;
    border: 1px solid #aaa;
    border-radius: 4px;
}

在 js 文件夹创建 library.js 文件 写入

$(function(){
    // 获取 cookie 判断用户登录状态
    var is_login = $.cookie("username");
    if(is_login == null || is_login == "" || is_login == ''){
        alert("请登录!");
        window.location.replace("/index.html");
    }
    
	// 添加假数据
    for(var i = 1; i < 51; i++){
        var text =  "<tr id='" + i + "'>" +
                    "<td>" + i + "</td>" +
                    "<td>基础书籍</td>" +
                    "<td>语文书</td>" +
                    "<td>张三</td>" +
                    "<td>无</td>" +
                    "<td>6.66</td>" +
                    "<td>6</td>" +
                    "<td>978000000006</td>" +
                    "<td><button class='btn btn-success btn-sm edit' name='" + i + "'>编辑</button><button class='btn btn-danger btn-sm delete' name='" + i + "'>删除</button></td>" +
                    "</tr>";
        $("tbody").append(text);
    }
});

至此,我们就创建好了前端的图书管理页面
d7966170adb9bcea943b9be33ae2c8ef

现在这个图书页面也只是一个静态页面,那怎么让他动起来呢?
首先我们要知道,后台页面有些内容是不会经常进行变动,比如侧边的导航栏,顶部的用户栏,经常改变的内容是信息面板这一块,为了减少代码沉余,在后台页面我将添加一个 iframe 框架动态刷新信息内容,静态更改 url 就能访问其他页面,导航栏和用户栏相对也不会进行变化。

现在把导航栏需要的页面都给创建出来
library 文件夹创建下面的文件
后台 -> library.html
图书管理 -> books.html
借阅图书 -> borrow.html
归还图书 -> return.html
超时查询 -> overtime.html
用户管理 -> users.html
961a45cfa3e6e1051099b9d56e2881fe
然后再给每一个 html 文件创建一个对应名字的 css 文件,js 文件即可

创建文件完毕后,在 library.html 文件夹添加一个 iframe 框架
替换 <div class="info-pane"> 下的代码,只用添加一个 iframe 写上 src 页面路径

<div class="info-pane">
	<iframe src="/library/books.html" frameborder="0" name="info-iframe"></iframe>
</div>

给 ** library.css** 样式表添加 iframe 的样式

.info-pane iframe{
    width: 100%;
    height: 100%;
}

现在可以把原来写在 <div class="info-pane"> 下的代码搬到 books.html 文件里

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="/library/css/books.css">
</head>
<body>
    <div class="main">
        <div class="search-pane">
            <button class="btn btn-success add-button">添加书籍</button>
            <input type="text" name="search" id="search" placeholder="请输入搜索的内容">
            <button class="btn btn-primary search-button">搜索</button>
        </div>
        <table class="table table-hover">
            <thead>
              <tr>
                <th>Id</th>
                <th>组名</th>
                <th>书名</th>
                <th>作者</th>
                <th>出版社</th>
                <th>价格(人民币)</th>
                <th>数量(本)</th>
                <th>ISBN号码</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/library/js/books.js"></script>
</html>

然后把 search-pane 的样式搬到 books.css 文件里

*{
    margin:0;
    padding: 0;
    outline: none;
}
html,body,.main{
    width: 100%;
    height: 100%;
}
/* 主页面样式 */
.main{
    display: flex;
    flex-direction: column;
    padding: 32px;
}
.search-pane{
    display: flex;
    justify-content: center;
    width: 100%;
    height: 32px;
    margin-bottom: 16px;
}
.search-pane button{
    margin-right: 32px;
    padding: 0;
    padding-left: 16px;
    padding-right: 16px;
}
.search-pane #search{
    width: 400px;
    padding-left: 12px;
    border: 1px solid #aaa;
    border-radius: 4px;
}

把之前写的假数据代码搬到 books.js

$(function(){
    // 添加假数据
    for(var i = 1; i < 51; i++){
        var text =  "<tr id='" + i + "'>" +
                    "<td>" + i + "</td>" +
                    "<td>基础书籍</td>" +
                    "<td>语文书</td>" +
                    "<td>张三</td>" +
                    "<td>无</td>" +
                    "<td>6.66</td>" +
                    "<td>6</td>" +
                    "<td>978000000006</td>" +
                    "<td><button class='btn btn-success btn-sm edit' name='" + i + "'>编辑</button><button class='btn btn-danger btn-sm delete' name='" + i + "'>删除</button></td>" +
                    "</tr>";
        $("tbody").append(text);
    }
});

现在把侧边导航栏的地址一一对应到每一个文件

<nav class="navbar bg-primary navbar-dark">
    <ul class="navbar-nav">
      <li class="nav-item active">
        <a class="nav-link" href="/library/books.html" target="info-iframe">图书管理</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/library/borrow.html" target="info-iframe">借阅图书</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/library/return.html" target="info-iframe">归还图书</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/library/overtime.html" target="info-iframe">超时查询</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/library/users.html" target="info-iframe">用户管理</a>
      </li>
      <li class="nav-item">
        <a class="nav-link exit" href="#">退出系统</a>
      </li>
    </ul>
  </nav>

给侧边导航栏添加动态激活样式,在 library.js 写入

// 侧边栏激活状态
$("ul>li").click(function (e) { 
    $("li").removeClass("active");
    $(this).addClass("active");
});

退出系统的操作

// 退出系统
$(".exit").click(function (e) { 
    var exit = $.removeCookie('username', { path: '/' });
    if(exit){
        window.location.replace("/index.html");
        alert("您已退出系统");
    }
    else{
        alert("系统错误");
    }
});

在图书管理页面显示真数据,将原先的假数据代码替换成如下代码

$(function(){
    $.ajax({
        type: "get", // 请求方式
        url: "http://192.168.1.3:8181/nav/books", // 请求地址
        dataType: "json", // 返回文件格式
        success:function(data){
            // 添加数据
            for(var i = 0; i < data.length; i++){
                var text =  "<tr id='" + data[i].id + "'>" +
                            "<td>" + data[i].id + "</td>" +
                            "<td>" + data[i].groups + "</td>" +
                            "<td>" + data[i].name + "</td>" +
                            "<td>" + data[i].author + "</td>" +
                            "<td>" + data[i].press + "</td>" +
                            "<td>" + data[i].price + "</td>" +
                            "<td>" + data[i].quantity + "</td>" +
                            "<td>" + data[i].isbn + "</td>" +
                            "<td><button class='btn btn-success btn-sm edit' name='" + data[i].id + "'>编辑</button><button class='btn btn-danger btn-sm delete' name='" + data[i].id + "'>删除</button></td>" +
                            "</tr>";
                $("tbody").append(text);
            }
        },
        error: function(data){
            alert("系统错误");
        }
    });
});

# 搜索图书

添加一个新的请求,接收返回的数据,处理一下即可,更改 library.js 的代码为

$(function(){
    // 获取图书数据
    $.ajax({
        type: "get", // 请求方式
        url: "http://localhost:8181/nav/books", // 请求地址
        dataType: "json", // 返回文件格式
        success:function(data){
            // 添加数据
            searchBook(data);
        },
        error: function(data){
            alert("系统错误");
        }
    });
    // 搜索图书
    var search_button = $('.search-button');
    var input_text = $('#search');
    $(search_button).click(function (e) { 
        e.preventDefault();        
        $.ajax({
            type: "get",
            url: "http://localhost:8181/nav/books/find",
            data: {book:input_text.val()},
            dataType: "json",
            success:function(data){
                $(".book").remove(); // 删除原来的书
                searchBook(data); // 搜索图书
            },
            error:function(data){
                alert("系统错误");
            }
        });
    });
});
// 显示图书信息函数
function searchBook(data){
    for(var i = 0; i < data.length; i++){
        var text =  "<tr id='" + data[i].id + "' class='book'>" +
                    "<td name='id'>" + data[i].id + "</td>" +
                    "<td name='groups'>" + data[i].groups + "</td>" +
                    "<td name='name'>" + data[i].name + "</td>" +
                    "<td name='author'>" + data[i].author + "</td>" +
                    "<td name='press'>" + data[i].press + "</td>" +
                    "<td name='price'>" + data[i].price + "</td>" +
                    "<td name='quantity'>" + data[i].quantity + "</td>" +
                    "<td name='isbn'>" + data[i].isbn + "</td>" +
                    "<td><button class='btn btn-success btn-sm edit' name='" + data[i].id + "' data-toggle='modal' data-target='#book-modal'>编辑</button><button class='btn btn-danger btn-sm delete' name='" + data[i].id + "' data-toggle='modal' data-target='#delete-modal'>删除</button></td>" +
                    "</tr>";
        $("tbody").append(text);
    }
}

# 添加图书

books.html 添加一个模态框,输入图书的信息

<!-- 给添加按钮写入打开模态框参数 -->
<button class="btn btn-success add-button" data-toggle="modal" data-target="#book-modal">添加书籍</button>
    <!-- 模态框 -->
    <div class="modal fade" id="book-modal">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                <h4 class="modal-title"></h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
        
                <div class="modal-body">
                    <form id="book-form" name="book-form" class="book-form">
                        <div class="form-group">
                            <label for="groups">图书组名</label>
                            <input type="text" class="form-control" placeholder="请输入图书组名" id="groups" name="groups">
                        </div>
                        <div class="form-group">
                            <label for="name">图书名称</label>
                            <input type="text" class="form-control" placeholder="请输入图书名称" id="name" name="name">
                        </div>
                        <div class="form-group">
                            <label for="author">作者名称:</label>
                            <input type="text" class="form-control" placeholder="请输入作者名称" id="author" name="author">
                        </div>
                        <div class="form-group">
                            <label for="press">出版社名称:</label>
                            <input type="text" class="form-control" placeholder="请输入出版社名称" id="press" name="press">
                        </div>
                        <div class="form-group">
                            <label for="price">价格(人民币):</label>
                            <input type="text" class="form-control" placeholder="请输入价格" id="price" name="price" maxlength="10">
                        </div>
                        <div class="form-group">
                            <label for="quantity">数量(本):</label>
                            <input type="text" class="form-control" placeholder="请输入数量" id="quantity" name="quantity" maxlength="4">
                        </div>
                        <div class="form-group">
                            <label for="isbn">ISBN号码:</label>
                            <input type="text" class="form-control" placeholder="请输入ISBN号码" id="isbn" name="isbn" maxlength="13">
                        </div>
                    </form>
                </div>
        
                <div class="modal-footer">
                    <button type="submit" class="btn btn-success operate-button"></button>
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                </div>
        
            </div>
        </div>
    </div>

library.js 添加

// 表单组件
var book_title = $('#book-modal .modal-title'); // 标题栏
var book_form = $('.book-form'); // 表单
var operate_button= $('.operate-button'); // 添加图书按钮
// 添加图书
var add_button = $('.add-button'); // 添加按钮
$(add_button).click(function (e) { 
    e.preventDefault();
    book_title.text("添加图书"); // 设置标题栏
    book_form[0].reset(); // 重置表单
    operate_button.text("添加"); // 设置按钮文本
});
// 图书操作
$(operate_button).click(function (e) { 
    e.preventDefault();
    if(book_title.text() == "添加图书"){
        addBook(book_form);
    }
});
// 检查表单函数
function checkForm(){
    var group = $('#groups');
    var name = $('#name');
    var author = $('#author');
    var press = $('#press');
    var price = $('#price');
    var quantity = $('#quantity');
    var isbn = $('#isbn');
    if(group.val() == '' || group.val() == "" || group.val() == null){
        alert("请输入图书组名");
    }
    else if(name.val() == '' || name.val() == "" || name.val() == null){
        alert("请输入图书名称");
    } 
    else if(author.val() == '' || author.val() == "" || author.val() == null){
        alert("请输入作者名称");
    } 
    else if(press.val() == '' || press.val() == "" || press.val() == null){
        alert("请输入出版社名称");
    } 
    else if(price.val() == '' || price.val() == "" || price.val() == null){
        alert("请输入价格(人民币)");
    } 
    else if(quantity.val() == '' || quantity.val() == "" || quantity.val() == null){
        alert("请输入数量(本)");
    } 
    else if(isbn.val() == '' || isbn.val() == "" || isbn.val() == null){
        alert("请输入ISBN号码");
    } 
    else if(isbn.val().length != 13){
        alert("请输入正确的ISBN号码");
    }
    else{
        return true;
    }
    
    return false;
}
// 添加图书函数
function addBook(book_form){
    // 判断表单,返回 false 不能添加,返回 true 能添加
    if(checkForm() != false){
        $.ajax({
            type: "post",
            url: "http://localhost:8181/nav/books/save",
            data: book_form.serialize(),
            dataType: "json",
            success:function(data){
                if(data.resultCode == '-1'){
                    alert("添加失败,服务器错误");
                }
                if(data.resultCode == '0'){
                    alert("添加失败,此书已存在");
                }
                if(data.resultCode == '1'){
                    alert("添加成功");
                    window.location.reload();
                }
            },
            error:function(data){
                alert("错误");
            }
        });
    }
}

# 编辑图书

books.js 添加

// 编辑图书
$(document).on('click', '.edit', function (e) { 
    e.preventDefault();
    book_title.text("编辑图书"); // 设置标题
    book_form[0].reset(); // 重置表单
    operate_button.text("编辑"); // 设置按钮文本
    operate_button.attr("name",$(this).attr("name")); // 设置 id
    getBook($(this).attr("name")); // 获取图书信息
});
// 图书操作
$(operate_button).click(function (e) { 
    e.preventDefault();
    
    if(book_title.text() == "添加图书"){
        addBook(book_form);
    }
    if(book_title.text() == "编辑图书"){
        editBook($(this).attr("name"), book_form);
    }
});
// 获取图书信息
function getBook(id){
    $.ajax({
        type: "get",
        url: "http://localhost:8181/nav/books/find/" + id,
        dataType: "json",
        success: function (data) {
            $('#groups').val(data.groups);
            $('#name').val(data.name);
            $('#author').val(data.author);
            $('#press').val(data.press);
            $('#price').val(data.price);
            $('#quantity').val(data.quantity);
            $('#isbn').val(data.isbn);
        },
        error: function (data){
            alert("错误");
        }
    });
}
// 编辑图书信息
function editBook(id, book_form){
    if(checkForm() == true){
        $.ajax({
            type: "put",
            url: "http://localhost:8181/nav/books/update/" + id,
            data: book_form.serialize(),
            dataType: "json",
            success: function (data) {
                if(data.resultCode == "-1"){
                    alert("修改失败,服务器错误");
                }
                if(data.resultCode == "0"){
                    alert("修改失败,要修改的ISBN号码已存在");
                }
                if(data.resultCode == "1"){
                    alert("修改成功");
                    window.location.reload();
                }
            },
            error: function (data) {
                alert("错误")
            }
        });
    }
}

# 删除图书

books.html 添加一个模态框

<div class="modal fade" id="delete-modal">
    <div class="modal-dialog">
        <div class="modal-content">
    
            <div class="modal-header">
            <h4 class="modal-title">删除图书</h4>
            <button type="button" class="close" data-dismiss="modal">&times;</button>
            </div>
    
            <div class="modal-body">
            <p class="tip"></p>
            </div>
    
            <div class="modal-footer">
            <button type="button" class="btn btn-danger delete-button">删除</button>
            <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
            </div>
    
        </div>
    </div>
</div>

books.js 写入

// 删除图书
$(document).on('click', '.delete', function (e) {
    e.preventDefault();
    $('.delete-button').attr("name",$(this).attr("name")); // 设置 id
    $('.tip').text("确定删除" + $('#' + $(this).attr("name") + '>td[name="name"]').text() + "?");
});
$('.delete-button').click(function (e){
    e.preventDefault();
    
    deleteBook($(this).attr("name"));
});
// 删除书本函数
function deleteBook(id){
    $.ajax({
        type: "delete",
        url: "http://localhost:8181/nav/books/delete/" + id,
        dataType: "json",
        success: function (data) {
            if(data.resultCode == "-1"){
                alert("服务器错误");
            }
            if(data.resultCode == "1"){
                alert("删除成功");
                window.location.reload();
            }
        },
        error: function (data){
            alert("错误");
        }
    });
}

# 后端

# 获取图书

在 SpringBoot 项目创建
d1be3ebc1c9fd4236ac795e1d5e80e07

类:
BooksHandler -------- 图书操作
Books ------------------- 图书实体
BooksRepository ----- 图书存储库

BooksHandler 写入

package com.ksamar.library.controller;
import com.ksamar.library.entity.Books;
import com.ksamar.library.repository.BooksRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/nav") // 请求地址
public class BooksHandler {
    @Autowired
    private BooksRepository booksRepository;
    // 搜索全部
    @GetMapping("/books") // 请求地址
    public List<Books> findAll() {
        return booksRepository.findAll();
    }
}

Books 写入

package com.ksamar.library.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Data
public class Books {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer Id;
    private String groups;
    private String name;
    private String author;
    private String press;
    private Double price;
    private Integer quantity;
    private String isbn;
}

BooksRepository 写入

package com.ksamar.library.repository;
import com.ksamar.library.entity.Books;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BooksRepository extends JpaRepository<Books,Integer> {
}

# 搜索图书

BooksHandler 里添加

// 搜索单本图书
@GetMapping("/books/find")
public List<Books> findByNameLike(String book){
    return booksRepository.findByNameLike("%" + book + "%");
}

BooksRepository 里添加

List<Books> findByNameLike(String book);

# 添加图书

BooksHandler 添加

/**
 * -1:错误,添加失败
 * 0:存在,添加失败
 * 1:添加成功
 */
@PostMapping("/books/save")
public Object save(Books books){
    List<Books> book1 = booksRepository.findByIsbn(books.getIsbn()); // 搜索书籍是否存在
    JSONObject jsonObject = new JSONObject(); // 创建一个空 JSONObject 对象
    if(book1.size() == 0){
        Books result = booksRepository.save(books); // 保存书籍
        if(result != null){
            jsonObject.put("resultCode","1");
        }
        else{
            jsonObject.put("resultCode","-1");
        }
    }
    else{
        jsonObject.put("resultCode","0");
    }
    return jsonObject;
}

BooksReposiitory 添加

List<Books> findByIsbn(String Isbn);

# 编辑图书

BooksHandler 添加

/**
 * 修改图书
 * -1:错误,修改失败
 * 0:修改后的 isbn 存在,修改失败
 * 1:修改成功
 */
@PutMapping("/books/update/{id}")
public Object update(Books books){
    JSONObject jsonObject = new JSONObject();
    List<Books> booksList = booksRepository.findByIsbn(books.getIsbn()); // 搜索 isbn 是否存在
    // 存在
    if(booksList.size() == 1){
        int oldId = books.getId(); // 获取旧 id
        int newId = booksList.get(0).getId(); // 获取新 id
        // 判断要修改的书的 id 是否和原来的书 id 一致
        if(oldId == newId){
            Books save = booksRepository.save(books);
            if(save != null){
                jsonObject.put("resultCode","1");
            }
            else{
                jsonObject.put("resultCode","-1");
            }
        }
        else{
            jsonObject.put("resultCode","0");
        }
    }
    // 不存在
    else if(booksList.size() == 0){
        booksRepository.save(books);
        jsonObject.put("resultCode","1");
    }
    // 其他情况
    else{
        jsonObject.put("resultCode","0");
    }
    return jsonObject;
}

# 删除图书

Bookshandler 写入

/**
 * 删除图书
 * -1:删除失败
 * 1:删除成功
 */
@DeleteMapping("/books/delete/{id}")
public Object deleteById(@PathVariable("id") Integer Id){
    JSONObject jsonObject = new JSONObject();
    if(booksRepository.existsById(Id)){
        booksRepository.deleteById(Id);
        jsonObject.put("resultCode","1");
    }
    else{
        jsonObject.put("resultCode","-1");
    }
    return jsonObject;
}

# 页面是如何与数据库交互的?

4bd6a01ccbcb70c525083b78ac8ffa22

# 获取图书数据

前端通过调用 Ajax 发送一个 get 请求到服务端,然后服务端返回一组 json 数据给 Web 前端,用 JavaScript 对 json 数据进行处理,然后将处理好的数据展示到 Web 前端

# 搜托图书

与上面方法类似,多添加了一个 book 的参数,作为查询的书名,后端接收到请求去查询数据库有没有该本书,有则返回书本信息,没有则返回空

# 添加图书

前端发送一个带表单信息 post 请求到服务端,然后由服务器检测这本书是否存在,如果存在则返回添加失败的 Code,如果不存在则发返回添加成功的 Code,如果服务器添加书本不成功则返回异常的 Code

# 编辑图书

前端先发送一个请求获取该本书的信息 ,然后修改数据后再向服务器发送修改请求,服务器检测 id 和 isbn 号码,如果 isbn 没有变动可以直接修改,如果修改的 isbn 在数据库里没有则可以直接修改,如果修改新的 isbn 在数据库中存在,则判断原来的 id 与数据库搜索出来的 isbn 图书 id 是否一致,不一致则修改失败

# 删除图书

前端发送一个带 id 的删除请求,服务器接受删除请求,判断 id 是否在数据库中,如果存在就删除,不存在就不删除

# 五、借阅图书页面

# 前端

borrow.html 里写入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="/library/css/borrow.css">
</head>
<body>
    <div class="main">
        <h2>借阅图书</h2>
        <div class="search-pane">
            <input type="text" name="search-input" id="search-input" class="search-input" maxlength="13" placeholder="请搜索要借阅的图书ISBN号码">
            <input type="submit" value="搜索" name="search-button" id="search-button" class="search-button">
        </div>
        <div class="info-pane">
            <div class="book">
                <h3>图书信息</h3>
                <p>图书名称:<span class="book-name"></span></p>
                <p>作者名称: <span class="book-author"></span></p>
                <p>出版社名称:<span class="book-press"></span></p>
                <p>ISBN号码: <span class="book-isbn"></span></p>
                <p>库存(本): <span class="book-quantity"></span></p>
            </div>
            <div class="user">
                <h3>用户信息</h3>
                <input type="text" name="username" id="username" class="username" placeholder="借阅人名字">
                <input type="text" name="id-card" id="id-card" class="id-card" placeholder="借阅人卡号">
                <input type="text" name="phone" id="phone" class="phone" placeholder="借阅人手机号">
                <input type="button" name="borrow-button" id="borrow-button" class="btn btn-primary borrow-button" value="借阅图书"></button>
            </div>
        </div>
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/library/js/config.js"></script>
<script src="/library/js/borrow.js"></script>
</html>

borrow.css 写入

* {
    margin: 0;
    padding: 0;
    outline: none;
}
html,
body,
.main {
    width: 100%;
    height: 100%;
}
/* 主页面样式 */
.main {
    display: flex;
    flex-direction: column;
    padding: 32px;
    justify-content: center;
    align-items: center;
}
/* 搜索栏样式 */
.search-pane{
    display: flex;
    margin-bottom: 32px;
}
.search-pane .search-input{
    width: 480px;
    height: 38px;
    border-radius: 8px 0px 0px 8px;
    border: 2px solid #007BFF;
    padding-left: 12px;
}
.search-pane .search-button{
    width: 70px;
    border: transparent;
    border-radius: 0px 8px 8px 0px;
    background-color: #007BFF;
    color: white;
}
/* 信息栏样式 */
.info-pane{
    display: flex;
    width: 550px;
}
.info-pane div{
    display: flex;
    width: 50%;
    flex-direction: column;
}
.info-pane .user input{
    margin-top: 12px;
    padding: 4px;
    border-radius: 4px;
}
.info-pane .user input[type=text]{
    border: 1px solid rgb(77, 77, 77);
}

borrow.js 写入

$(function(){
    
    // 搜索图书
    var search_button = $(".search-button");
    $(search_button).click(function (e) { 
        e.preventDefault();
    
        var isbn = $(".search-input").val();
        if(isbn != '' && isbn != "" && isbn != null){
            if(isbn.length == 13){
                $.ajax({
                    type: "get",
                    url: ip + "/nav/books/find/isbn/" + isbn,
                    dataType: "json",
                    success:function(data){
                        if(!jQuery.isEmptyObject(data)){
                            $('.book-name').text(data[0].name);
                            $('.book-author').text(data[0].author);
                            $('.book-press').text(data[0].press);
                            $('.book-isbn').text(data[0].isbn);
                            $('.book-quantity').text(data[0].quantity);
                        }
                        else{
                            alert("查无此书");
                        }
                    },
                    error:function(data){
                        alert("系统错误");
                    }
                });
            }
            else{
                alert("请输入正确的ISBN号码");
            }
        }
        else{
            alert("请输入ISBN号码");
        }
    });
    // 借阅图书
    var borrow_button = $('.borrow-button');
    $(borrow_button).click(function (e) { 
        e.preventDefault();
        
        var isbn = $('.book-isbn').text();
        var username = $('.username').val();
        var id_card = $('.id-card').val();
        var phone = $('.phone').val();
        
        if(isbn != '' && isbn != "" && isbn != null){
            if(username != '' && username != "" && username != null){
                if(id_card != '' && id_card != "" && id_card != null){
                    if(phone != '' && phone != "" && phone != null){
                        $.ajax({
                            type: "post",
                            url: ip + "/nav/books/borrow",
                            data: {isbn:isbn,username:username,id_card:id_card,phone:phone},
                            dataType: "json",
                            success: function (data) {
                                console.log(data);
                                if(data.resultCode == "-1"){
                                    alert("借阅失败,系统错误");
                                }
                                if(data.resultCode == "0"){
                                    alert("借阅失败,库存不足");
                                }
                                if(data.resultCode == "1"){
                                    alert("借阅成功");
                                    window.location.reload();
                                }
                            },
                            error: function (data){
                                alert("系统错误");
                            }
                        });
                    }
                    else{
                        alert("请输入借阅人手机");
                    }
                }
                else{
                    alert("请输入借阅人卡号");
                }
            }
            else{
                alert("请输入借阅人名字");
            }
        }
        else{
            alert("请先选择书籍!");
        }
    });
});

# 后端

BookHandler 里写入

// 搜索单本图书 ISBN
@GetMapping("/books/find/isbn/{isbn}")
public List<Books> findByIsbn(@PathVariable("isbn") String isbn) {
    return booksRepository.findByIsbn(isbn);
}

新建 Borrow 类,BorrowRepository 接口,BorrowHandler 类,分别写入
Borrow

package com.ksamar.library.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.sql.Date;
@Entity
@Data
public class Borrow {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer Id;
    private String name;
    private String isbn;
    private String username;
    private String id_card;
    private String phone;
    private Date time;
    private Date r_time;
}

BorrowRepository

package com.ksamar.library.repository;
import com.ksamar.library.entity.Borrow;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BorrowRepository extends JpaRepository<Borrow,Integer> {
}

BorrowHandler

package com.ksamar.library.controller;
import com.alibaba.fastjson.JSONObject;
import com.ksamar.library.entity.Books;
import com.ksamar.library.entity.Borrow;
import com.ksamar.library.entity.Users;
import com.ksamar.library.repository.BooksRepository;
import com.ksamar.library.repository.BorrowRepository;
import com.ksamar.library.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Calendar;
import java.util.List;
@RestController
@RequestMapping("/nav") // 请求地址
public class BorrowHandler {
    @Autowired
    private BooksRepository booksRepository;
    @Autowired
    private BorrowRepository borrowRepository;
    @Autowired
    private UsersRepository usersRepository;
/**
 * 借阅图书
 * -1: 系统错误
 *  0: 库存不足
 *  1: 借阅成功
 */
@PostMapping("/books/borrow")
public Object bookBorrow(String isbn, String username, String id_card, String phone){
    JSONObject jsonObject = new JSONObject();
    if(!isbn.equals("") && !username.equals("") && !id_card.equals("") && !phone.equals("")){
        List<Books> booksList = booksRepository.findByIsbn(isbn); // 搜索图书
        // 判断有没有书
        if(booksList.size() != 0){
            Books books = booksList.get(0);
            if(books.getQuantity() - 1 >= 0){
                books.setQuantity(books.getQuantity() - 1);
                Users users = usersRepository.findByPhone(phone); // 搜索用户
                // 判断有没有用户 用户信息是否正确
                if(users != null && users.getUsername().equals(username) && users.getId_card().equals(id_card) && users.getPhone().equals(phone)){
                    TimeZone.setDefault(TimeZone.getTimeZone("GMT")); // 设置时区
                    Calendar calendar = Calendar.getInstance(); // 获取时间
                    Date nowDate; // 借阅时间
                    Date returnDate; // 归还时间
                    nowDate = calendar.getTime(); // 借阅时间
                    calendar.add(Calendar.DATE, 7); // 添加时间
                    returnDate = calendar.getTime(); // 归还时间
                    Borrow borrow = new Borrow();
                    borrow.setName(books.getName()); // 图书名称
                    borrow.setIsbn(books.getIsbn()); //ISBN 号码
                    borrow.setUsername(users.getUsername()); // 借阅人名字
                    borrow.setId_card(users.getId_card()); // 借阅人 ID
                    borrow.setPhone(users.getPhone()); // 借阅人手机号
                    borrow.setTime(nowDate); // 设置借阅图书时间
                    borrow.setR_time(returnDate); // 添加归还书本时间
                    Borrow save = borrowRepository.save(borrow); // 保存数据
                    if(save != null){
                        jsonObject.put("resultCode","1");
                    }
                    else{
                        jsonObject.put("resultCode","-1");
                    }
                }
                else{
                    jsonObject.put("resultCode","-1");
                }
            }
            else{
                jsonObject.put("resultCode","0");
            }
        }
        else{
            jsonObject.put("resultCode","0");
        }
    }
    else{
        jsonObject.put("resultCode","-1");
    }
    return jsonObject;
}

# 借阅图书是如何实现的?

前端先发送一个搜索图书的请求,查询这本书是否存在,然后显示图书的信息,然后再填写好借阅人的信息,后端判断借阅人信息是否存在,若都存在,借阅图书成功

# 六、归还图书页面

# 前端

return.html 里写入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="/library/css/return.css">
</head>
<body>
    <div class="main">
        <div class="search-pane">
            <input type="text" name="search" id="search" placeholder="请输入搜索的内容">
            <button class="btn btn-primary search-button">搜索</button>
        </div>
        <table class="table table-hover">
            <thead>
              <tr>
                <th>Id</th>
                <th>书名</th>
                <th>ISBN号码</th>
                <th>借阅人名字</th>
                <th>借阅人卡号</th>
                <th>借阅人手机号</th>
                <th>借阅时间</th>
                <th>归还时间</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>
    <!-- 模态框 -->
    <div class="modal fade" id="return-modal">
        <div class="modal-dialog">
            <div class="modal-content">
        
                <div class="modal-header">
                <h4 class="modal-title">归还图书</h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
        
                <div class="modal-body">
                <p class="tip"></p>
                </div>
        
                <div class="modal-footer">
                <button type="button" class="btn btn-danger return-button">归还</button>
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                </div>
        
            </div>
        </div>
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/library//js/config.js"></script>
<script src="/library/js/return.js"></script>
</html>

return.css 里写入

* {
    margin: 0;
    padding: 0;
    outline: none;
}
html,
body,
.main {
    width: 100%;
    height: 100%;
}
/* 主页面样式 */
.main {
    display: flex;
    flex-direction: column;
    padding: 32px;
}
.search-pane {
    display: flex;
    justify-content: center;
    width: 100%;
    height: 32px;
    margin-bottom: 16px;
}
.search-pane button {
    margin-right: 32px;
    padding: 0;
    padding-left: 16px;
    padding-right: 16px;
}
.search-pane #search {
    width: 400px;
    padding-left: 12px;
    border: 1px solid #aaa;
    border-radius: 4px;
}

return.js 里写入

$(function(){
    // 获取图书数据
    $.ajax({
        type: "get", // 请求方式
        url: ip + "/nav/books/borrow/find", // 请求地址
        dataType: "json", // 返回文件格式
        success:function(data){
            // 添加数据
            searchBook(data);
        },
        error: function(data){
            alert("系统错误");
        }
    });
    // 搜索图书
    var search_button = $('.search-button');
    var isbn = $('#search');
    $(search_button).click(function (e) { 
        e.preventDefault();        
        $.ajax({
            type: "get",
            url: ip + "/nav/books/borrow/find/" + isbn.val(),
            dataType: "json",
            success:function(data){
                $(".book").remove(); // 删除原来的书
                searchBook(data); // 搜索图书
            },
            error:function(data){
                alert("系统错误");
            }
        });
    });
    // 归还图书
    $(document).on('click', '.return', function (e) {
        e.preventDefault();
        $('.return-button').attr("name",$(this).attr("name")); // 设置 id
        $('.tip').text("确定归还 " + $('#' + $(this).attr("name") + '>td[name="username"]').text() + " 的 " + $('#' + $(this).attr("name") + '>td[name="name"]').text() + " 书吗?");
    });
    $('.return-button').click(function (e){
        e.preventDefault();
        
        returnBook($(this).attr("name"));
    });
});
// 显示图书信息函数
function searchBook(data){
    for(var i = 0; i < data.length; i++){
        var text =  "<tr id='" + data[i].id + "' class='book'>" +
                    "<td name='id'>" + data[i].id + "</td>" +
                    "<td name='name'>" + data[i].name + "</td>" +
                    "<td name='isbn'>" + data[i].isbn + "</td>" +
                    "<td name='username'>" + data[i].username + "</td>" +
                    "<td name='id_card'>" + data[i].id_card + "</td>" +
                    "<td name='phone'>" + data[i].phone + "</td>" +
                    "<td name='time'>" + data[i].time.substr(0,10) + "</td>" +
                    "<td name='r_time'>" + data[i].r_time.substr(0,10) + "</td>" +
                    "<td><button class='btn btn-warning btn-sm return' name='" + data[i].id + "' data-toggle='modal' data-target='#return-modal'>归还</button>" +
                    "</tr>";
        $("tbody").append(text);
    }
}
// 归还书本函数
function returnBook(id){
    $.ajax({
        type: "delete",
        url: ip + "/nav/books/borrow/return/" + id,
        dataType: "json",
        success: function (data) {
            if(data.resultCode == "-1"){
                alert("服务器错误");
            }
            if(data.resultCode == "0"){
                alert("归还失败");
            }
            if(data.resultCode == "1"){
                alert("归还成功");
                window.location.reload();
            }
        },
        error: function (data){
            alert("错误");
        }
    });
}

# 后端

BorrowHandler 里写入

// 搜索图书信息
@GetMapping("/books/borrow/find")
public List<Borrow> findAll() {
    return borrowRepository.findAll();
}
// 搜索图书信息 ISBN
@GetMapping("/books/borrow/find/{isbn}")
public List<Borrow> findByIsbn(@PathVariable("isbn") String isbn){
    return borrowRepository.findByIsbn(isbn);
}
    
/**
 * 归还图书
 * -1: 系统错误
 *  0: 归还失败
 *  1: 归还成功
 */
@DeleteMapping("/books/borrow/return/{id}")
public Object bookReturn(@PathVariable("id") int Id){
    JSONObject jsonObject = new JSONObject();;
    Borrow borrow = borrowRepository.getById(Id); // 获取借阅信息
    List<Books> booksList = booksRepository.findByIsbn(borrow.getIsbn()); // 获取图书
    if(booksList.size() != 0){
        // 删除信息
        if(borrowRepository.existsById(Id)){
            borrowRepository.deleteById(Id);
            Books books = booksList.get(0); // 获取图书信息
            books.setQuantity(books.getQuantity() + 1); // 图书数量加一
            booksRepository.save(books);
            jsonObject.put("resultCode","1");
        }
        else{
            jsonObject.put("resultCode","0");
        }
    }
    else{
        jsonObject.put("resultCode","-1");
    }
    return jsonObject;
}

# 归还图书是如何实现的?

获取借阅图书表的信息,点击按钮发送归还请求,后端搜索数据 ID,再用搜索出的 ISBN 号码再搜索图书表的书,归还成功后该书本数量加一

# 七、超时查询页面

# 前端

overtime.html 写入

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图书管理系统</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
    <link rel="stylesheet" href="/library/css/overtime.css">
</head>
<body>
    <div class="main">
        <div class="search-pane">
            <input type="text" name="search" id="search" placeholder="请输入搜索的内容">
            <button class="btn btn-primary search-button">搜索</button>
        </div>
        <table class="table table-hover">
            <thead>
              <tr>
                <th>Id</th>
                <th>书名</th>
                <th>ISBN号码</th>
                <th>借阅人名字</th>
                <th>借阅人卡号</th>
                <th>借阅人手机号</th>
                <th>借阅时间</th>
                <th>归还时间</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
            </tbody>
        </table>
    </div>
    <!-- 模态框 -->
    <div class="modal fade" id="return-modal">
        <div class="modal-dialog">
            <div class="modal-content">
        
                <div class="modal-header">
                <h4 class="modal-title">归还图书</h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
        
                <div class="modal-body">
                <p class="tip"></p>
                </div>
        
                <div class="modal-footer">
                <button type="button" class="btn btn-danger return-button">归还</button>
                <button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
                </div>
        
            </div>
        </div>
    </div>
</body>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script src="/library//js/config.js"></script>
<script src="/library/js/overtime.js"></script>
</html>

overtime.css 写入

* {
    margin: 0;
    padding: 0;
    outline: none;
}
html,
body,
.main {
    width: 100%;
    height: 100%;
}
/* 主页面样式 */
.main {
    display: flex;
    flex-direction: column;
    padding: 32px;
}
.search-pane {
    display: flex;
    justify-content: center;
    width: 100%;
    height: 32px;
    margin-bottom: 16px;
}
.search-pane button {
    margin-right: 32px;
    padding: 0;
    padding-left: 16px;
    padding-right: 16px;
}
.search-pane #search {
    width: 400px;
    padding-left: 12px;
    border: 1px solid #aaa;
    border-radius: 4px;
}

overtime.js 写入

$(function(){
    // 获取图书数据
    $.ajax({
        type: "get", // 请求方式
        url: ip + "/nav/books/overtime/find/0", // 请求地址
        dataType: "json", // 返回文件格式
        success:function(data){
            // 添加数据
            searchBook(data);
        },
        error: function(data){
            alert("系统错误");
        }
    });
    // 搜索图书
    var search_button = $('.search-button');
    var isbn = $('#search');
    $(search_button).click(function (e) { 
        e.preventDefault();        
        $.ajax({
            type: "get",
            url: ip + "/nav/books/overtime/find/" + isbn.val(),
            dataType: "json",
            success:function(data){
                $(".book").remove(); // 删除原来的书
                searchBook(data); // 搜索图书
            },
            error:function(data){
                alert("系统错误");
            }
        });
    });
    // 归还图书
    $(document).on('click', '.return', function (e) {
        e.preventDefault();
        $('.return-button').attr("name",$(this).attr("name")); // 设置 id
        $('.tip').text("确定归还 " + $('#' + $(this).attr("name") + '>td[name="username"]').text() + " 的 " + $('#' + $(this).attr("name") + '>td[name="name"]').text() + " 书吗?");
    });
    $('.return-button').click(function (e){
        e.preventDefault();
        
        returnBook($(this).attr("name"));
    });
});
// 显示图书信息函数
function searchBook(data){
    for(var i = 0; i < data.length; i++){
        var text =  "<tr id='" + data[i].id + "' class='book'>" +
                    "<td name='id'>" + data[i].id + "</td>" +
                    "<td name='name'>" + data[i].name + "</td>" +
                    "<td name='isbn'>" + data[i].isbn + "</td>" +
                    "<td name='username'>" + data[i].username + "</td>" +
                    "<td name='id_card'>" + data[i].id_card + "</td>" +
                    "<td name='phone'>" + data[i].phone + "</td>" +
                    "<td name='time'>" + data[i].time.substr(0,10) + "</td>" +
                    "<td name='r_time'>" + data[i].r_time.substr(0,10) + "</td>" +
                    "<td><button class='btn btn-warning btn-sm return' name='" + data[i].id + "' data-toggle='modal' data-target='#return-modal'>归还</button>" +
                    "</tr>";
        $("tbody").append(text);
    }
}
// 归还书本函数
function returnBook(id){
    $.ajax({
        type: "delete",
        url: ip + "/nav/books/borrow/return/" + id,
        dataType: "json",
        success: function (data) {
            if(data.resultCode == "-1"){
                alert("服务器错误");
            }
            if(data.resultCode == "0"){
                alert("归还失败");
            }
            if(data.resultCode == "1"){
                alert("归还成功");
                window.location.reload();
            }
        },
        error: function (data){
            alert("错误");
        }
    });
}

# 后端

BorrowHandler 写入

// 搜索超时信息
@GetMapping("/books/overtime/find/{isbn}")
public List<Borrow> findOverTime(@PathVariable("isbn") String isbn) {
    List<Borrow> oldBorrowList;
    List<Borrow> borrowList = new ArrayList<>();
    TimeZone.setDefault(TimeZone.getTimeZone("GMT")); // 设置时区
    if(isbn.equals("0")){
        oldBorrowList = borrowRepository.findAll(); // 获取数据
    }
    else{
        oldBorrowList = borrowRepository.findByIsbn(isbn);
    }
    // 判断表里有没有数据
    if(oldBorrowList.size() != 0){
        // 循环读取数据
        for (Borrow borrow : oldBorrowList) {
            Calendar calendar = Calendar.getInstance();
            if(calendar.getTime().after(borrow.getR_time())){
                borrowList.add(borrow); // 添加超时归还的数据
            }
        }
    }
    return borrowList;
}

# 超时查询是如何实现的?

前端发送搜索请求,后端把表里的数据处理,超过归还时间的书就放到一个列表里然后返回,前端处理数据显示即可

# 八、用户管理页面

与图书管理页面是一模一样的,这里就不放出来了,在源码里有,想自己写的也可以试试

# 九、退出登录

# 前端

library.js 写入

// 退出系统
$(".exit").click(function (e) { 
    var exit = $.removeCookie('username', { path: '/' });
    if(exit){
        window.location.replace("/index.html");
        alert("您已退出系统");
    }
    else{
        alert("系统错误");
    }
});

# 用户的退出是如何实现的?

前端把 Cookie 删掉就退出了

# 总结与项目源码地址

源码下载地址

GitHub: Github

Gitee: Gitee

# Tooltip 小贴士

1.SpringBoot 热更新
Spring Boot 热更新 / 热部署
2.CSS3 display: flex 使用指南
CSS3 display: felx 使用指南

此文章已被阅读次数:正在加载...更新于

祝您开心每一天

筱原空 微信支付

微信支付

筱原空 支付宝

支付宝