前言

前两篇文章已经讲过了如何准备项目框架以及如何整合 SSM,今天就来具体看看如何实现吧。

以下附上前两篇文章的传送门:

SSM 图书管理系统:项目框架结构搭建

SSM 图书管理系统:整合 SSM

准备数据库

新建数据库 bookmanager,然后创建两张表:图书表 book 和 预约图书表 appointment

  1. -- 建数据库
  2. CREATE DATABASE `bookmanager`;
  1. -- 创建图书表
  2. CREATE TABLE `book` (
  3. `book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '图书ID',
  4. `name` varchar(100) NOT NULL COMMENT '图书名称',
  5. `number` int(11) NOT NULL COMMENT '馆藏数量',
  6. PRIMARY KEY (`book_id`)
  7. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='图书表';
  8. -- 插入数据
  9. INSERT INTO `book`(`book_id`, `name`, `number`) VALUES (1, "Effective Java", 10),(2, "算法", 10),(3, "MySQL 必知必会", 10);
  1. -- 创建预约图书表
  2. CREATE TABLE `appointment` (
  3. `book_id` int(11) NOT NULL COMMENT '图书ID',
  4. `student_id` int(11) NOT NULL COMMENT '学号',
  5. `appoint_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '预约时间' ,
  6. PRIMARY KEY (`book_id`, `student_id`),
  7. INDEX `idx_appoint_time` (`appoint_time`)
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='预约图书表';

实体类编写

数据库准备好之后,就可以给对应表创建实体类,创建实体类之前,我们可以在 pom.xml 中引入 lombok 依赖,减少代码的编写;

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <version>1.18.12</version>
  5. </dependency>

Book.java

  1. package com.cunyu.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. /**
  6. * @author : cunyu
  7. * @version : 1.0
  8. * @className : Book
  9. * @date : 2020/7/23 15:53
  10. * @description : Book 实体类
  11. */
  12. @Data
  13. @AllArgsConstructor
  14. @NoArgsConstructor
  15. public class Book {
  16. private int bookId;
  17. private String name;
  18. private int number;
  19. }

Appointment.java

  1. package com.cunyu.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import java.util.Date;
  6. /**
  7. * @author : cunyu
  8. * @version : 1.0
  9. * @className : Appointment
  10. * @date : 2020/7/23 15:57
  11. * @description : Appointment 实体类
  12. */
  13. @Data
  14. @NoArgsConstructor
  15. @AllArgsConstructor
  16. public class Appointment {
  17. private int bookId;
  18. private int studentId;
  19. private Date appointTime;
  20. private Book book;
  21. }

dao 接口类编写

BookDao.java

  1. package com.cunyu.dao;
  2. import com.cunyu.pojo.Book;
  3. import org.apache.ibatis.annotations.Param;
  4. import java.util.List;
  5. /**
  6. * @InterfaceName : BookDao
  7. * @Author : cunyu
  8. * @Date : 2020/7/23 16:02
  9. * @Version : 1.0
  10. * @Description : Book 接口
  11. **/
  12. public interface BookDao {
  13. /**
  14. * @param bookId 图书 id
  15. * @return 对应 id 的图书
  16. * @description 根据图书 id 查找对应图书
  17. * @date 2020/7/23 16:04
  18. * @author cunyu1943
  19. * @version 1.0
  20. */
  21. Book queryById(@Param("bookId") int bookId);
  22. /**
  23. * @param offset 查询起始位置
  24. * @param limit 查询条数
  25. * @return 查询出的所有图书列表
  26. * @description 查询所有图书
  27. * @date 2020/7/23 16:08
  28. * @author cunyu1943
  29. * @version 1.0
  30. */
  31. List<Book> queryAll(@Param("offset") int offset, @Param("limit") int limit);
  32. /**
  33. * @param bookId 图书 id
  34. * @return 更新的记录行数
  35. * @description 借阅后更新馆藏
  36. * @date 2020/7/23 16:09
  37. * @author cunyu1943
  38. * @version 1.0
  39. */
  40. int reduceNumber(@Param("bookId") int bookId);
  41. }

AppointmentDao.java

  1. package com.cunyu.dao;
  2. import com.cunyu.pojo.Appointment;
  3. import org.apache.ibatis.annotations.Param;
  4. /**
  5. * @InterfaceName : AppointmentDao
  6. * @Author : cunyu
  7. * @Date : 2020/7/23 16:03
  8. * @Version : 1.0
  9. * @Description : Appointment 接口
  10. **/
  11. public interface AppointmentDao {
  12. /**
  13. * @param bookId 图书 id
  14. * @param studentId 学生 id
  15. * @return 插入的行数
  16. * @description 插入预约图书记录
  17. * @date 2020/7/23 16:13
  18. * @author cunyu1943
  19. * @version 1.0
  20. */
  21. int insertAppointment(@Param("bookId") int bookId, @Param("studentId") int studentId);
  22. /**
  23. * @param bookId 图书 id
  24. * @param studentId 学生 id
  25. * @return
  26. * @description 通过主键查询预约图书记录,并且携带图书实体
  27. * @date 2020/7/23 16:16
  28. * @author cunyu1943
  29. * @version 1.0
  30. */
  31. Appointment queryByKeyWithBook(@Param("bookId") int bookId, @Param("studentId") int studentId);
  32. }

mapper 编写

编写好 dao 接口之后,并不需要我们自己去实现,MyBatis 会给我们动态实现,但是需要我们配置相应的 mapper。在 src/main/resources/mapper 下新建 BookDao.xmlAppointmentDao.xml,用于对应上面的 dao 接口;

BookDao.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.cunyu.dao.BookDao">
  6. <select id="queryById" resultType="Book" parameterType="int">
  7. SELECT book_id, name, number
  8. FROM book
  9. WHERE book_id = #{bookId}
  10. </select>
  11. <select id="queryAll" resultType="Book">
  12. SELECT *
  13. FROM book
  14. ORDER BY book_id
  15. LIMIT #{offset},#{limit}
  16. </select>
  17. <update id="reduceNumber">
  18. UPDATE book
  19. SET number = number - 1
  20. WHERE book_id = #{bookId}
  21. AND number > 0
  22. </update>
  23. </mapper>

AppointmentDao.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.cunyu.dao.AppointmentDao">
  6. <insert id="insertAppointment">
  7. <!-- ignore 主键冲突,报错 -->
  8. INSERT ignore INTO appointment (book_id, student_id) VALUES (#{bookId}, #{studentId})
  9. </insert>
  10. <select id="queryByKeyWithBook" resultType="Appointment">
  11. <!-- 告知MyBatis 把结果映射到 Appointment 的同时映射 Book 属性 -->
  12. SELECT
  13. appointment.book_id,
  14. appointment.student_id,
  15. appointment.appoint_time,
  16. book.book_id "book.book_id",
  17. book.`name` "book.name",
  18. book.number "book.number"
  19. FROM
  20. appointment
  21. INNER JOIN book ON appointment.book_id = book.book_id
  22. WHERE
  23. appointment.book_id = #{bookId}
  24. AND appointment.student_id = #{studentId}
  25. </select>
  26. </mapper>

测试

经过 准备数据库 -> 实体类编写 -> 接口类编写 -> mapper 配置 这一套流程之后,我们就可以进行模块化测试了,看看我们的接口是否成功实现。

BookDaoTest.java

  1. package com.cunyu.dao;
  2. import com.cunyu.pojo.Book;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.test.context.ContextConfiguration;
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  8. import java.util.List;
  9. /**
  10. * @author : cunyu
  11. * @version : 1.0
  12. * @className : BookDaoTest
  13. * @date : 2020/7/23 18:02
  14. * @description : BookDao 测试类
  15. */
  16. @RunWith(SpringJUnit4ClassRunner.class)
  17. @ContextConfiguration("classpath:spring/spring-*.xml")
  18. public class BookDaoTest {
  19. // 自动注入
  20. @Autowired
  21. private BookDao bookDao;
  22. @Test
  23. public void testQueryById() {
  24. int bookId = 1;
  25. Book book = bookDao.queryById(bookId);
  26. System.out.println("ID 对应的图书信息:" + book);
  27. }
  28. @Test
  29. public void testQueryAll() {
  30. List<Book> bookList = bookDao.queryAll(0, 3);
  31. System.out.println("所有图书信息:");
  32. for (Book book : bookList
  33. ) {
  34. System.out.println(book);
  35. }
  36. }
  37. @Test
  38. public void testReduceNumber() {
  39. int bookId = 3;
  40. int update = bookDao.reduceNumber(bookId);
  41. System.out.println("update = " + update);
  42. }
  43. }

运行两次测试后,数据库的结果如下图:

后端具体实现(上) - 图1

AppointmentDaoTest.java

  1. package com.cunyu.dao;
  2. import com.cunyu.pojo.Appointment;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.test.context.ContextConfiguration;
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  8. /**
  9. * @author : cunyu
  10. * @version : 1.0
  11. * @className : AppointmentDaoTest
  12. * @date : 2020/7/23 18:21
  13. * @description : AppointmentDao 测试
  14. */
  15. @RunWith(SpringJUnit4ClassRunner.class)
  16. @ContextConfiguration("classpath:spring/spring-*.xml")
  17. public class AppointmentDaoTest {
  18. @Autowired
  19. AppointmentDao appointmentDao;
  20. @Test
  21. public void testInsertAppointment() {
  22. int bookId = 2;
  23. int studentId = 18301333;
  24. int insert = appointmentDao.insertAppointment(bookId, studentId);
  25. System.out.println("Insert = " + insert);
  26. }
  27. @Test
  28. public void testQueryByKeyWithBook(){
  29. int bookId = 2;
  30. int studentId = 18301333;
  31. Appointment appointment=appointmentDao.queryByKeyWithBook(bookId,studentId);
  32. System.out.println(appointment);
  33. System.out.println(appointment.getBook());
  34. }
  35. }

预约后,appointment 表中插入记录;

后端具体实现(上) - 图2

总结

至此,我们做的工作总结下来主要有如下几点:

  1. 设计数据库
  2. 创建实体类
  3. 编写 dao 接口类
  4. 编写 dao 接口对应 mapper,交由 MyBatis 动态实现
  5. 对 dao 接口方法实现进行测试

好了,图书管理系统第一阶段到此就结束了,下一步我们就可以对其进行优化,并编写 service 层和 controller 层代码了。