Spring-图书管理系统

发布于:2025-06-29 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

一.项目准备

        1.创建项目

        2.配置MyBatis 

二.代码编写

        1.创建数据库和数据表

        2.用户登入接口

                创建用于接收登入用户数据的类(和用户数据表匹配,使用驼峰的方式):

                创建Mapper(根据登入用户的用户名来获取数据库中的密码) :

                创建Service: 

                创建Controller:

                HTML页面准备:

                运行结果: 

                3.图书列表接口

                        创建用于接收图书列表数据的类: 

                        创建页面信息类(当前页码和每页显示的条数): 

                        创建用于接收图书信息的类:

                        创建Mapper: 

                 创建Service:

                 创建Controller:

                        返回中文图书状态:

        4.添加图书接口         

                创建Mapper:

                创建Service: 

                创建Controller:

                        在Controller层中有一个设计问题:

                                当需要查看代码条件语句,在某一操作下的执行结果,来判断代码是否执行正确的情况:​编辑

                        HTML代码准备:

        5.图书修改接口

                查询图书信息:

                        创建Mapper: 

                        创建Service: 

                        创建Controller: 

                修改图书信息:

                        创建Mapper:

                        XML文件代码:

                        创建Service: 

                        创建Controller: 

                        HTML代码准备:

                6.删除单个图书和批量删除选中的图书接口 :

                        删除单本图书:

                                批量删除图书:

                                        创建Mapper:

                                        创建Service层: 

                                        创建Controller层: 

                7.强制登入


一.项目准备

        1.创建项目

        2.配置MyBatis 

        在使用yml配置文件的时候一定要注意空格,空格不对会导致yml配置文件读取错误: 


MyBatis配置模板 https://blog.csdn.net/weixin_52159554/article/details/148771292?spm=1001.2014.3001.5501

        试运行检查MySQL数据库连接是否成功: 

        表示连接成功: 

       连接错误日志 https://blog.csdn.net/weixin_52159554/article/details/148848671?sharetype=blogdetail&sharerId=148848671&sharerefer=PC&sharesource=weixin_52159554&spm=1011.2480.3001.8118

二.代码编写

        1.创建数据库和数据表

 -- 创建数据库
 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, '⺠主与建设出版社');

