一、案例目的
基于Spring Boot+MyBatis+MySQL完成图书管理系统的设计与实现,本案例完成两个实体的维护和实体间的关系,两个实体分别为学生对象和图书对象,实体间的关系是学生借阅图书。
二、需求分析
2.1 系统角色
本系统包含图书管理员和学生两个角色,图书管理员可以维护学生信息、维护图书信息、查询借阅信息,学生可以查询图书、借阅图书、归还图书、查询借阅记录。
2.2 该系统功能层次图如下:
2.3 管理员模块功能
维护学生信息,可以对学生信息进行新增、修改、删除操作。
维护图书信息,可以对图书信息进行新增、修改、下架操作。
查询借阅信息,可以按条件对图书借阅情况进行查询,可以查询已借阅图书信息和未归还图书信息。
2.4 学生模块功能
查询图书,学生可以按条件查询图书相关信息。
借阅图书,学生可以借阅图书。
归还图书,学生对图书进行归还操作。
查询借阅记录,学生对自己借阅的图书记录进行查询。
三、数据库设计
学生表:学生编号、姓名、年龄、性别、出生日期、身份证号、电话号码。
图书表:图书编号、图书名称、图书类别、出版社、作者、图书库存、图书状态(0:正常,1:已下架)。
借阅记录表:借阅记录ID、学生编号、图书编号、借阅时间、归还状态、归还时间。
3.1 创建学生表
create table t_student (
id varchar(32) ,
name varchar(255),
age int,
sex varchar(2),
birthday varchar(20),
idCard varchar(20),
phone varchar(20)
);
3.2 创建图书表
create table t_book(
id varchar(32),
name varchar(50),
category varchar(32),
press varchar(50),
author varchar(50),
num int,
state varchar(2) default '0' comment '图书状态(0正常,1已下架)'
);
3.3 创建借阅记录表
create table t_borrow(
id varchar(32),
sid varchar(32),
bid varchar(32),
borrow_time varchar(32),
borrow_state varchar(2) comment '借阅状态(0借阅中,1已归还)',
back_time varchar(32)
);
3.4 数据初始化
insert into t_student
values('S1111','zhangsan',20,'1','2000-01-01','370701200001011111','15800000001');
insert into t_student
values('S2222','lisi',20,'1','2000-01-01','370701200001011112','15800000002');
四、案例实现
4.1 创建Spring Boot项目
创建Spring Boot项目,项目名称为springboot-book02。
pom文件如下所示:
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.0</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
4.2 基本配置
-
4.2.1 创建配置文件
resources目录下创建application.yml。
# 配置端口号
server:
port: 8090
# 配置数据源
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/book
username: root
password: root
# 配置MyBatis
mybatis:
mapper-locations: classpath*:mapper/**/*Mapper.xml
type-aliases-package: com.wfit
-
4.2.2 创建Constants常量类
com.wfit.boot.commons目录下创建Constants.java。
public class Constants {
// 默认成功码
public static final int SUCCESS_CODE = 200;
public static final String SUCCESS_MSG = "操作成功";
// 默认失败码
public static final int ERROR_CODE = 500;
public static final String ERROR_MSG = "系统异常";
// 图书状态(0:正常,1:已下架)
public static final String BOOK_STATE_NORMAL = "0";
public static final String BOOK_STATE_REMOVED = "1";
// 归还状态(0:借阅状态,1:归还状态)
public static final String BORROW_STATE_BORROW = "0";
public static final String BORROW_STATE_BACK = "1";
}
-
4.2.3 创建Result类
com.wfit.boot.commons目录下创建Result.java。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Result<T> {
//响应码
private int code;
//响应消息
private String msg;
//响应结果
private T data;
public static <T> Result<T> success(T data){
return new Result<>(Constants.SUCCESS_CODE, Constants.SUCCESS_MSG,data);
}
public static <T> Result<T> error(T data){
return new Result<>(Constants.ERROR_CODE, Constants.ERROR_MSG,data);
}
}
-
4.2.4 创建DateTimeUtil类
com.wfit.boot.commons目录下创建DateTimeUtil.java。
public class DateTimeUtil {
public static String now(){
LocalDateTime dateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return dateTime.format(formatter);
}
}
-
4.2.5 创建UuidUtil类
com.wfit.boot.commons目录下创建UuidUtil.java。
public class UuidUtil {
public static String getUUID(){
String uuid = UUID.randomUUID().toString().trim().replaceAll("-", "");
return uuid;
}
}
4.3 Student模块
-
4.3.1 创建Student实体类
com.wfit.boot.pojo目录下创建Student.java。
@Data
public class Student implements Serializable {
private String id; //学生学号
private String name;
private int age;
private String sex;
private String birthday;
private String idCard;
private String phone;
}
-
4.3.2 创建StudentController类
com.wfit.boot.controller目录下创建StudentController.java。
/**
* 维护学生信息
*/
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
/**
* 新增学生信息
*/
@PostMapping("/add")
public Result addStudent(@RequestBody Student student){
studentService.saveStudent(student);
return Result.success("新增学生成功," + student);
}
/**
* 修改学生信息
*/
@PostMapping("/update")
public Result updateStudent(@RequestBody Student student){
studentService.updateStudent(student);
return Result.success("修改成功," + student);
}
/**
* 删除学生信息
*/
@GetMapping("/del")
public Result delStudent(String id){
studentService.delStudent(id);
return Result.success("删除学生成功," + id);
}
/**
* 查询学生信息
*/
@GetMapping("/query")
public Result queryStudent(){
List<Student> studentList = studentService.queryStudent();
return Result.success(studentList);
}
}
-
4.3.3 创建StudentService接口
com.wfit.boot.service目录下创建StudentService.java。
public interface StudentService {
public void saveStudent(Student student);
public void updateStudent(Student student);
public void delStudent(String id);
public List<Student> queryStudent();
}
-
4.3.4 创建StudentServiceImpl类
com.wfit.boot.service.impl目录下创建StudentServiceImpl.java。
@Service
public class StudentServiceImpl implements StudentService {
@Resource
private StudentMapper studentMapper;
@Override
public void saveStudent(Student student) {
studentMapper.saveStudent(student);
}
@Override
public void updateStudent(Student student) {
studentMapper.updateStudent(student);
}
@Override
public void delStudent(String id) {
studentMapper.delStudent(id);
}
@Override
public List<Student> queryStudent() {
return studentMapper.queryStudent();
}
}
-
4.3.5 创建StudentMapper接口
com.wfit.boot.mapper目录下创建StudentMapper.java。
@Mapper
public interface StudentMapper {
public void saveStudent(Student student);
public void updateStudent(Student student);
public void delStudent(String id);
public List<Student> queryStudent();
}
-
4.3.6 创建StudentMapper.xml文件
resources.mapper目录下创建StudentMapper.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.wfit.boot.mapper.StudentMapper">
<!--新增学生信息-->
<insert id="saveStudent" parameterType="com.wfit.boot.pojo.Student">
insert into t_student values(
#{id},
#{name},
#{age},
#{sex},
#{birthday},
#{idCard},
#{phone}
)
</insert>
<!--修改学生信息-->
<update id="updateStudent" parameterType="com.wfit.boot.pojo.Student">
update t_student
set name = #{name}, age = #{age}
where id = #{id}
</update>
<!--删除学生信息-->
<delete id="delStudent" parameterType="java.lang.String">
delete from t_student where id = #{id}
</delete>
<!--查询学生信息-->
<select id="queryStudent" resultType="com.wfit.boot.pojo.Student">
select *
from t_student
</select>
</mapper>
4.4 Book模块
-
4.4.1 创建Book实体类
com.wfit.boot.pojo目录下创建Book.java。
@Data
public class Book implements Serializable {
private String id; //图书ISBN
private String name;
private String category;
private String press;
private String author;
private int num;
private String state; //图书状态(0:正常,1:已下架)
}
-
4.4.2 创建BookController类
com.wfit.boot.controller目录下创建BookController.java。
/**
* 维护图书信息
*/
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
/**
* 新增图书信息
*/
@PostMapping("/add")
public Result addBook(@RequestBody Book book) {
try{
bookService.addBook(book);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success("新增图书成功," + book);
}
/**
* 修改图书信息
*/
@PostMapping("/update")
public Result updateBook(@RequestBody Book book){
try{
bookService.updateBook(book);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success("修改图书成功," + book);
}
/**
* 下架图书信息
*/
@GetMapping("/remove")
public Result removeBook(String bookId){
try{
bookService.removeBook(bookId);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success("下架图书成功," + bookId);
}
/**
* 查询图书信息
*/
@PostMapping("/query")
public Result queryBook(@RequestBody Book book) {
List<Book> bookList;
try{
bookList = bookService.queryBook(book);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success(bookList);
}
}
-
4.4.3 创建BookService接口
com.wfit.boot.service目录下创建BookService.java。
public interface BookService {
public void addBook(Book book) throws Exception;
public void updateBook(Book book) throws Exception;
public void removeBook(String id) throws Exception;
public List<Book> queryBook(Book book) throws Exception;
}
-
4.4.4 创建BookServiceImpl类
com.wfit.boot.service.impl目录下创建BookServiceImpl.java。
@Service
public class BookServiceImpl implements BookService {
@Resource
private BookMapper bookMapper;
@Resource
private BorrowMapper borrowMapper;
/**
* 新增图书
* @param book
*/
@Override
public void addBook(Book book) throws Exception{
//查询图书是否已存在
int num = bookMapper.queryBookNum(book.getId());
if(num >= 0){ //如果已存在则更新图书数量
bookMapper.updateBookNum(book.getId(),book.getNum());
}else { //否则,新增图书信息
book.setState(Constants.BOOK_STATE_NORMAL);
bookMapper.saveBook(book);
}
}
/**
* 修改图书
* @param book
*/
@Override
public void updateBook(Book book) throws Exception{
bookMapper.updateBook(book);
}
/**
* 下架图书
* @param bookId
*/
@Override
public void removeBook(String bookId) throws Exception{
//下架图书校验是否有正在借阅中的图书
int num = borrowMapper.queryBorrowNum(null,bookId);
if(num > 0){
throw new Exception("尚有未归还图书,不允许下架操作!");
}else{ //执行下架操作
bookMapper.removeBook(bookId);
}
}
/**
* 查询图书信息
* @param book
* @return
* @throws Exception
*/
@Override
public List<Book> queryBook(Book book) throws Exception {
return bookMapper.queryBook(book);
}
}
-
4.4.5 创建BookMapper接口
com.wfit.boot.mapper目录下创建BookMapper.java。
@Mapper
public interface BookMapper {
/**
* 查询图书数量
* @param id
* @return
*/
public int queryBookNum(String id);
/**
* 新增图书
* @param book
*/
public void saveBook(Book book);
/**
* 更新图书库存
* @param id
* @param num
*/
public void updateBookNum(@Param("id") String id,@Param("num") int num);
/**
* 修改图书
* @param book
*/
public void updateBook(Book book);
/**
* 下架图书
* @param id
*/
public void removeBook(String id);
/**
* 查询图书信息
* @param book
* @return
*/
public List<Book> queryBook(Book book);
}
-
4.4.6 创建BookMapper.xml文件
resources.mapper目录下创建BookMapper.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.wfit.boot.mapper.BookMapper">
<!--查询图书库存-->
<select id="queryBookNum" parameterType="java.lang.String" resultType="java.lang.Integer">
select if(count(*) = 0 , -1 , sum(num)) num
from t_book
where id = #{id}
and state = '0'
</select>
<!--新增图书信息-->
<insert id="saveBook" parameterType="com.wfit.boot.pojo.Book">
insert into t_book values(
#{id},
#{name},
#{category},
#{author},
#{press},
#{num},
#{state}
)
</insert>
<!--更新图书库存-->
<update id="updateBookNum">
update t_book
set num = num + #{num}
where id = #{id}
and state = '0'
</update>
<!--修改图书信息-->
<update id="updateBook" parameterType="com.wfit.boot.pojo.Book">
update t_book
<set>
<if test="name != null and name != ''">
name = #{name},
</if>
<if test="category != null and category != ''">
category = #{category},
</if>
<if test="press != null and press != ''">
press = #{press},
</if>
<if test="author != null and author != ''">
author = #{author},
</if>
<if test="num != null">
num = #{num},
</if>
</set>
where id = #{id}
and state = '0'
</update>
<!--下架图书-->
<update id="removeBook" parameterType="java.lang.String">
update t_book
set state = '1',num = 0
where id = #{id}
and state = '0'
</update>
<!--查询图书信息-->
<select id="queryBook" parameterType="com.wfit.boot.pojo.Book"
resultType="com.wfit.boot.pojo.Book">
select *
from t_book
<where>
state = '0'
<if test="id != null and id != ''">
and id like concat('%',#{id},'%')
</if>
<if test="name != null and name != ''">
and name like concat('%',#{name},'%')
</if>
<if test="author != null and author != ''">
and author like concat('%',#{author},'%')
</if>
<if test="press != null and press != ''">
and press like concat('%',#{press},'%')
</if>
</where>
</select>
</mapper>
4.5 Borrow模块
-
4.5.1 创建Borrow实体类
com.wfit.boot.pojo目录下创建Borrow.java。
@Data
public class Borrow implements Serializable {
private String id; //借阅记录ID
private String studentId; //学生学号
private String bookId; //图书ISBN
private String borrowTime; //借阅时间
private String borrowState; //借阅状态(0借阅中,1已归还)
private String backTime; //归还时间
//借阅图书详细信息
private String bookName; //图书名称
//学生详细信息
private String studentName; //学生姓名
}
-
4.5.2 创建BorrowController类
com.wfit.boot.controller目录下创建BorrowController.java。
/**
* 借阅图书
*/
@RestController
@RequestMapping("/borrow")
public class BorrowController {
@Autowired
private BorrowService borrowService;
/**
* 借阅图书
*/
@PostMapping("/borrow")
public Result borrowBook(@RequestBody Borrow borrow){
try {
borrowService.borrowBook(borrow);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success("借阅图书成功," + borrow);
}
/**
* 归还图书
*/
@PostMapping("/back")
public Result backBook(@RequestBody Borrow borrow){
try {
borrowService.backBook(borrow);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success("归还图书成功," + borrow);
}
/**
* 查询借阅记录
* @param borrow
* @return
*/
@PostMapping("/query")
public Result queryBorrow(@RequestBody Borrow borrow){
List<Borrow> borrowList;
try {
borrowList = borrowService.queryBorrowInfo(borrow);
}catch (Exception e){
return Result.error(e.getMessage());
}
return Result.success(borrowList);
}
}
-
4.5.3 创建BorrowService接口
com.wfit.boot.service目录下创建BorrowService.java。
public interface BorrowService {
public void borrowBook(Borrow borrow) throws Exception;
public void backBook(Borrow borrow) throws Exception;
public List<Borrow> queryBorrowInfo(Borrow borrow) throws Exception;
}
-
4.5.4 创建BorrowServiceImpl类
com.wfit.boot.service.impl目录下创建BorrowServiceImpl.java。
@Service
public class BorrowServiceImpl implements BorrowService {
@Resource
private BookMapper bookMapper;
@Resource
private BorrowMapper borrowMapper;
/**
* 借阅图书
* @param borrow
* @throws Exception
*/
@Override
public void borrowBook(Borrow borrow) throws Exception{
//查询图书是否存在以及是否库存充足
int num = bookMapper.queryBookNum(borrow.getBookId());
if(num > 0){ //如果图书存在
//借阅图书,库存数量更新 -1
bookMapper.updateBookNum(borrow.getBookId(),-1);
//新增借阅记录
borrow.setId(UuidUtil.getUUID());
borrow.setBorrowTime(DateTimeUtil.now());
borrow.setBorrowState(Constants.BORROW_STATE_BORROW);
borrowMapper.borrowBook(borrow);
}else { //否则,返回图书不存在或数量不足不能借阅
throw new Exception("图书不存在或数量不足!");
}
}
/**
* 归还图书
* @param borrow
* @throws Exception
*/
@Override
public void backBook(Borrow borrow) throws Exception {
//查询此学生是否有借阅图书
int num = borrowMapper.queryBorrowNum(borrow.getStudentId(),borrow.getBookId());
if(num <= 0){
throw new Exception("不存在未归还图书信息!");
}else{ //执行归还图书操作
//归还图书,库存数量更新 +1
bookMapper.updateBookNum(borrow.getBookId(),1);
//修改借阅记录为归还状态
borrow.setBorrowState(Constants.BORROW_STATE_BACK);
borrow.setBackTime(DateTimeUtil.now());
borrowMapper.backBook(borrow);
}
}
/**
* 查询借阅记录
* @param borrow
* @throws Exception
*/
@Override
public List<Borrow> queryBorrowInfo(Borrow borrow) throws Exception {
return borrowMapper.queryBorrowInfo(borrow);
}
}
-
4.5.5 创建BorrowMapper接口
com.wfit.boot.mapper目录下创建BorrowMapper.java。
@Mapper
public interface BorrowMapper {
public void borrowBook(Borrow borrow);
public void backBook(Borrow borrow);
public int queryBorrowNum(@Param("studentId") String studentId,@Param("bookId") String bookId);
public List<Borrow> queryBorrowInfo(Borrow borrow);
}
-
4.5.6 创建BorrowMapper.xml文件
resources.mapper目录下创建BorrowMapper.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.wfit.boot.mapper.BorrowMapper">
<!--借阅记录信息-->
<resultMap id="BorrowMap" type="com.wfit.boot.pojo.Borrow">
<id column="id" property="id"/>
<result column="sid" property="studentId"/>
<result column="bid" property="bookId"/>
<result column="sname" property="studentName"/>
<result column="bname" property="bookName"/>
<result column="borrow_time" property="borrowTime"/>
<result column="borrow_state" property="borrowState"/>
<result column="back_time" property="backTime"/>
</resultMap>
<!--查询借阅图书数量-->
<select id="queryBorrowNum" resultType="java.lang.Integer">
select count(*) num
from t_borrow
where borrow_state = '0'
<if test="studentId != null and studentId !=''">
and sid = #{studentId}
</if>
<if test="bookId != null and bookId !=''">
and bid = #{bookId}
</if>
</select>
<!--新增借阅图书记录-->
<insert id="borrowBook" parameterType="com.wfit.boot.pojo.Borrow">
insert into t_borrow(id,sid,bid,borrow_time,borrow_state) values(
#{id},
#{studentId},
#{bookId},
#{borrowTime},
#{borrowState}
)
</insert>
<!--修改借阅记录为归还状态-->
<update id="backBook" parameterType="com.wfit.boot.pojo.Borrow">
update t_borrow
set borrow_state = #{borrowState}, back_time = #{backTime}
where sid = #{studentId}
and bid = #{bookId}
</update>
<!--查询借阅记录信息-->
<select id="queryBorrowInfo" parameterType="com.wfit.boot.pojo.Borrow" resultMap="BorrowMap">
select t.id,
t.sid,
t.bid,
b.name bname,
s.name sname,
t.borrow_time,
t.borrow_state,
t.back_time
from t_borrow t,t_book b,t_student s
where t.bid = b.id
and t.sid = s.id
<if test="studentId != null and studentId !=''">
and t.sid = #{studentId}
</if>
</select>
</mapper>
五、案例测试
5.1 测试新增图书信息
5.2 测试修改图书信息
5.3 测试下架图书信息
5.4 测试查询图书信息
5.5 测试借阅图书
5.6 测试归还图书