SpringMVC + Spring + MyBatis 整合(三)

接着SpringMVC + Spring + MyBatis 整合(二)


SSM框架应用实例(图书管理系统)

一开始想就这样结束教程,但是发现其实很多人都还不会把这个SSM框架用起来,特别是mybatis部分。那我现在就以最常见的“图书管理系统”中【查询图书】和【预约图书】业务来做一个demo吧!

首先新建数据库名为ssm,再创建两张表:图书表book和预约图书表appointment,并且为book表初始化一些数据,sql如下。

ssm.sql

-- 创建图书表
CREATE TABLE book(
	book_id BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '图书ID',
	name VARCHAR(100) NOT NULL COMMENT '图书名称',
	number int(11) NOT NULL COMMENT '馆藏数量',
	PRIMARY KEY(book_id)
)ENGINE=INNODB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8 COMMENT '图书表';

-- 初始化图书数据
INSERT INTO book (book_id, name, number)
VALUES
	(1000, 'Java程序设计', 10),
	(1001, '数据结构', 10),
	(1002, '设计模式', 10),
	(1003, '编译原理', 10);
	
-- 创建预约图书表
CREATE TABLE appointment(
	book_id BIGINT(20) NOT NULL COMMENT '图书ID',
	student_id BIGINT(20) 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 '预约图书表'

entity包中添加两个对应的实体,图书实体Book.java和预约图书实体Appointment.java

Book.java

package com.ray.entity;

/**
 * @author Ray
 * @date 2018/5/2 0002
 * 图书类
 */
public class Book {

    private long bookId; // 图书ID
    private String name; // 图书名称
    private int number; // 馆藏数量

    // 构造方法,getter和setter方法,toString方法
    public Book() {
    }

    public Book(long bookId, String name, int number) {
        this.bookId = bookId;
        this.name = name;
        this.number = number;
    }

    public long getBookId() {
        return bookId;
    }

    public void setBookId(long bookId) {
        this.bookId = bookId;
    }

    public String getName() {
        return name;
    }

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

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bookId=" + bookId +
                ", name='" + name + '\'' +
                ", number=" + number +
                '}';
    }
}

Appointment.java

package com.ray.entity;

import java.util.Date;

/**
 * @author Ray
 * @date 2018/5/2 0002\
 * 预约图书实体
 */
public class Appointment {

    private long bookId; // 图书ID
    private long studentId; // 学号
    private Date appointTime; // 预约时间

    // 多对一的复合属性
    private Book book; // 图书实体

    // 构造方法,getter和setter方法,toString方法
    public Appointment() {
    }

    public Appointment(long bookId, long studentId, Date appointTime, Book book) {
        this.bookId = bookId;
        this.studentId = studentId;
        this.appointTime = appointTime;
        this.book = book;
    }

    public long getBookId() {
        return bookId;
    }

    public void setBookId(long bookId) {
        this.bookId = bookId;
    }

    public long getStudentId() {
        return studentId;
    }

    public void setStudentId(long studentId) {
        this.studentId = studentId;
    }

    public Date getAppointTime() {
        return appointTime;
    }

    public void setAppointTime(Date appointTime) {
        this.appointTime = appointTime;
    }

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    @Override
    public String toString() {
        return "Appointment{" +
                "bookId=" + bookId +
                ", studentId=" + studentId +
                ", appointTime=" + appointTime +
                ", book=" + book +
                '}';
    }
}

在dao包新建 接口 BookDao.java 和 Appointment.java

BookDao.java

扫描二维码关注公众号,回复: 124412 查看本文章
package com.ray.dao;

import com.ray.entity.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * @author Ray
 * @date 2018/5/2 0002
 */
public interface BookDao {

    /**
     * 通过ID查询单本图书
     * @param id
     * @return
     */
    Book queryById(long id);

    /**
     * 查询所有图书
     * @param offset 查询起始位置
     * @param limit 查询条数
     * @return
     */
    List<Book> queryAll(@Param("offset") int offset, @Param("limit") int limit);

    /**
     * 减少馆藏数量
     * @param bookId
     * @return 如果影响行数等于>1,表示更新的记录行数
     */
    int reduceNumber(long bookId);
}

AppointmentDao.java

package com.ray.dao;

import com.ray.entity.Appointment;
import org.apache.ibatis.annotations.Param;

/**
 * @author Ray
 * @date 2018/5/2 0002
 */
public interface AppointmentDao {

    /**
     * 插入预约图书记录
     * @param bookId
     * @param studentId
     * @return 插入的行数
     */
    int insertAppointment(@Param("bookId") long bookId, @Param("studentId") long studentId);

    /**
     * 通过主键查询预约图书记录,并且携带图书实体
     * @param bookId
     * @param studentId
     * @return
     */
    Appointment queryByKeyWithBook(@Param("bookId") long bookId, @Param("studentId") long studentId);
}
提示 :这里为什么要给方法的参数添加 @Param 注解呢?是因为该方法有两个或以上的参数,一定要加,不然mybatis识别不了。上面的 BookDao 接口的 queryById 方法和 reduceNumber 方法只有一个参数 book_id ,所以可以不用加  @Param 注解,当然加了也无所谓~

