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

目录

一、数据库表设计

二、引入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=false
    username: root
    password: 1234
    driver-class-name: com.mysql.cj.jdbc.Driver

mybatis:
  configuration: #配置驼峰自动转换
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-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 {
    @Autowired
    private 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 {
    @Autowired
    private 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 {
    @Autowired
    BookService 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 {
    @Autowired
    BookMapper 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 {
    @Autowired
    BookService 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也没设置,则会使用默认的10
            pageRequest.setPageNum(1);
        }
        PageResult<BookInfo> bookList = bookService.getBookListByPage(pageRequest);
        return Result.success(bookList);
    }
}

        BookService类:

@Slf4j
@Service
public class BookService {
    @Autowired
    BookMapper 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 {
    @Autowired
    BookService 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 {
    @Autowired
    BookMapper 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 {
    @Autowired
    BookService 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 {
    @Autowired
    BookMapper 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 {
    @Autowired
    BookService 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 {
    @Autowired
    BookMapper 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 = 0
        where 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 {
    @Autowired
    BookService 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也没设置,则会使用默认的10
            pageRequest.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">
                    <path
                        d="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) {
                    //获取复选框的id
                    var 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">
                    <path
                        d="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

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

        数据库内容:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用 HBuilder X 进行 uniapp 小程序开发遇到的问题合集

文章目录 背景介绍问题集锦1. 在 HBuilderX 点击浏览器运行时&#xff0c;报 uni-app vue3编译器下载失败 安装错误2.在 HBuilderX 点击微信小程序运行时&#xff0c;报 微信开发者工具打开项目失败&#xff0c;请参阅启动日志错误 背景介绍 HBuilder X 版本&#xff1a;HBui…

餐饮界的新传奇:沃可趣员工社区,让品牌关怀在指尖流淌

咖啡师与顾客发生肢体冲突、员工用咖啡粉泼顾客……某精品咖啡一天爆出两个大瓜&#xff01; 很快有网友指出咖啡店员工长期遭受重压&#xff0c;与品牌之间存在根本矛盾。 同样做餐饮的老牌快餐&#xff0c;门店密度与之不相上下&#xff0c;却很少发生这样的暴雷。 不仅因…

六.核心动画 - 特殊图层①

引言 本专栏到目前为止已经介绍了CALayer&#xff0c;了解了它的绘画和动画功能。但是Core Animation图层不仅仅能够用于图片和颜色&#xff0c;本篇博客就来介绍一下一些CALayer的子类特殊图层&#xff0c;来进一步扩展Core Animation的绘图能力。 特殊图层 Core Animation…

Vue实现金钱输入框组件自动带千位逗号

新建PriceInput.vue <template><div id"bord"><el-inputv-model"inputValue"v-bind"$attrs":maxlength"maxlength"input"handleInput"focus"handleFocus"blur"handleBlur"change"h…

自闭症儿童:探索症状背后的多彩内心世界

在星启帆自闭症康复中心&#xff0c;我们每天与一群独特而珍贵的孩子相遇——他们&#xff0c;是自闭症谱系障碍的患儿。自闭症&#xff0c;这一复杂的神经发育障碍&#xff0c;以其多样化的症状表现&#xff0c;为每个孩子的生活轨迹绘上了不同的色彩。 自闭症孩子的症状各异…

Websocket通信实战项目(js)(图片互传应用)(下)客户端H5+css+js实现

Rqtz : 个人主页 ​ 共享IT之美&#xff0c;共创机器未来 Sharing the Beauty of IT and Creating the Future of Machines Together 目录 起始 客户端GUI Javascripts连接websocket 使用localStorage保存用户输入的IP Websocket连接成功 Websocket接收数据 解析…

【Linux】正确的关机方法

1. Linux正确的关机方式 如何关机呢&#xff1f;我想&#xff0c;很多朋友在DOS年代已经有在玩计算机了。在当时我们关闭DOS的系统时&#xff0c;常常是直接关闭电源开关&#xff0c;而Windows 在你不爽的时候&#xff0c;按着电源开关四秒也可以关机&#xff0c;但是在Linux则…

旧衣回收小程序:减少资源浪费,提高回收效率

当下&#xff0c;旧衣服回收成为了大众热衷的事&#xff0c;不少居民都会把闲置的衣物进行回收&#xff0c;旧衣回收行业逐渐火爆。不过&#xff0c;传统的旧衣回收模式已经不符合当下时代发展&#xff0c;具有较大的不便利性。 因此&#xff0c;为解决这一问题&#xff0c;线…

PG实践|内置函数之GENERATE_SERIES之深入理解(二)

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

使用Vue CLI方式创建Vue3.0应用程序

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统。新版本的 Vue CLI 的包名由原来的 vue-cli 改成了 vue/cli。 在开发大型项目时&#xff0c;需要考虑项目的组织结构、项目构建和部署等问题。如果手动完成这些配置工作&#xff0c;工作效率会非常低。为此&#xff0c;Vue.…

Rocky Linux 9 快速安装docker 教程

前述 CentOS 7系统将于2024年06月30日停止维护服务。CentOS官方不再提供CentOS 及后续版本&#xff0c;不再支持新的软件和补丁更新。CentOS用户现有业务随时面临宕机和安全风险&#xff0c;并无法确保及时恢复。由于 CentOS Stream 相对不稳定&#xff0c;刚好在寻找平替系统…

Python学生信息管理系统(完整代码)

引言&#xff1a;&#xff08;假装不是一个大学生课设&#xff09;在现代教育管理中&#xff0c;学生管理系统显得尤为重要。这种系统能够帮助教育机构有效地管理学生资料、成绩、出勤以及其他教育相关活动&#xff0c;从而提高管理效率并减少人为错误。通过使用Python&#xf…

IDEA版本推荐

推荐版本&#xff1a; IDEA 2024.1.4 下载链接&#xff1a;IDEA下载 &#xff08;下载时可以往下拖&#xff0c;选到自己想要的版本哦&#xff09; 本人由于项目开发需要&#xff0c;陆续用过几个版本的IDEA&#xff0c;包括&#xff1a; IDEA 2020.2.4 。这是在看韩顺平老师…

昇思25天学习打卡营第9天|CycleGAN图像风格迁移互换

文章目录 昇思MindSpore应用实践基于MindSpore的CycleGAN图像风格迁移互换1、CycleGAN 概述2、生成器部分3、判别器部分4、优化器和损失函数5、模型训练6、模型推理 Reference 昇思MindSpore应用实践 本系列文章主要用于记录昇思25天学习打卡营的学习心得。 基于MindSpore的C…

打造商贸物流“产-供-销”、“仓-运-配”全流程供应链

在当今全球化的商业环境中&#xff0c;商贸物流平台的搭建成为企业提升效率、降低成本并增强市场竞争力的关键因素。在现代商业环境中&#xff0c;商贸与物流之间的紧密协作是业务成功的关键因素。然而&#xff0c;许多组织面临着信息不对称、资源配套不足、以及系统间隔离等痛…

Windows的管理工具

任务计划程序&#xff1a;这是一个用来安排任务自动运行的工具。你可以在这里创建新的任务&#xff0c;设定触发条件&#xff0c;并指定任务的操作。 事件查看器&#xff1a;这是一套日志记录和分析工具&#xff0c;&#xff0c;你可以了解到系统的工作状况&#xff0c;帮助诊…

Spark大数据处理:技术、应用与性能优化(全)PDF书籍推荐分享

本书从一个系统化的视角&#xff0c;秉承大道至简的主导思想&#xff0c;介绍Spark中最值得关注的内 容&#xff0c;讲解Spark部署、开发实战&#xff0c;并结合Spark的运行机制及拓展&#xff0c;帮读者开启Spark技术之旅。 Spark大数据处理&#xff1a;技术、应用与性能优化…

阿里云邮件推送邮件发送失败的问题排查解决

阿里云邮件推送为何失败&#xff1f;解决邮件推送失败的步骤指南&#xff01; 即便是功能强大的阿里云邮件推送服务&#xff0c;也可能在实际使用中遇到邮件发送失败的问题。AokSend将详细介绍如何排查和解决阿里云邮件推送邮件发送失败的问题。 阿里云邮件推送&#xff1a;验…

深入浅出 LangChain 与智能 Agent:构建下一代 AI 助手

我们小时候都玩过乐高积木。通过堆砌各种颜色和形状的积木&#xff0c;我们可以构建出城堡、飞机、甚至整个城市。现在&#xff0c;想象一下如果有一个数字世界的乐高&#xff0c;我们可以用这样的“积木”来构建智能程序&#xff0c;这些程序能够阅读、理解和撰写文本&#xf…

6.26.3 基于Transformer的深度神经网络在数字乳腺断层合成图像上的乳腺癌分类

开发一种有效的深度神经网络模型&#xff0c;该模型结合了相邻图像部分的上下文&#xff0c;以检测数字乳腺断层合成(DBT)图像上的乳腺癌。 数字乳房断层合成(DBT)是一种医学成像技术&#xff0c;其中检测器围绕患者以有限角度旋转并记录多幅图像。然后将这些图像重建为二维(2D…