图书管理系统(持久化存储数据以及增添新功能)

目录

一、数据库表设计

二、引入MyBatis 和MySQL 驱动依赖

三、配置数据库 & 日志

四、Model创建

五、枚举类 + 常量类用户登录

六、用户登录

七、添加图书

八、图书列表

九、修改图书

十、删除图书

十一、批量删除

十二、强制登录

十三、前端代码

(1)login.html

(2)book_add.html

(3)book_list.html

(4)book.update.html

十四、测试

(1)登录界面

(2)添加图书

(3)翻页,图书列表

(4)修改图书

(5)删除图书

(6)批量删除图书


        之前写的内容地址:综合性练习(后端代码练习4)——图书管理系统-CSDN博客 ,项目的gitte地址:https://gitee.com/cool_tao6/studying-java-ee-advanced/tree/master/Books_Management_System

一、数据库表设计

        数据库表是应用程序开发中的一个重要环节,数据库表的设计往往会决定我们的应用需求是否能顺利实现,甚至决定我们的实现方式。如何设计表以及这些表有哪些字段,这些表存在哪些关系 也是非常重要的。

        数据库表设计是依据业务需求来设计的。如何设计出优秀的数据库表,与经验有很大关系。

        数据库表通常分为两种:实体表 和 关系表。

        分析我们的需求,图书管理系统相对来说比较简单,只有两个实体:用户和图书,并且用户和图书之间没有关联关系。

        表的具体字段设计,也与需求有关。

        用户表有用户名和密码即可(复杂的业务可能还涉及昵称,年龄等资料)

        图书表有哪些字段,也是参考需求页面(通常不是一个页面决定的,而是要对整个系统进行全面分析观察后定的)。

        创建数据库 book_test,SQL如下:

