前言
前两篇文章已经讲过了如何准备项目框架以及如何整合 SSM,今天就来具体看看如何实现吧。
以下附上前两篇文章的传送门:
准备数据库
新建数据库 bookmanager,然后创建两张表:图书表 book 和 预约图书表 appointment;
-- 建数据库CREATE DATABASE `bookmanager`;
-- 创建图书表CREATE TABLE `book` (`book_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '图书ID',`name` varchar(100) NOT NULL COMMENT '图书名称',`number` int(11) NOT NULL COMMENT '馆藏数量',PRIMARY KEY (`book_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='图书表';-- 插入数据INSERT INTO `book`(`book_id`, `name`, `number`) VALUES (1, "Effective Java", 10),(2, "算法", 10),(3, "MySQL 必知必会", 10);
-- 创建预约图书表CREATE TABLE `appointment` (`book_id` int(11) NOT NULL COMMENT '图书ID',`student_id` int(11) NOT NULL COMMENT '学号',`appoint_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '预约时间' ,PRIMARY KEY (`book_id`, `student_id`),INDEX `idx_appoint_time` (`appoint_time`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='预约图书表';
实体类编写
数据库准备好之后,就可以给对应表创建实体类,创建实体类之前,我们可以在 pom.xml 中引入 lombok 依赖,减少代码的编写;
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version></dependency>
Book.java
package com.cunyu.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;/*** @author : cunyu* @version : 1.0* @className : Book* @date : 2020/7/23 15:53* @description : Book 实体类*/@Data@AllArgsConstructor@NoArgsConstructorpublic class Book {private int bookId;private String name;private int number;}
Appointment.java
package com.cunyu.pojo;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.util.Date;/*** @author : cunyu* @version : 1.0* @className : Appointment* @date : 2020/7/23 15:57* @description : Appointment 实体类*/@Data@NoArgsConstructor@AllArgsConstructorpublic class Appointment {private int bookId;private int studentId;private Date appointTime;private Book book;}
dao 接口类编写
BookDao.java
package com.cunyu.dao;import com.cunyu.pojo.Book;import org.apache.ibatis.annotations.Param;import java.util.List;/*** @InterfaceName : BookDao* @Author : cunyu* @Date : 2020/7/23 16:02* @Version : 1.0* @Description : Book 接口**/public interface BookDao {/*** @param bookId 图书 id* @return 对应 id 的图书* @description 根据图书 id 查找对应图书* @date 2020/7/23 16:04* @author cunyu1943* @version 1.0*/Book queryById(@Param("bookId") int bookId);/*** @param offset 查询起始位置* @param limit 查询条数* @return 查询出的所有图书列表* @description 查询所有图书* @date 2020/7/23 16:08* @author cunyu1943* @version 1.0*/List<Book> queryAll(@Param("offset") int offset, @Param("limit") int limit);/*** @param bookId 图书 id* @return 更新的记录行数* @description 借阅后更新馆藏* @date 2020/7/23 16:09* @author cunyu1943* @version 1.0*/int reduceNumber(@Param("bookId") int bookId);}
AppointmentDao.java
package com.cunyu.dao;import com.cunyu.pojo.Appointment;import org.apache.ibatis.annotations.Param;/*** @InterfaceName : AppointmentDao* @Author : cunyu* @Date : 2020/7/23 16:03* @Version : 1.0* @Description : Appointment 接口**/public interface AppointmentDao {/*** @param bookId 图书 id* @param studentId 学生 id* @return 插入的行数* @description 插入预约图书记录* @date 2020/7/23 16:13* @author cunyu1943* @version 1.0*/int insertAppointment(@Param("bookId") int bookId, @Param("studentId") int studentId);/*** @param bookId 图书 id* @param studentId 学生 id* @return* @description 通过主键查询预约图书记录,并且携带图书实体* @date 2020/7/23 16:16* @author cunyu1943* @version 1.0*/Appointment queryByKeyWithBook(@Param("bookId") int bookId, @Param("studentId") int studentId);}
mapper 编写
编写好 dao 接口之后,并不需要我们自己去实现,MyBatis 会给我们动态实现,但是需要我们配置相应的 mapper。在 src/main/resources/mapper 下新建 BookDao.xml 和 AppointmentDao.xml,用于对应上面的 dao 接口;
BookDao.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.cunyu.dao.BookDao"><select id="queryById" resultType="Book" parameterType="int">SELECT book_id, name, numberFROM bookWHERE book_id = #{bookId}</select><select id="queryAll" resultType="Book">SELECT *FROM bookORDER BY book_idLIMIT #{offset},#{limit}</select><update id="reduceNumber">UPDATE bookSET number = number - 1WHERE book_id = #{bookId}AND number > 0</update></mapper>
AppointmentDao.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.cunyu.dao.AppointmentDao"><insert id="insertAppointment"><!-- ignore 主键冲突,报错 -->INSERT ignore INTO appointment (book_id, student_id) VALUES (#{bookId}, #{studentId})</insert><select id="queryByKeyWithBook" resultType="Appointment"><!-- 告知MyBatis 把结果映射到 Appointment 的同时映射 Book 属性 -->SELECTappointment.book_id,appointment.student_id,appointment.appoint_time,book.book_id "book.book_id",book.`name` "book.name",book.number "book.number"FROMappointmentINNER JOIN book ON appointment.book_id = book.book_idWHEREappointment.book_id = #{bookId}AND appointment.student_id = #{studentId}</select></mapper>
测试
经过 准备数据库 -> 实体类编写 -> 接口类编写 -> mapper 配置 这一套流程之后,我们就可以进行模块化测试了,看看我们的接口是否成功实现。
BookDaoTest.java
package com.cunyu.dao;import com.cunyu.pojo.Book;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import java.util.List;/*** @author : cunyu* @version : 1.0* @className : BookDaoTest* @date : 2020/7/23 18:02* @description : BookDao 测试类*/@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:spring/spring-*.xml")public class BookDaoTest {// 自动注入@Autowiredprivate BookDao bookDao;@Testpublic void testQueryById() {int bookId = 1;Book book = bookDao.queryById(bookId);System.out.println("ID 对应的图书信息:" + book);}@Testpublic void testQueryAll() {List<Book> bookList = bookDao.queryAll(0, 3);System.out.println("所有图书信息:");for (Book book : bookList) {System.out.println(book);}}@Testpublic void testReduceNumber() {int bookId = 3;int update = bookDao.reduceNumber(bookId);System.out.println("update = " + update);}}
运行两次测试后,数据库的结果如下图:

AppointmentDaoTest.java
package com.cunyu.dao;import com.cunyu.pojo.Appointment;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** @author : cunyu* @version : 1.0* @className : AppointmentDaoTest* @date : 2020/7/23 18:21* @description : AppointmentDao 测试*/@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:spring/spring-*.xml")public class AppointmentDaoTest {@AutowiredAppointmentDao appointmentDao;@Testpublic void testInsertAppointment() {int bookId = 2;int studentId = 18301333;int insert = appointmentDao.insertAppointment(bookId, studentId);System.out.println("Insert = " + insert);}@Testpublic void testQueryByKeyWithBook(){int bookId = 2;int studentId = 18301333;Appointment appointment=appointmentDao.queryByKeyWithBook(bookId,studentId);System.out.println(appointment);System.out.println(appointment.getBook());}}
预约后,appointment 表中插入记录;

总结
至此,我们做的工作总结下来主要有如下几点:
- 设计数据库
- 创建实体类
- 编写 dao 接口类
- 编写 dao 接口对应 mapper,交由 MyBatis 动态实现
- 对 dao 接口方法实现进行测试
好了,图书管理系统第一阶段到此就结束了,下一步我们就可以对其进行优化,并编写 service 层和 controller 层代码了。
