SSM框架应用实例《图书管理系统》

针对上一篇文章详细介绍了SSM框架的搭建,这篇文章使用SSM给大家举一个栗子;希望对大家有所帮助。

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

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

schema.sql

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class = "language-sql hljs " >-- 创建图书表
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class = "language-java hljs " > package com.soecode.lyf.entity;
 
public class Book {
 
     private long bookId; // 图书ID
 
     private String name; // 图书名称
 
     private int number; // 馆藏数量
 
     // 省略构造方法,getter和setter方法,toString方法
 
}

Appointment.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class = "language-java hljs " > package com.soecode.lyf.entity;
 
import java.util.Date;
 
/**
  * 预约图书实体
  */
public class Appointment {
 
     private long bookId; // 图书ID
 
     private long studentId; // 学号
 
     private Date appointTime; // 预约时间
 
     // 多对一的复合属性
     private Book book; // 图书实体
 
     // 省略构造方法,getter和setter方法,toString方法
 
}

dao包新建接口BookDao.javaAppointment.java

BookDao.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class = "language-java hljs " > package com.soecode.lyf.dao;
 
import java.util.List;
 
import com.soecode.lyf.entity.Book;
 
public interface BookDao {
 
     /**
      * 通过ID查询单本图书
      *
      * @param id
      * @return
      */
     Book queryById( long id);
 
     /**
      * 查询所有图书
      *
      * @param offset 查询起始位置
      * @param limit 查询条数
      * @return
      */
     List queryAll( @Param ( "offset" ) int offset, @Param ( "limit" ) int limit);
 
     /**
      * 减少馆藏数量
      *
      * @param bookId
      * @return 如果影响行数等于>1,表示更新的记录行数
      */
     int reduceNumber( long bookId);
}

AppointmentDao.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class = "language-java hljs " > package com.soecode.lyf.dao;
 
import org.apache.ibatis.annotations.Param;
 
import com.soecode.lyf.entity.Appointment;
 
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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class = "language-xml hljs " >
 
"com.soecode.lyf.dao.BookDao" >
    
    
 
    
 
     "reduceNumber" >
         UPDATE book
         SET number = number - 1
         WHERE
             book_id = #{bookId}
         AND number > 0
    

AppointmentDao.xml

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class = "language-xml hljs " >
 
"com.soecode.lyf.dao.AppointmentDao" >
     "insertAppointment" >
        
         INSERT ignore INTO appointment (book_id, student_id)
         VALUES (#{bookId}, #{studentId})
    
 
    

mapper总结namespace是该xml对应的接口全名,selectupdate中的id对应方法名,resultType是返回值类型,parameterType是参数类型(这个其实可选),最后#{...}中填写的是方法的参数,看懂了是不是很简单!!我也这么觉得~ 还有一个小技巧要交给大家,就是在返回Appointment对象包含了一个属性名为book的Book对象,那么可以使用"book.属性名"的方式来取值,看上面queryByKeyWithBook方法的sql。


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

BaseTest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class = "language-java hljs " > package com.soecode.lyf;
 
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
/**
  * 配置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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class = "language-java hljs " > package com.soecode.lyf.dao;
 
import java.util.List;
 
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.soecode.lyf.BaseTest;
import com.soecode.lyf.entity.Book;
 
public class BookDaoTest extends BaseTest {
 
     @Autowired
     private BookDao bookDao;
 
     @Test
     public void testQueryById() throws Exception {
         long bookId = 1000 ;
         Book book = bookDao.queryById(bookId);
         System.out.println(book);
     }
 
     @Test
     public void testQueryAll() throws Exception {
         List books = bookDao.queryAll( 0 , 4 );
         for (Book book : books) {
             System.out.println(book);
         }
     }
 
     @Test
     public void testReduceNumber() throws Exception {
         long bookId = 1000 ;
         int update = bookDao.reduceNumber(bookId);
         System.out.println( "update=" + update);
     }
 
}

BookDaoTest测试结果

testQueryById
testQueryById

testQueryAll
testQueryAll

testReduceNumber
testReduceNumber

AppointmentDaoTest.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class = "language-java hljs " > package com.soecode.lyf.dao;
 
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
 
import com.soecode.lyf.BaseTest;
import com.soecode.lyf.entity.Appointment;
 
public class AppointmentDaoTest extends BaseTest {
 
     @Autowired
     private AppointmentDao appointmentDao;
 
     @Test
     public void testInsertAppointment() throws Exception {
         long bookId = 1000 ;
         long studentId = 12345678910L;
         int insert = appointmentDao.insertAppointment(bookId, studentId);
         System.out.println( "insert=" + insert);
     }
 
     @Test
     public void testQueryByKeyWithBook() throws Exception {
         long bookId = 1000 ;
         long studentId = 12345678910L;
         Appointment appointment = appointmentDao.queryByKeyWithBook(bookId, studentId);
         System.out.println(appointment);
         System.out.println(appointment.getBook());
     }
 
}

AppointmentDaoTest测试结果

testInsertAppointment
testInsertAppointment

testQueryByKeyWithBook
testQueryByKeyWithBook


嗯,到这里一切到很顺利~那么我们继续service层的编码吧~可能下面开始信息里比较大,大家要做好心理准备~

首先,在写我们的业务之前,我们先定义几个预约图书操作返回码的数据字典,我们这类使用枚举类,没听过的小伙伴要好好恶补一下了(我也是最近才学到的= =)

预约业务操作返回码说明

返回码 说明
1 预约成功
0 库存不足
-1 重复预约
-2 系统异常

新建一个包叫enums,在里面新建一个枚举类AppointStateEnum.java,用来定义预约业务的数据字典,没听懂没关系,我们直接看代码吧~是不是感觉有模有样了!

AppointStateEnum.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class = "language-java hljs " > package com.soecode.lyf.enums;
 
/**
  * 使用枚举表述常量数据字典
  */
public enum AppointStateEnum {
 
     SUCCESS( 1 , "预约成功" ), NO_NUMBER( 0 , "库存不足" ), REPEAT_APPOINT(- 1 , "重复预约" ), INNER_ERROR(- 2 , "系统异常" );
 
     private int state;
 
     private String stateInfo;
 
     private AppointStateEnum( int state, String stateInfo) {
   &

你可能感兴趣的:(java,java,web,SSM,框架)