注意,这里不需要实现dao接口不用编写daoImpl, mybatis会给我们动态实现,但是我们需要编写相应的mapper。 在mapper目录里新建两个文件BookDao.xmlAppointmentDao.xml,分别对应上面两个dao接口,代码如下。

BookDao.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.ray.dao.BookDao">
    <!-- 目的:为dao接口方法提供sql语句配置 -->
    <select id="queryById" resultType="Book" parameterType="long">
      <!-- 具体的sql语句 -->
        SELECT
                book_id,
                name,
                number
        FROM
                book
        WHERE
                book_id = #{id}
    </select>

    <select id="queryAll" resultType="Book">
        SELECT
                book_id,
                name,
                number
        FROM
                book
        ORDER BY
                book_id
        LIMIT #{offset}, #{limit}
    </select>

    <update id="reduceNumber">
        UPDATE
                book
        SET
                number = number - 1
        WHERE
                book_id = #{bookId}
        AND
                number > 0
    </update>
</mapper>

AppointmentDao.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.ray.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属性 -->
        <!-- 可以自由控制SQL -->
        SELECT
                a.book_id,
                a.student_id,
                a.appoint_time,
                b.book_id "book.book_id",
                b.name "book.name",
                b.number "book.number"
        FROM
                appointment a
        INNER JOIN
                book b
        ON
                a.book_id = b.book_id
        WHERE
                a.book_id = #{bookId}
        AND
                a.student_id = #{studentId}
    </select>
</mapper>
mapper总结 namespace 是该xml对应的接口全名, select update 中的 id 对应方法名, resultType 是返回值类型, parameterType 是参数类型(这个其实可选),最后 #{...} 中填写的是方法的参数,看懂了是不是很简单!!我也这么觉得~ 还有一个小技巧要交给大家,就是在返回 Appointment 对象包含了一个属性名为 book 的Book对象,那么可以使用 "book.属性名" 的方式来取值,看上面 queryByKeyWithBook 方法的sql。

dao层写完了,接下来test对应的package写我们测试方法吧。 因为我们之后会写很多测试方法,在测试前需要让程序读入spring-dao和mybatis等配置文件,所以我这里就抽离出来一个BaseTest类,只要是测试方法就继承它,这样那些繁琐的重复的代码就不用写那么多了~

BaseTest.java

package com.ray;

import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @author Ray
 * @date 2018/5/2 0002
 * 配置spring和junit整合,junit启动时加载springIOC容器 spring-test,junit
 */
@RunWith(SpringJUnit4ClassRunner.class)
// 告诉junit spring配置文件
@ContextConfiguration({"classpath:spring/spring-dao.xml", "classpath:spring/spring-service.xml"})
public class BaseTest {
}

因为spring-serviceservice层的测试中会时候到,这里也一起引入算了!

新建BookDaoTest.javaAppointmentDaoTest.java两个dao测试文件。

BookDaoTest.java

package com.ray;

import com.ray.dao.BookDao;
import com.ray.entity.Book;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

/**
 * @author Ray
 * @date 2018/5/2 0002
 */
public class BookDaoTest extends BaseTest {

    @Autowired
    private BookDao bookDao;

    @Test
    public void testQueryById(){
        long bookId = 1000;
        Book book = bookDao.queryById(bookId);
        System.out.println(book);
    }

    @Test
    public void testQueryAll(){
        List<Book> books = bookDao.queryAll(0,4);
        for (Book book :
                books) {
            System.out.println(book);
        }
    }

    @Test
    public void testReduceNumber(){
        long bookId = 1000;
        int update = bookDao.reduceNumber(bookId);
        System.out.println("update= " + update);

        Book book = bookDao.queryById(bookId);
        System.out.println(book);
    }
}

BookDaoTest测试结果

    testQueryById


    testQueryAll 


    testReduceNumber



AppointmentDaoTest.java

package com.ray;

import com.ray.dao.AppointmentDao;
import com.ray.entity.Appointment;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * @author Ray
 * @date 2018/5/2 0002
 */
public class AppointmentDaoTest extends BaseTest {

    @Autowired
    private AppointmentDao appointmentDao;

    @Test
    public void testInsertAppointment(){
        long bookId = 1000;
        long studentId = 1234567890L;
        int insert = appointmentDao.insertAppointment(bookId, studentId);
        System.out.println("insert= " + insert);
    }

    @Test
    public void testQueryByKeyWithBook(){
        long bookId = 1000;
        long studentId = 1234567890L;
        Appointment appointment = appointmentDao.queryByKeyWithBook(bookId, studentId);
        System.out.println(appointment);
        System.out.println(appointment.getBook());
    }
}

AppointmentDaoTest测试结果

    testInsertAppointment


    testQueryByKeyWithBook


到此,我们的SSM框架整合配置,与应用实例部分已经结束了,我把所有源码和jar包一起打包放在了我的GitHub上,需要的可以去下载

猜你喜欢

转载自blog.csdn.net/q343509740/article/details/80166269