-- 创建数据库
DROP DATABASE IF EXISTS book_test;CREATE DATABASE book_test DEFAULT CHARACTER SET utf8mb4;-- 用户表
DROP TABLE IF EXISTS user_info;
CREATE TABLE user_info (`id` INT NOT NULL AUTO_INCREMENT,`user_name` VARCHAR ( 128 ) NOT NULL,`password` VARCHAR ( 128 ) NOT NULL,`delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` ),
UNIQUE INDEX `user_name_UNIQUE` ( `user_name` ASC )) ENGINE = INNODB DEFAULT CHARACTER 
SET = utf8mb4 COMMENT = '用户表';-- 图书表
DROP TABLE IF EXISTS book_info;
CREATE TABLE `book_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`book_name` VARCHAR ( 127 ) NOT NULL,`author` VARCHAR ( 127 ) NOT NULL,`count` INT ( 11 ) NOT NULL,`price` DECIMAL (7,2 ) NOT NULL,`publish` VARCHAR ( 256 ) NOT NULL,`status` TINYINT ( 4 ) DEFAULT 1 COMMENT '0-无效, 1-正常, 2-不允许借阅',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),
PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;-- 初始化数据
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "admin", "admin" );
INSERT INTO user_info ( user_name, PASSWORD ) VALUES ( "zhangsan", "123456" );-- 初始化图书数据
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('活着', '余华', 29, 22.00, '北京文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('平凡的世界', '路遥', 5, 98.56, '北京十月文艺出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('三体', '刘慈欣', 9, 102.67, '重庆出版社');
INSERT INTO `book_info` (book_name,author,count, price, publish) VALUES ('金字塔原理', '麦肯锡', 16, 178.00, '民主与建设出版社');

二、引入MyBatis 和MySQL 驱动依赖

        修改pom.xml文件,内容如下:

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version>
</dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope>
</dependency>

        或者使用Edit Starters添加,如图:


三、配置数据库 & 日志

        在properties.yml下添加如下内容:

spring.application.name:Books_Management_System# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: 1234driver-class-name: com.mysql.cj.jdbc.Drivermybatis:configuration: #配置驼峰自动转换log-impl: org.apache.ibatis.logging.stdout.StdOutImplmap-underscore-to-camel-case: true #打印sql语句mapper-locations: classpath:mapper/*Mapper.xml

四、Model创建

        BookInfo类 实体书类:

@Data
public class BookInfo {private Integer id;private String bookName;private String author;private Integer count;private BigDecimal price;private String publish;private Integer status;//1-可借阅   2-不可借阅private String statusCN;private Date createTime;private Date update_time;
}

        UserInfo类 用户类:

@Data
public class UserInfo {private Integer id;private String userName;private String password;private Integer deleteFlag;private Date createTime;private Date updateTime;
}

        PageRequest类 查询图书列表 前端发来的请求类:

import lombok.Data;@Data
public class PageRequest {private Integer pageNum = 1;private Integer pageSize = 10;private Integer offset;public Integer getOffset() {return (pageNum - 1) * pageSize;}
}

        PageResult类 查询图书列表 返回的结果类:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;
@AllArgsConstructor//全参构造函数
@NoArgsConstructor//无参构造函数
@Data
public class PageResult <T>{private List<T> records;private Integer count;private PageRequest pageRequest;
}

        Result类 查询图书列表 返回的结果类(对的PageResult 进行扩展):

import com.example.books_management_system.enums.ResultStatus;
import lombok.Data;@Data
public class Result <T> {private ResultStatus code; //业务码, 200-成功, -2-失败, -1-失败未登录private String errMsg; //错误信息,如果业务成功,errMsg为空private T data;public static <T> Result success(T data) {Result<PageResult<BookInfo>> result = new Result<>();result.setCode(ResultStatus.SUCCESS);result.setData((PageResult<BookInfo>) data);return result;}public static <T> Result nologin() {Result<PageResult<BookInfo>> result = new Result<>();result.setCode(ResultStatus.NOLOGIN);result.setErrMsg("用户未登录");result.setData(null);return result;}public static <T> Result fail(String msg) {Result<PageResult<BookInfo>> result = new Result<>();result.setCode(ResultStatus.FAIL);result.setErrMsg(msg);return result;}public static <T> Result fail(ResultStatus resultStatus, String msg) {Result<PageResult<BookInfo>> result = new Result<>();result.setCode(resultStatus);result.setErrMsg(msg);return result;}
}

五、枚举类 + 常量类用户登录

        BookStatus枚举类 枚举图书的状态(删除、可借阅、不可借阅):

public enum BookStatus {DELETE(0, "删除"),NORMAL(1, "可借阅"),FORBIDDEN(2, "不可借阅");private Integer code;private String desc;BookStatus(Integer code, String desc) {this.code = code;this.desc = desc;}/*** 根据code,返回描述信息*  其余两种写法:* //    public static String getDescByCode2(Integer code) {* //        switch (code) {* //            case 0: return DELETE.getDesc();* //            case 1: return NORMAL.getDesc();* //            case 2:* //            default:* //                return FORBIDDEN.getDesc();* //        }* //    }* //    static Map<Integer, String> map = new HashMap<>();* //    public static String getDescByCode3(Integer code) {* //        return map.get(code);* //    }*/public static BookStatus getDescByCode(Integer code) {switch (code) {case 0: return DELETE;case 1: return NORMAL;case 2:default:return FORBIDDEN;}}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}
}

        ResultStatus枚举类 枚举返回结果的code(SUCCESS、FAIL、NOLOGIN):

public enum ResultStatus {SUCCESS(200),FAIL(-1),NOLOGIN(-2),;private int code;ResultStatus(int code) {this.code = code;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}
}

        Constant常量类 session的常量值:

public class Constant {public static final String USER_SESSION_KEY = "user_session_key";
}

六、用户登录

        UserController类:

@RestController
@RequestMapping("/user")
public class UserController {@Autowiredprivate UserService userService;@RequestMapping("/login")public String login(String userName, String password, HttpSession session) {//1、校验参数//2、校验密码是否正确//3、返回响应结果System.out.println(userName + " " + password);if(!StringUtils.hasLength(userName) || !StringUtils.hasLength(password)) {return "用户名或者密码为空";}UserInfo userInfo = userService.getUserInfoByName(userName);if(userInfo == null) {return "用户不存在";}if(!password.equals(userInfo.getPassword())) {return "密码错误";}//根据用户名称,去数据库查询用户信息,如果未查询到,说明用户不存在//如果查询到用户信息,比对密码是否正确//正确的情况session.setAttribute(Constant.USER_SESSION_KEY, userInfo);return "";}
}

        UserService类:

@Service
public class UserService {@Autowiredprivate UserInfoMapper userInfoMapper;public UserInfo getUserInfoByName(String userName) {return userInfoMapper.getUserInfoByName(userName);}
}

        UserInfoMapper类:

@Mapper
public interface UserInfoMapper {@Select("select * from user_info where user_name = #{name} and delete_flag = 0")UserInfo getUserInfoByName(String name);
}

七、添加图书

        BookController类:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 添加图书*/@RequestMapping("/addBook")public String addBook(BookInfo bookInfo) {//校验参数log.info("添加图书,接收到参数:bookInfo {}", bookInfo);if(!StringUtils.hasLength(bookInfo.getBookName())|| !StringUtils.hasLength(bookInfo.getAuthor())|| bookInfo.getCount() == null|| bookInfo.getPrice() == null|| !StringUtils.hasLength(bookInfo.getPublish())|| bookInfo.getStatus() == null) {return "输入参数不合法";}//添加图书try {Integer result = bookService.insertBook(bookInfo);if(result > 0) {//添加成功return "";}}catch (Exception e) {log.error("添加图书异常, e: " +e);}return "添加失败";}
}

        BookService类:

@Slf4j
@Service
public class BookService {@AutowiredBookMapper bookMapper;public Integer insertBook(BookInfo bookInfo) {return bookMapper.insertBook(bookInfo);}
}

         BookMapper类:

@Mapper
public interface BookMapper {/*** 插入图书*/@Insert("insert into book_info(book_name, author, count, price, publish, `status`) " +"values (#{bookName}, #{author}, #{count}, #{price}, #{publish}, #{status})")Integer insertBook(BookInfo bookInfo);
}

八、图书列表

        BookController类:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 查询图书列表*/@RequestMapping("/getBookListByPage")public Result<PageResult<BookInfo>> getBookListByPage(PageRequest pageRequest, HttpSession session) {log.info("查询图书的列表, 请求参数pageRequest: {}", pageRequest);//从session中获取用户信息//如果用户信息为空, 说明用户未登录UserInfo loginUserInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION_KEY);if(loginUserInfo == null || loginUserInfo.getId() < 0) {return Result.nologin();}//参数校验if(pageRequest.getPageNum() == null) {//返回默认第一页,如果pageSize也没设置,则会使用默认的10pageRequest.setPageNum(1);}PageResult<BookInfo> bookList = bookService.getBookListByPage(pageRequest);return Result.success(bookList);}
}

        BookService类:

@Slf4j
@Service
public class BookService {@AutowiredBookMapper bookMapper;public PageResult<BookInfo> getBookListByPage(PageRequest pageRequest) {//1、获取总记录数Integer count = bookMapper.count();//2、获取当前页的记录List<BookInfo> bookInfos = bookMapper.queryBookByPage(pageRequest.getOffset(), pageRequest.getPageSize());//3、处理状态for(BookInfo bookInfo : bookInfos) {bookInfo.setStatusCN(BookStatus.getDescByCode(bookInfo.getStatus()).getDesc());//得到的是枚举类型//            bookInfo.setStatusCN(BookStatus.getDescByCode3(bookInfo.getStatus()));//hash映射
//            bookInfo.setStatusCN(BookStatus.getDescByCode2(bookInfo.getStatus()));//得到的是字符串//            if(bookInfo.getStatus() == 2) {
//                bookInfo.setStatusCN("不可借阅");
//            } else {
//                bookInfo.setStatusCN("可借阅");
//            }}return new PageResult<BookInfo>(bookInfos, count, pageRequest);}
}

         BookMapper类:

@Mapper
public interface BookMapper {/*** 查询列表*/@Select("select * from  book_info where status != 0 order by id desc limit #{offset}, #{limit}")List<BookInfo> queryBookByPage(Integer offset, Integer limit);
}

九、修改图书

        BookController类:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 更新图书*/@RequestMapping("/updateBook")public String updateBook(BookInfo bookInfo) {log.info("更新图书, bookInfo: {}", bookInfo);try {Integer result = bookService.updateBookById(bookInfo);if(result > 0) {return "";}return "内部错误, 请练习管理员11111";}catch (Exception e) {log.error("更新图书失败, e: " + e);return "内部错误, 请练习管理员";}}/*** 查询图书信息* @param bookId* @return*/@RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId) {log.info("根据ID查询图书信息, id:" + bookId);return bookService.queryBookById(bookId);}}

        BookService类:

@Slf4j
@Service
public class BookService {@AutowiredBookMapper bookMapper;public Integer updateBookById(BookInfo bookInfo) {log.info("更新图书, bookInfo: {}", bookInfo);return bookMapper.updateBookById(bookInfo);}/*** 根据ID查询图书信息* @param bookId* @return*/public BookInfo queryBookById(Integer bookId) {BookInfo bookInfo = bookMapper.queryBookById(bookId);bookInfo.setStatusCN(BookStatus.getDescByCode(bookInfo.getStatus()).getDesc());return bookInfo;}
}

        BookMapper类:

@Mapper
public interface BookMapper {/*** 更新图书*/Integer updateBookById(BookInfo bookInfo);/*** 查询图书信息*/@Select("select * from book_info where id = #{bookId}")BookInfo queryBookById(Integer bookId);
}

        更新图书的xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.books_management_system.mapper.BookMapper"><update id="updateBookById">update book_info<set><if test="bookName != null">book_name = #{bookName},</if><if test="author != null">author = #{author},</if><if test="count != null">count = #{count},</if><if test="price != null" >price = #{price},</if><if test="publish != null">publish = #{publish},</if><if test="status != null">status = #{status}</if></set>where id = #{id}</update></mapper>

十、删除图书

        BookController类:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 删除图书*/@RequestMapping("/deleteBook")public String deleteBook(Integer bookId) {log.info("删除图书, bookId: {}", bookId);try{Integer result =  bookService.deleteBookById(bookId);if(result > 0) {return "";}return "内部错误, 请练习管理员11111";}catch (Exception e) {log.error("删除图书失败, e: " + e);return "内部错误, 请练习管理员";}}
}

        BookService类:

@Slf4j
@Service
public class BookService {@AutowiredBookMapper bookMapper;/*** 删除图书*/public Integer deleteBookById(Integer bookId) {log.info("删除图书, bookId: {}", bookId);BookInfo bookInfo = new BookInfo();bookInfo.setId(bookId);bookInfo.setStatus(0);return bookMapper.deleteBookById(bookInfo);}
}

        BookMapper类:

@Mapper
public interface BookMapper {/*** 删除图书*/Integer deleteBookById(BookInfo bookInfo);
}

        删除图书的xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.books_management_system.mapper.BookMapper"><update id="deleteBookById">update book_info<set><if test="status != null">status = #{status}</if></set>where id = #{id}</update></mapper>

十一、批量删除

        BookController类:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 批量删除图书*/@RequestMapping("/batchDeleteBook")public String batchDeleteBook(@RequestParam List<Integer> ids) {log.info("批量删除图书, ids: {}", ids);try{Integer result = bookService.batchDeleteBookById(ids);if(result > 0) {return "";}return "内部错误, 请练习管理员11111";}catch (Exception e) {log.error("批量删除图书失败, e: " + e);return "内部错误, 请练习管理员";}}
}

        BookService类:

@Slf4j
@Service
public class BookService {@AutowiredBookMapper bookMapper;public Integer batchDeleteBookById(List<Integer> ids) {return bookMapper.batchDeleteBookByIds(ids);}
}

        BookMapper类:

@Mapper
public interface BookMapper {/*** 批量删除*/Integer batchDeleteBookByIds(List<Integer> ids);
}

        批量删除图书的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.books_management_system.mapper.BookMapper"><delete id="batchDeleteBookByIds">update book_info set status = 0where id in<!--    (1, 2, 3, 4)--><foreach collection="ids" open="(" close=")" item="id" separator=",">#{id}</foreach></delete></mapper>

十二、强制登录

        强制登录是指不让用户在没登录的情况下访问某一列表,会使用到session,如果没登录直接访问图书某一列表的url,则让用户跳转到登录界面进行强制登录所以不用这里每一个接口都要增添一个强制登录的功能,但已经写好了代码的接口,逐一添加会耗时好力这里只给 图书列表 接口增添这个功能后面学习了SpringBoot 统一功能处理再解决其他接口,添加强制登录

        图书列表也就是在Controller层进行修改,增添强制登录的功能,和上面图书列表的Controller代码一样:

@Slf4j
@RestController
@RequestMapping("/book")
public class BookController {@AutowiredBookService bookService;/*** 查询图书列表*/@RequestMapping("/getBookListByPage")public Result<PageResult<BookInfo>> getBookListByPage(PageRequest pageRequest, HttpSession session) {log.info("查询图书的列表, 请求参数pageRequest: {}", pageRequest);//从session中获取用户信息//如果用户信息为空, 说明用户未登录UserInfo loginUserInfo = (UserInfo) session.getAttribute(Constant.USER_SESSION_KEY);if(loginUserInfo == null || loginUserInfo.getId() < 0) {return Result.nologin();}//参数校验if(pageRequest.getPageNum() == null) {//返回默认第一页,如果pageSize也没设置,则会使用默认的10pageRequest.setPageNum(1);}PageResult<BookInfo> bookList = bookService.getBookListByPage(pageRequest);return Result.success(bookList);}
}

十三、前端代码

(1)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() {var userName = $("#userName").val();var password = $("#password").val();$.ajax({url: "/user/login",type: "post",data: {userName: $("#userName").val(),password: $("#password").val()},success: function(result) {if(result == "") {location.href = "book_list.html?pageNum=1";} else{alert(result);}}});}</script>
</body></html>

(2)book_add.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/add.css"></head><body><div class="container"><div class="form-inline"><h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16"><pathd="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" /></svg><span>添加图书</span></h2></div><form id="addBook"><div class="form-group"><label for="bookName">图书名称:</label><input type="text" class="form-control" placeholder="请输入图书名称" id="bookName" name="bookName"></div><div class="form-group"><label for="bookAuthor">图书作者</label><input type="text" class="form-control" placeholder="请输入图书作者" id="bookAuthor" name="author" /></div><div class="form-group"><label for="bookStock">图书库存</label><input type="text" class="form-control" placeholder="请输入图书库存" id="bookStock" name="count"/></div><div class="form-group"><label for="bookPrice">图书定价:</label><input type="number" class="form-control" placeholder="请输入价格" id="bookPrice" name="price"></div><div class="form-group"><label for="bookPublisher">出版社</label><input type="text" id="bookPublisher" class="form-control" placeholder="请输入图书出版社" name="publish" /></div><div class="form-group"><label for="bookStatus">图书状态</label><select class="custom-select" id="bookStatus" name="status"><option value="1" selected>可借阅</option><option value="2">不可借阅</option></select></div><div class="form-group" style="text-align: right"><button type="button" class="btn btn-info btn-lg" onclick="add()">确定</button><button type="button" class="btn btn-secondary btn-lg" onclick="javascript:history.back()">返回</button></div></form></div><script type="text/javascript" src="js/jquery.min.js"></script><script>function add() {$.ajax({url: "/book/addBook",type: "post",data: $("#addBook").serialize(),success: function(result) {if(result == "") {//添加成功location.href = "book_list.html";} else {alert(result);}}})}</script>
</body></html>

(3)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></tbody></table><div class="demo"><ul id="pageContainer" class="pagination justify-content-center"></ul></div><script>getBookList();function getBookList() {$.ajax({url: "/book/getBookListByPage" + location.search,type: "get",success: function (result) {if (result.code == "NOLOGIN") {//用户登录location.href = "login.html";}if (result.data != null && result.data.records != null) {console.log("拿到参数")var finalHtml = "";for (book of result.data.records) {finalHtml += '<tr>';finalHtml += '<td><input type="checkbox" name="selectBook" value="' + book.id + '" id="' + book.id + '" 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>';finalHtml += '<div class="op">';finalHtml += '<a href="book_update.html?bookId=' + book.id + '">修改</a>';finalHtml += '<a href="javascript:void(0)" onclick="deleteBook(' + book.id + ')">删除</a>';finalHtml += '</div>';finalHtml += '</td>';finalHtml += '</tr>';}$("tbody").html(finalHtml);var data = result.data;//翻页信息$("#pageContainer").jqPaginator({totalCounts: data.count, //总记录数pageSize: 10,    //每页的个数visiblePages: 5, //可视页数currentPage: data.pageRequest.pageNum,  //当前页码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);if (type == "change") {location.href = "book_list.html?pageNum=" + page;}}});}}});}function deleteBook(id) {var isDelete = confirm("确认删除?");if (isDelete) {//删除图书$.ajax({url: "/book/deleteBook",type: "post",data: {bookId: id},success: function (result) {if (result == "") {// location.href = "book_list.html" + location.search;location.href = "book_list.html";} else {alert(result);}}});// alert("删除成功");}}function batchDelete() {var isDelete = confirm("确认批量删除?");if (isDelete) {//获取复选框的idvar ids = [];$("input:checkbox[name='selectBook']:checked").each(function () {ids.push($(this).val());});console.log(ids);$.ajax({url: "/book/batchDeleteBook?ids=" + ids,type: "post",success: function (result) {if (result == "") {//删除成功location.href = "book_list.html";} else {alert(result);}}});// alert("批量删除成功");}}</script></div>
</body></html>

(4)book.update.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/add.css">
</head><body><div class="container"><div class="form-inline"><h2 style="text-align: left; margin-left: 10px;"><svg xmlns="http://www.w3.org/2000/svg" width="40"fill="#17a2b8" class="bi bi-book-half" viewBox="0 0 16 16"><pathd="M8.5 2.687c.654-.689 1.782-.886 3.112-.752 1.234.124 2.503.523 3.388.893v9.923c-.918-.35-2.107-.692-3.287-.81-1.094-.111-2.278-.039-3.213.492V2.687zM8 1.783C7.015.936 5.587.81 4.287.94c-1.514.153-3.042.672-3.994 1.105A.5.5 0 0 0 0 2.5v11a.5.5 0 0 0 .707.455c.882-.4 2.303-.881 3.68-1.02 1.409-.142 2.59.087 3.223.877a.5.5 0 0 0 .78 0c.633-.79 1.814-1.019 3.222-.877 1.378.139 2.8.62 3.681 1.02A.5.5 0 0 0 16 13.5v-11a.5.5 0 0 0-.293-.455c-.952-.433-2.48-.952-3.994-1.105C10.413.809 8.985.936 8 1.783z" /></svg><span>修改图书</span></h2></div><form id="updateBook"><input type="hidden" class="form-control" id="bookId" name="id"><div class="form-group"><label for="bookName">图书名称:</label><input type="text" class="form-control" id="bookName" name="bookName"></div><div class="form-group"><label for="bookAuthor">图书作者</label><input type="text" class="form-control" id="bookAuthor" name="author"/></div><div class="form-group"><label for="bookStock">图书库存</label><input type="text" class="form-control" id="bookStock" name="count"/></div><div class="form-group"><label for="bookPrice">图书定价:</label><input type="number" class="form-control" id="bookPrice" name="price"></div><div class="form-group"><label for="bookPublisher">出版社</label><input type="text" id="bookPublisher" class="form-control" name="publish"/></div><div class="form-group"><label for="bookStatus">图书状态</label><select class="custom-select" id="bookStatus" name="status"><option value="1" selected>可借阅</option><option value="2">不可借阅</option></select></div><div class="form-group" style="text-align: right"><button type="button" class="btn btn-info btn-lg" onclick="update()">确定</button><button type="button" class="btn btn-secondary btn-lg" onclick="javascript:history.back()">返回</button></div></form></div><script type="text/javascript" src="js/jquery.min.js"></script><script>$.ajax({url: "/book/queryBookById" + location.search,type: "get",success: function(book) {$("#bookId").val(book.id);$("#bookName").val(book.bookName);$("#bookAuthor").val(book.author);$("#bookStock").val(book.count);$("#bookPrice").val(book.price);$("#bookPublisher").val(book.publish);$("#bookStatus").val(book.status)}});function update() {$.ajax({url: "/book/updateBook",type: "post",data: $("#updateBook").serialize(),success: function(result) {if(result == "") {//更新成功location.href = "book_list.html";} else{alert(result);}}})// alert("更新成功");// location.href = "book_list.html"}</script>
</body></html>

十四、测试

(1)登录界面

        输入URL:http://127.0.0.1:8080/login.html

        不输入密码:

        输入错误密码:

        输入正确用户名、密码:

        登录成功,跳转到下面界面:

(2)添加图书

        不安规定,少输入信息进行添加,会出现下面结果:

        正确添加图书:

        多出现了刚刚添加的图书信息

        数据库内容:

(3)翻页,图书列表

        第一页:

        第二页:

(4)修改图书

        点击确定,成功修改:

        数据库内容:

(5)删除图书

        点击确定,删除成功:

        数据库内容:

(6)批量删除图书

        勾选图书ID为19、18、17、16、15

        点击批量删除,结果如下:

        数据库内容:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/39423.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI与测试相辅相成

AI助力软件测试 1.AI赋能软件测试 使用AI工具来帮助测试人员提高测试效率&#xff0c;提供缺陷分析和缺陷预测。 语法格式 设定角色 具体指示 上下文格式 例: 角色&#xff1a;你是一个测试人员 内容&#xff1a;请帮我生成登录案例的测试用例 ​ 1.只有输入正确账号和密码才…

生命在于学习——Python人工智能原理(3.2.1)

二、随机变量 2.1 随机变量及其分布 &#xff08;一&#xff09;基本概念 定义1 随机变量 随机变量表示随机试验各种结果的实值单值函数&#xff0c;即能用数学分析方法来研究随机现象&#xff0c;例如某一时间内公共汽车站等车的乘客人数、淘宝在一定时间内的交易次数等&am…

Shenandoah GC概述

文章目录 1_介绍2_原理1.0版本2.0版本3_ShenandoahGC的执行流程4_并发转移阶段 – 并发问题 1_介绍 Shenandoah 是由Red Hat开发的一款低延迟的垃圾收集器&#xff0c;Shenandoah 并发执行大部分 GC 工作&#xff0c;包括并发的整理&#xff0c;堆大小对STW的时间基本没有影响…

【pearcmd】通过pearcmd.php 进行GetShell

https://cloud.tencent.com/developer/article/2204400 关于PHP 配置 register_argc_argv 小结 的一些研究文章。 应用例题 [NewStarCTF 2023 公开赛道]Include &#x1f350; <?phperror_reporting(0);if(isset($_GET[file])) {$file $_GET[file];if(preg_match(/flag|l…

贪心 | Java | LeetCode 455, 376, 53 做题总结

贪心算法介绍 贪心算法&#xff1a;贪心的本质是选择每一阶段的局部最优&#xff0c;从而达到全局最优。 说实话贪心算法并没有固定的套路。 一般解题步骤 贪心算法一般分为如下四步&#xff1a; ① 将问题分解为若干个子问题 ② 找出适合的贪心策略 ③ 求解每一个子问题的…

SQL Server数据库的组成

《SQL Server 2022从入门到精通&#xff08;视频教学超值版&#xff09;》图书介绍-CSDN博客 对于数据库的概念&#xff0c;没有一个完全固定的定义&#xff0c;随着数据库历史的发展&#xff0c;定义的内容也有很大的差异&#xff0c;其中一种比较普遍的观点认为&#xff0c;…

Winform中使用HttpClient实现调用http的post接口并设置传参content-type为application/json示例

场景 Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类&#xff1a; Winform中怎样使用HttpClient调用http的get和post接口并将接口返回json数据解析为实体类_winform解析json-CSDN博客 上面使用HttpClient调用post接口时使用的HttpCon…

21.《C语言》——【位操作符】

&#x1f33b;开场语 亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&a…

今天不看文章,明天变垃圾(明天收费)-----字节数据分析发展过程中所遭遇的挑战

字节数据分析发展过程中所遭遇的挑战 三个核心议题&#xff1a; 海量数据分析性能&#xff1a;会议指出Spark分析性能不足成为了一个显著问题&#xff0c;尤其是在需要毫秒级响应的业务场景中。实时导入与查询能力&#xff1a;目前Kylin只能以T1的形式提供分析服务&#xff0…

蓝牙资讯|苹果Apple Pencil新专利:用笔套扩展传感器 / 续航等模块化方案

根据美国商标和专利局最新公示的清单&#xff0c;苹果公司获得了一项 Apple Pencil 的专利&#xff0c;探索了模块化设计方案&#xff0c;用户未来可以根据自身需求或者使用场景&#xff0c;随心更换 Pencil 的模块&#xff0c;达到不同的效果。 苹果在专利中表示笔套内置传感器…

图书电商引入实在Agent:自动化运营提效80%,节省人天1000+

某知名教辅图书品牌深耕中小学教辅图书领域&#xff0c;是中国最具影响力的教育出版策划与发行集团之一&#xff0c;以丰富的图书品类&#xff0c;满足了小学、初中、高中各年龄段读者多元化的阅读需求。 2023年&#xff0c;该品牌在运营、客服等多部门超60个场景中部署实在Ag…

2024高考作文题“人工智能”

今年开年到现在&#xff0c;明显的感受就是&#xff0c;咨询人工智能机器人的客户比往年更多了。什么原因&#xff0c;是因为人工成本太高了&#xff0c;今年整体经济环境变差&#xff0c;招不起人&#xff0c;所以想用AI机器人来降低用工成本吗&#xff1f; 还是说因为语音线路…

项目进度管理(信息系统项目管理师)

定义活动的输出&#xff1a;活动清单、活动属性、里程碑清单定义活动的输入包括进度管理计划、范围基准、事业环境因素、组织过程资产定义活动的工具与技术包括专家判断、分解、滚动式规划、会议分解是一种把项目范围和项目可交付成果逐步划分为更小、更便于管理的组成部分的技…

银湖资本在中国设立公司运营点,全球投资巨头的新篇章!

近日&#xff0c;全球知名私募股权投资公司银湖资本宣布在中国设立公司运营点。一点是银湖资本在国内安置了两个办事营业点&#xff0c;一个在黑龙江&#xff0c;一个在广州等一线城市。这一举动标志着银湖资本在全球范围内的扩展进入了新的阶段&#xff0c;同时也展示了其对中…

SerialportToTcp①

窗体 效果&#xff1a;串口和网口旁边的是panel当客户端或者服务器发送消息的时候会闪烁&#xff0c;下面的的textbox当接收到接受或者发送的数据会增加数量&#xff0c;心跳机制单选框可以开关&#xff0c;可设置心跳间隔和内容&#xff0c;重置按钮重置串口数据&#xff0c;…

PDM系统中物料分类与编码规则生成方案

在企业管理软件中&#xff0c;PDM系统是企业管理的前端软件&#xff0c;用于管理研发图纸、BOM等数据&#xff0c;然后生成相关物料表或BOM&#xff0c;递交给后端ERP系统进行生产管理。在PDM系统中&#xff0c;有两种方式可以生成物料编码。 1第一种是用户可以通过软件接口将…

汽车免拆诊断案例 | 2021款路虎揽胜运动版车遥控及一键起动功能失效

故障现象 一辆2021款路虎揽胜运动版车&#xff0c;搭载AJ20-P6H3L发动机&#xff0c;累计行驶里程约为2.5万km。车主反映&#xff0c;使用智能钥匙无法解锁车门&#xff0c;使用机械钥匙打开车门&#xff0c;进入车内&#xff0c;发现一键起动功能也失效&#xff1b;根据组合…

将excel表格转换为element table(下)

在‘将excel表格转换为element table(上)’我们把excel 转换后通过数据重构绑定到了element table上&#xff0c;现在要做的就是根据源文件进行行列进行合并操作 先看看最终处理的结果 这里在一步步分析实现步骤。 先分析一下合并的逻辑 大致思路理理如上。 思路有了接下来…

3-数据提取方法1(json)(6节课学会爬虫)

3-数据提取方法1&#xff08;json&#xff09;&#xff08;6节课学会爬虫&#xff09; 1&#xff0c;Json2&#xff0c;哪里会返回json的数据&#xff08;值得尝试的操作&#xff09;3&#xff0c;Json字符串转换成字典或python类型进行数据提取&#xff08;1&#xff09;Json.…

农夫山泉:玩一个“弯道超车”的“新游戏”

今年夏天&#xff0c;有一款产品的爆火&#xff0c;仿佛上演了一出“欧亨利式”的好戏&#xff0c;既出人意料又在情理之中。它就是农夫山泉的“冰杯”。 在小红书搜索关键词“冰杯”后&#xff0c;我们会发现&#xff0c;相关笔记达到4万篇&#xff0c;相关商品超过8000件&am…