INSERT INTO `book_info` ( book_name, author, count, price, publish )
 VALUES
 ( '图书2', '作者2', 29, 22.00, '出版社2' ),( '图书3', '作者2', 29, 22.00, '出版社
3' ),
 ( '图书4', '作者2', 29, 22.00, '出版社1' ),( '图书5', '作者2', 29, 22.00, '出版社
1' ),
 ( '图书6', '作者2', 29, 22.00, '出版社1' ),( '图书7', '作者2', 29, 22.00, '出版社
1' ),
 ( '图书8', '作者2', 29, 22.00, '出版社1' ),( '图书9', '作者2', 29, 22.00, '出版社
1' ),
 ( '图书10', '作者2', 29, 22.00, '出版社1'),( '图书11', '作者2', 29, 22.00, '出版
社1'),
 ( '图书12', '作者2', 29, 22.00, '出版社1'),( '图书13', '作者2', 29, 22.00, '出版
社1'),
 ( '图书14', '作者2', 29, 22.00, '出版社1'),( '图书15', '作者2', 29, 22.00, '出版
社1'),
 ( '图书16', '作者2', 29, 22.00, '出版社1'),( '图书17', '作者2', 29, 22.00, '出版
社1'),
 ( '图书18', '作者2', 29, 22.00, '出版社1'),( '图书19', '作者2', 29, 22.00, '出版
社1'),
( '图书20', '作者2', 29, 22.00, '出版社1'),( '图书21', '作者2', 29, 22.00, '出版
社1');

        2.用户登入接口

                创建用于接收登入用户数据的类(和用户数据表匹配,使用驼峰的方式):
import lombok.Data;

import java.util.Date;

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

                创建Mapper(根据登入用户的用户名来获取数据库中的密码) :
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.springbookmanagerdemo.model.UserInfo;

@Mapper
public interface UserInfoMapper {

    @Select("select * from user_info where user_name = #{userName}")
    UserInfo selectUserPassword(String userName);
}

                创建Service: 
import org.example.springbookmanagerdemo.mapper.UserInfoMapper;
import org.example.springbookmanagerdemo.model.UserInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    public UserInfo getUserInfo(String username){
        return userInfoMapper.selectUserPassword(username);
    }
}

                创建Controller:
import org.example.springbookmanagerdemo.model.UserInfo;
import org.example.springbookmanagerdemo.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@RequestMapping("/user")
@RestController
public class UserInfoController {

    @Autowired
    private UserInfoService userInfoService;

    @RequestMapping("/login")
    public boolean userLogin(String userName, String password, HttpSession session) {

        if(!StringUtils.hasLength(userName) && !StringUtils.hasLength(password)){
            return false;
        }

        UserInfo userInfo = userInfoService.getUserInfo(userName);

        if(userInfo.getPassword().equals(password)){

            //将密码置空保护用户信息安全
            userInfo.setPassword("");
            //保存Session
            session.setAttribute("userName",userInfo);

            return true;
        }

        return false;
    }
}

                HTML页面准备:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="css/login.css">
    <script type="text/javascript" src="js/jquery.min.js"></script>
</head>

<body>
    <div class="container-login">
        <div class="container-pic">
            <img src="pic/computer.png" width="350px">
        </div>
        <div class="login-dialog">
            <h3>登陆</h3>
            <div class="row">
                <span>用户名</span>
                <input type="text" name="userName" id="userName" class="form-control">
            </div>
            <div class="row">
                <span>密码</span>
                <input type="password" name="password" id="password" class="form-control">
            </div>
            <div class="row">
                <button type="button" class="btn btn-info btn-lg" onclick="login()">登录</button>
            </div>
        </div>
    </div>
    <script src="js/jquery.min.js"></script>
    <script>

        function login() {
            $.ajax({
                type: 'post',
                url: '/user/login',
                data:{
                    "userName": $("#userName").val(),
                    "password": $("#password").val()
                },
                success: function (result) {
                    if(result){
                        location.href = "book_list.html"
                    }else{
                        alert('登入失败!')
                    }
                }
            })
        }

    </script>
</body>

</html>
                运行结果: 

                3.图书列表接口

                        创建用于接收图书列表数据的类: 
import lombok.Data;

import java.util.List;

@Data
public class PageResult<T> {

    //图书列表数据
    private List<T> records;
    //图书总数
    private Integer total;
    
    public PageResult(Integer total, List<T> records) {
        this.total = total;
        this.records = records;
    }
}

                        创建页面信息类(当前页码和每页显示的条数): 
import lombok.Data;

@Data
public class PageRequest {

    //当前页码
    private Integer currentPage = 1;

    //每页的显示条数
    private Integer pageSize = 10;
    
    private Integer offset;

    public Integer getOffset() {
        return (currentPage - 1) * pageSize;
    }
}

                        创建用于接收图书信息的类:
import lombok.Data;

import java.math.BigDecimal;

@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;
    private String statusCN;

}

                        创建Mapper: 
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.example.springbookmanagerdemo.model.BookInfo;

import java.util.List;

@Mapper
public interface BookInfoMapper {

    //获取图书列表
    @Select("select * from book_info where status != 0" +
            " order by id asc" +
            " limit ${offset},${pageSize}")
    List<BookInfo> selectByPage(@Param("offset") Integer offset, @Param("pageSize")Integer pageSize);

    //获取图书总量
    @Select("select count(1) from book_info where status != 0")
    Integer selectCount();
}

                 创建Service:
import org.example.springbookmanagerdemo.mapper.BookInfoMapper;
import org.example.springbookmanagerdemo.model.BookInfo;
import org.example.springbookmanagerdemo.model.PageRequest;
import org.example.springbookmanagerdemo.model.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookInfoService {

    @Autowired
    private BookInfoMapper bookInfoMapper;

    PageResult<BookInfo> pageResult = null;

    public PageResult<BookInfo> getPageResult(PageRequest pageRequest) {

        pageResult = new PageResult<>(bookInfoMapper.selectCount(),
                                      bookInfoMapper.selectByPage(pageRequest.getOffset(),pageRequest.getPageSize()),
                                      pageRequest);

        return pageResult;
    };
}

                 创建Controller:
import lombok.extern.slf4j.Slf4j;
import org.example.springbookmanagerdemo.model.BookInfo;
import org.example.springbookmanagerdemo.model.PageRequest;
import org.example.springbookmanagerdemo.model.PageResult;
import org.example.springbookmanagerdemo.service.BookInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("/book")
@RestController
@Slf4j
public class BookInfoController {

    @Autowired
    private BookInfoService bookInfoService;

    @RequestMapping("/getListByPage")
    public PageResult<BookInfo> getListByPage(PageRequest pageRequest) {

        if(pageRequest.getCurrentPage() < 0 || pageRequest.getPageSize() < 1 ) {
            return null;
        }

        System.out.println(pageRequest.getCurrentPage());
        System.out.println(pageRequest.getPageSize());

        PageResult<BookInfo> pageResult = null;
        try {
           pageResult =  bookInfoService.getPageResult(pageRequest);
        }
        catch (Exception e) {
            log.error("查询翻页信息错误,e:{}",e);
        }

        return pageResult;
    }
}

                        图书列表页面准备: 

<!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>
                <tr>
                    <td><input type="checkbox" name="selectBook" value="1" id="selectBook" class="book-select"></td>
                    <td>4</td>
                    <td>大秦帝国第四册</td>
                    <td>我是作者</td>
                    <td>23</td>
                    <td>33.00</td>
                    <td>北京出版社</td>
                    <td>可借阅</td>
                    <td>
                        <div class="op">
                            <a href="book_update.html?bookId=4">修改</a>
                            <a href="javascript:void(0)" onclick="deleteBook(4)">删除</a>
                        </div>
                    </td>
                </tr>
            </tbody>
        </table>

        <div class="demo">
            <ul id="pageContainer" class="pagination justify-content-center"></ul>
        </div>
        <script>

            getBookList();
            function getBookList() {
                $.ajax({
                    type: 'get',
                    url: '/book/getListByPage' + location.search,
                    success: function (result) {
                        bookList = result.records;
                        var trE = ''
                        for(var books of bookList) {
                            trE += '<tr>'
                            trE += '<td><input type="checkbox" name="selectBook" value="'+books.id+'" id="selectBook" class="book-select"></td>'
                            trE += '<td>'+books.id+'</td>'
                            trE += '<td>'+books.bookName+'</td>'
                            trE += '<td>'+books.author+'</td>'
                            trE += '<td>'+books.count+'</td>'
                            trE += '<td>'+books.price+'</td>'
                            trE += '<td>'+books.publish+'</td>'
                            trE += '<td>'+books.statusCN+'</td>'
                            trE += '<td> <div class="op">'
                            trE += ' <a href="book_update.html?bookId='+books.id+'">修改</a>'
                            trE += ' <a href="javascript:void(0)" onclick="deleteBook('+books.id+')">删除</a>'
                            trE += ' </div></td></tr>'
                            $('tbody').html(trE)
                        }

                        //翻页信息
                        $("#pageContainer").jqPaginator({
                            totalCounts: result.total, //总记录数
                            pageSize: 10,    //每页的个数
                            visiblePages: 5, //可视页数
                            currentPage: result.pageRequest.currentPage,  //当前页码
                            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?currentPage="+page;
                                }
                            }
                        });
                    }
                })
            }

            function deleteBook(id) {
                var isDelete = confirm("确认删除?");
                if (isDelete) {
                    //删除图书
                    alert("删除成功");
                }
            }
            function batchDelete() {
                var isDelete = confirm("确认批量删除?");
                if (isDelete) {
                    //获取复选框的id
                    var ids = [];
                    $("input:checkbox[name='selectBook']:checked").each(function () {
                        ids.push($(this).val());
                    });
                    console.log(ids);
                    alert("批量删除成功");
                }
            }



        </script>
    </div>
</body>

</html>
                        返回中文图书状态:

                                创建enum枚举类型:

public enum BookStatusEnum {

    DELETED(0,"删除"),
    NORMAL(1,"可借阅"),
    FORBIDDEN(2,"不可借阅");

    public static BookStatusEnum getBookStatusEnum(int status){
        switch(status){
            case 0:return DELETED;
            case 1:return NORMAL;
            case 2:return FORBIDDEN;
            default:return FORBIDDEN;
        }
    }


    private int code;
    private String name;

    BookStatusEnum(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

                               在Service层添加状态处理: 

import org.example.springbookmanagerdemo.enums.BookStatusEnum;
import org.example.springbookmanagerdemo.mapper.BookInfoMapper;
import org.example.springbookmanagerdemo.model.BookInfo;
import org.example.springbookmanagerdemo.model.PageRequest;
import org.example.springbookmanagerdemo.model.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class BookInfoService {

    @Autowired
    private BookInfoMapper bookInfoMapper;

    PageResult<BookInfo> pageResult = null;

    public PageResult<BookInfo> getPageResult(PageRequest pageRequest) {

        pageResult = new PageResult<>(bookInfoMapper.selectCount(),
                                      bookInfoMapper.selectByPage(pageRequest.getOffset(),pageRequest.getPageSize()),
                                      pageRequest);

        if(pageResult.getRecords() != null && pageResult.getRecords().size() > 0) {
            for(BookInfo bookInfo : pageResult.getRecords()) {
              bookInfo.setStatusCN(BookStatusEnum.getBookStatusEnum(bookInfo.getStatus()).getName());
            }
        }

        return pageResult;
    };
}

                                此时对于图书价格,当图书为整数的时候,会只显示为 22,而不是22.00此时只需要在后端将这个数据的传输格式限制为字符串就可以了:

        4.添加图书接口         

                创建Mapper:
 @Insert("insert into book_info (`book_name`, `author`, `count`, `price`,`publish`,`status`)" +
            "values (#{bookName}, #{author}, #{count}, #{price}, #{publish}, #{status})")
    Integer insertBook(BookInfo bookInfo);

                创建Service: 
//新增图书
    public Integer insertBookInfo(BookInfo bookInfo) {
        Integer result = 0;

        try{
            result = bookInfoMapper.insertBook(bookInfo);
        }catch (Exception e){
            log.error("新增图书失败:e:{}",e);
        }
        return result;
    }

                创建Controller:
@RequestMapping("/addBook")
    public String addBook(BookInfo bookInfo) {

        if(!StringUtils.hasLength(bookInfo.getBookName())
                || !StringUtils.hasLength(bookInfo.getAuthor())
                || bookInfo.getCount() < 0
                || bookInfo.getPrice() == null
                || !StringUtils.hasLength(bookInfo.getPublish())) {
            return "参数校验失败,请重新传入图书参数";
        }

        Integer result = bookInfoService.insertBookInfo(bookInfo);

        if(result <= 0) {
            log.error("添加图书错误,bookInfo:{}",bookInfo);
            return "添加图书错误,请联系管理员";
        }

        return "";
    }

                        在Controller层中有一个设计问题:

                                上图中的这段代码其实也可以写成: 

                                这两段代码的最终的实现结果都是一样的,但是不同的地方在于,图一中的业务逻辑处理在方法的第一层,图二中的业务逻辑处理在方法的第二层。

                                在项目开发规范中,一个方法不建议,循环超过五层。超过五层代码就变得不易读了,不方便后期的维护。

                                当需要查看代码条件语句,在某一操作下的执行结果,来判断代码是否执行正确的情况:

                                这样就可以看到这个条件语句的执行结果了。            

                        HTML代码准备:

                                $("#addBook").serialize() 可以提交整个from表单中的数据,input、select、text area等输入信息都会提交。

                                 提交的内容大概就是输入框的name:输入框的内容,这个是在$.ajax的data中。

<!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({
                type: "POST",
                url: "/book/addBook/",
                data: $("#addBook").serialize(),
                success: function (result) {
                    console.log(result);

                    if (result == "") {
                        alert("添加成功!");
                        location.href = "book_list.html";
                    } else {
                        alert("新增图书失败!");
                    }
                }
            })


        }


    </script>
</body>

</html>

        5.图书修改接口

                查询图书信息:
                        创建Mapper: 
//查询图书的信息
    @Select("select * from book_info " +
            "where id = #{id}")
    BookInfo selectBookById(Integer id);

                        创建Service: 
 //获取图书信息
    public BookInfo selectBookInfoById(Integer id) {
        return bookInfoMapper.selectBookById(id);
    }

                        创建Controller: 
 //获取图书信息
    @RequestMapping("/queryBookInfoById")
    public BookInfo selectBookInfo(Integer bookId) {
       return bookInfoService.selectBookInfoById(bookId);
    }

                修改图书信息:
                        创建Mapper:
 //修改图书的信息
    Integer updateBookInfo(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="org.example.springbookmanagerdemo.mapper.BookInfoMapper">

    <update id="updateBookInfo">
        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">
                status = #{status},
            </if>
        </set>
        where
            id = #{id}
    </update>

</mapper>
                        创建Service: 
//修改图书信息
    public Integer updateBookInfo(BookInfo bookInfo) {
        Integer result = 0;
        try{
            result = bookInfoMapper.updateBookInfo(bookInfo);
        }catch (Exception e){
            log.error("修改图书信息失败:e:{}",e);
        }

        return result;
    }

                        创建Controller: 
//修改图书信息
    @RequestMapping("/updateBook")
    public String updateBookInfo(BookInfo bookInfo) {
        if(!StringUtils.hasLength(bookInfo.getBookName())
            || !StringUtils.hasLength(bookInfo.getAuthor())
            || bookInfo.getCount() < 0
            || bookInfo.getPrice() == null
            || bookInfo.getPublish() == null) {
            return "参数校验失败,请重新传入图书参数";
        }

        Integer result = bookInfoService.updateBookInfo(bookInfo);
        if(result <= 0) {
            log.error("修改图书信息错误,bookInfo:{}",bookInfo);
            return "修改图书信息错误,请联系管理员";
        }

        return "";
    }

                        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({
            type: 'POST',
            url: '/book/queryBookInfoById' + location.search,
            success: function (result) {
                console.log(result);
                $("#bookId").val(result.id)
                $("#bookName").val(result.bookName)
                $("#bookAuthor").val(result.author)
                $("#bookStock").val(result.count)
                $("#bookPrice").val(result.price)
                $("#bookPublisher").val(result.publish)
                $("#bookStatus").val(result.status)
            }
        })

        function update() {
            $.ajax({
                type: 'GET',
                url: '/book/updateBook',
                data: {
                    "id": $("#bookId").val(),
                    "bookName": $("#bookName").val(),
                    "author": $("#bookAuthor").val(),
                    "count": $("#bookStock").val(),
                    "price": $("#bookPrice").val(),
                    "publish": $("#bookPublisher").val(),
                    "status": $("#bookStatus").val(),
                },
                success: function (result) {
                    if (result == "") {
                        alert("更新成功!");
                        location.href = "book_list.html"
                    } else {
                        alert("修改图书信息失败!");
                    }
                }
            })

        }


    </script>
</body>

</html>

                6.删除单个图书和批量删除选中的图书接口 :

                        在企业开发中很少使用delete语句来操作数据库中的数据,通常情况下,即使某些项目已经不对用户开放了,也不会将用户的数据彻底删除掉的,因为数据是非常宝贵的,但是也不代表数据就不删除了,只是换了一种方式。

                        对于数据来说,删除的方式通常分为逻辑删除和物理删除。

                        逻辑删除:数据依然在表中,只是将数据表示删除的字段置为删除。

                        物理删除:将数据从保存数据的物理设备上,彻底抹除掉。

                        一般情况下,在企业中会采用物理删除+存档或者逻辑删除+存档的方式对数据库中的数据进行操作。

                        所以,在这里所采用的删除也是逻辑删除。此时就不需要用delete关键字来操作数据了,使用update来更新数据库中需要操作的数据的字段就好了。

                        对于单个删除来说,直接使用之前的修改图书信息的接口就好了。

                        删除单本图书:

                        但是上面的接口在在Controller层进行参数校验的时候会将这样的请求给拦截,此时需要对代码就行修改: 

 //修改图书信息以及删除单本图书
    @RequestMapping("/updateBook")
    public String updateBookInfo(BookInfo bookInfo) {
        if(bookInfo.getStatus() != 0) {
            if(!StringUtils.hasLength(bookInfo.getBookName())
                    || !StringUtils.hasLength(bookInfo.getAuthor())
                    || bookInfo.getCount() < 0
                    || bookInfo.getPrice() == null
                    || bookInfo.getPublish() == null) {
                return "参数校验失败,请重新传入图书参数";
            }
        }

        Integer result = bookInfoService.updateBookInfo(bookInfo);
        if(result <= 0) {
            log.error("修改图书信息错误,bookInfo:{}",bookInfo);
            return "修改图书信息错误,请联系管理员";
        }

        return "";
    }

                                批量删除图书:
                                        创建Mapper:
 //批量删除图书
    Integer deleteBooksById(@Param("ids") List<Integer> ids);

                                        编写XML代码: 

 <update id = "deleteBooksById">
        update book_info
        set
            status = 0
        where id in
        <foreach collection="ids" item="id" separator="," open="(" close=")">
            #{id}
        </foreach>
    </update>
                                        创建Service层: 
//批量删除图书
    public Integer deleteBooksById(List<Integer> ids) {
        Integer result = 0;
        try{
            result = bookInfoMapper.deleteBooksById(ids);
        }catch (Exception e){
            log.error("删除图书失败:e:{}",e);
        }

        return result;
    }
                                        创建Controller层: 
//批量删除图书
    @RequestMapping("/batchDelete")
    public String deleteBookInfos(@RequestParam List<Integer> ids) {

        Integer result = bookInfoService.deleteBooksById(ids);
        if(result <= 0) {
            log.error("删除图书错误,ids:{}",ids);
            return "删除图书错误,请联系管理员";
        }

        return "";
    }

                7.强制登入

                         在没有用户登入检测的时候,直接进入图书列表的html网页,也是可以直接操作数据库信息的,这样是不合理的,所以此时需要进行登入检测,在没有登入信息的时候,进行强制登入。

                        创建Result类,用于后端返回响应的结果:

                                原来是由路径映射的方法直接返回数据,现在将需要返回的数据进行封装,加上了业务状态码和此次响应的信息提示。

import lombok.Data;
import org.example.springbookmanagerdemo.enums.ResultCode;

@Data
public class Result {
    /*业务状态码*/
    private ResultCode code;
    /*错误信息*/
    private String message;
    /*数据*/
    private Object data;

    public static Result success(Object data) {
        Result result = new Result();
        result.setCode(ResultCode.SUCCESS);
        result.setMessage(" ");
        result.setData(data);
        return result;
    }

    public static Result fail(String message) {
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setMessage(message);
        result.setData(null);
        return result;
    }

    public static Result fail(String message ,Object data) {
        Result result = new Result();
        result.setCode(ResultCode.FAIL);
        result.setMessage(message);
        result.setData(data);
        return result;
    }

    public static Result unlogin(){
        Result result = new Result();
        result.setCode(ResultCode.UNLOGIN);
        result.setMessage("用户未登入");
        result.setData(null);
        return result;
    }
}

public enum ResultCode {
    SUCCESS(0),
    FAIL(-1),
    UNLOGIN(2);

    private int code;

    ResultCode(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }
}

//获取图书列表
    @RequestMapping("/getListByPage")
    public Result getListByPage(PageRequest pageRequest, HttpSession session) {

        UserInfo userInfo = (UserInfo) session.getAttribute(Contants.SESSION_USER_KEY);
        if(userInfo == null || userInfo.getId() < 0 || "".equals(userInfo.getUserName())) {
            return Result.unlogin();
        }

        if(pageRequest.getCurrentPage() < 0 || pageRequest.getPageSize() < 1 ) {
            return Result.fail("数据校验错误");
        }

        PageResult<BookInfo> pageResult = null;
        try {
           pageResult =  bookInfoService.getPageResult(pageRequest);
           return Result.success(pageResult);
        }
        catch (Exception e) {
            log.error("查询翻页信息错误,e:{}",e);
            return Result.fail("查询翻译信息错误");
        }

    }

        如果使用上面的方式进行强制登入的话,需要在每一个页面的请求方法中都添加,未免也有点太繁琐了,可以采用拦截器。

import lombok.extern.slf4j.Slf4j;
import org.example.springbookmanagerdemo.constant.Contants;
import org.example.springbookmanagerdemo.model.Result;
import org.example.springbookmanagerdemo.model.UserInfo;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;


@Component
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HttpSession session = request.getSession(false);
        if(session != null && session.getAttribute(Contants.SESSION_USER_KEY) != null) {
            UserInfo userInfo = (UserInfo) session.getAttribute(Contants.SESSION_USER_KEY);
            if(userInfo != null && userInfo.getId() >= 0) {
                return true;
            }
        }

        response.setStatus(401);
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

                注册拦截器:

import org.example.springbookmanagerdemo.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.Arrays;
import java.util.List;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private LoginInterceptor loginInterceptor;

    private static List<String> excludePath = Arrays.asList(
            "/user/login",
            "/css/**",
            "/js/**",
            "/pic/**",
            "/**/*.html");

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
        .addPathPatterns("/**")
        .excludePathPatterns(excludePath);
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到