正文索引 [隐藏]

开篇文章记录一下开(hua)发(shui)周期仨个半星期的Java开发期末设计。

项目一览

欢迎页面

欢迎页面

登录页面

登录页面

系统主页

系统主页

表单页面

表单页面

技术结构

技术结构

需求分析

我们选的题目是图书管理系统,没别的原因,就图它简单。因为别的事情很多,并没有过多的精力单独放在这一门课。先研究研究老师给的需求:

大致功能需求:
图书信息有书名、ISBN、分类号、作者、在管本数。借书人姓名、性别、学号、班级、专业。
1)系统用户管理:系统管理员的增删改查;
2)图书管理:新进图书信息录入、修改、删除、查询,按模板导入,导出;
3)为借书人办理注册即添加借书人,借书人的增删改查;
4)办理借书手续;
5)借书信息的查询、统计,统计信息可按班级、书类别条件筛选导出Excel表;

从这些描述里,我们可以概括出以下核心功能:
1. 管理员、图书、借书人、借阅记录的常规增删改查;
2. 借阅记录的统计、筛选、查询;
3. Excel导出表格内容。
在动手开发之前,一定要明确项目的核心功能,这样写起来脑子才不会乱,至少不会乱得很离谱。
贴一下项目最终的结构(为保证观感,已省略末级目录)。

BMS
├── LICENSE # 开源许可证
├── .gitignore # Git ignore配置文件
├── README.en.md # readme
├── README.md # readme
├── pom.xml # maven配置文件
└── src
    └── main
        ├── java
        │      └── com
        │              └── edisoncgh
        │                      ├── controller # 控制层
        │                      ├── dao # 数据库访问层
        │                      ├── pojo # 实体层
        │                      └── service # 服务层
        ├── resources # 配置文件目录
        │       └── mapper # Mybatis 相关mapper xml文件
        └── webapp
            ├── WEB-INF
            │      └── jsp # 页面目录
            ├── index # 主页面
            └── static # 前端资源目录

Git相关

Git仓库:传送门→
协同开发首选肯定是Git,考虑到GitHub的延迟问题,我们这次作业选择了gitee作为在线仓库平台。在往线上仓库push之前,记得先做gitignore配置,下面贴一下我们的gitignore。主要针对的还是idea和target目录,它们在每个人各自的环境下都可能不一样,所以没有共享的价值。

# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Dump file
*.stackdump

# Folder config file
[Dd]esktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp

# Windows shortcuts
*.lnk

#ignore target folder
target/
target/java_ssm_final_work.war

# ignore .idea folder
.idea/

环境配置

在明确了用户需求之后,就可以开始着手开发了。现行的开发流程大多是配置式开发,真正要我们码农上手写的内容其实不多,所以我们先从配置环境开始。

Maven

项目使用maven进行包管理,有了maven就不用进行繁琐地导包操作了,所以maven是肯定要第一个搞得。
Maven依赖:

<dependencies>

    <!-- test -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!-- test -->

    <!--数据库驱动-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.47</version>
    </dependency>
    <!--数据库驱动-->

    <!-- 数据库连接池 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
    </dependency>
    <!-- 数据库连接池 -->

    <!--Servlet & JSP -->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>jsp-api</artifactId>
      <version>2.2</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
      <version>1.2</version>
    </dependency>
    <!--Servlet & JSP -->

    <!--Mybatis-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.2</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>2.0.2</version>
    </dependency>
    <!--Mybatis-->

    <!--Spring-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>
    <!--Spring-->

    <!-- lombok -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
    </dependency>
    <!-- lombok -->

  </dependencies>

Maven过滤设置

 <!-- Maven 过滤设置 -->
    <resources>
      <resource>
        <directory>src/main/java</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
      <resource>
        <directory>src/main/resources</directory>
        <includes>
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>

数据库

完成了maven的配置之后,就可以开始考虑做数据库了。在做配置之前,首先建库建表。

create database javafinal;

create table books (
    bookName varchar(100) not null comment '书名',
    ISBN char(13) not null  comment 'ISBN',
    classNo tinyint not null  comment '分类号',
    bookAmount int(10) not null comment '在管本数',
    author varchar(50) not null comment '作者',
    primary key (ISBN)
) ENGINE=INNODB DEFAULT CHARSET=utf8

insert into books (bookName, ISBN, classNo, bookAmount, author) values
('数字电子技术', '7-111-01342-5', 1, 5, '刘全盛'),
('CAD/CAM原理与应用', '7-111-06372-4', 1, 7, '蔡颖'),
('微观经济学', '7-301-04868-8', 2, 10, '朱善利');

create table managers (
    managerName varchar(100) not null comment '管理员姓名',
    managerId int(10) comment '唯一id',
    managerPwd varchar(20) not null comment '登录密码',
    primary key(managerId)
) ENGINE=INNODB DEFAULT CHARSET=utf8

insert into managers (managerName, managerId, managerPwd) values
('李四', 2019100001,'123456'),
('张三', 2019100002, '123456');

create table users (
    loanNo int(10) not null comment '借书人学号',
    loanName varchar(100) comment '借书人姓名',
    sex varchar(10) not null comment '借书人性别',
    classNo int(8) not null comment '借书人班级',
    major varchar(100) not null comment '借书人专业',
    primary key (loanNo)
) ENGINE=INNODB DEFAULT CHARSET=utf8

create table loan (
    loanNo int(10) not null comment '借书人学号',
    ISBN char(13) comment 'ISBN',
    borrowDate datetime not null,
    primary key (loanNo, ISBN),
    foreign key (loanNo) references users(loanNo),
    foreign key (ISBN) references books(ISBN)
) ENGINE=INNODB DEFAULT CHARSET=utf8

create view myView(loanNo, loanName, classNo, major, ISBN, bookName, bookClassNo, borrowDate)
as select a.loanNo, a.loanName, a.classNo, a.major, b.ISBN, b.bookName, b.classNo, c.borrowDate
from users a, books b, loan c
where a.loanNo = c.loanNo and b.ISBN = c.ISBN;

库和表建完之后,就要配置mybatis了。我们没有采用传统的jdbc来做dao,这两者的优劣关系可以自行查阅相关知识,这里碍于篇幅不做展开。
Mybatis-config配置文件:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- 配置数据源 -->
    <typeAliases>
        <package name="com.edisoncgh.pojo"/>
    </typeAliases>
    <!-- 配置数据源 -->

    <!-- 绑定 -->
    <mappers>
        <mapper class="com.edisoncgh.dao.BookMapper"/>
        <mapper class="com.edisoncgh.dao.ManagerMapper"/>
        <mapper class="com.edisoncgh.dao.UserMapper"/>
        <mapper class="com.edisoncgh.dao.LoanMapper"/>
        <mapper class="com.edisoncgh.dao.ViewMapper"/>
    </mappers>
    <!-- 绑定 -->

</configuration>

database.properties数据库配置文件

jdbc.driver=com.mysql.jdbc.Driver
<!-- 这里的url一定要做编码规范,不然项目跑起来后显示不了中文 -->
<!-- 一般来说url问号后面跟的都是可选参数,我们这里只做了编码规范 -->
jdbc.url=jdbc:mysql://localhost:3306/javafinal?useUnicode=true&characterEncoding=utf8
jdbc.username=<!-- 你的数据库用户名 -->
jdbc.password=<!-- 你的数据库密码 -->

使用Mybatis做dao要配置相关的mapper文件并创建与之配套的mapper类,这里用最早期版本的图书实体对象做一个展示。
BookMapper.java:

package com.edisoncgh.dao;

// 别忘了引用图书对象
import com.edisoncgh.pojo.Book;

import java.util.List;

public interface BookMapper {
    //增加一本书
    int addBook(Books book);
    //删除一本书
    int deleteBookById(@Param("bookId") int id);
    //更新一本书
    int updateBook(Books book);
    //查询一本书
    Books findBookById(@Param("bookId")int id);
    //查询所有的书
    List<Books> findAllBook();
}

BookMapper.xml配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.edisoncgh.dao.BookMapper">

    <insert id="addBook" parameterType="Book">
        insert into javafinal.books (bookName, bookCounts, detail)
        values (#{bookName},#{bookCounts},#{detail});
    </insert>
    <delete id="deleteBookById" parameterType="int">
        delete from javafinal.books where bookID = #{bookId}
    </delete>
    <update id="updateBook" parameterType="Book">
        update javafinal.books
        set bookName = #{bookName},
        bookCounts = #{bookCounts},
        detail = #{detail}
        where bookID = #{bookID};
    </update>
    <select id="findBookById" resultType="Book">
        select * from javafinal.books where bookID = #{bookId};
    </select>
    <select id="findAllBook" resultType="Book">
        select * from javafinal.books;
    </select>

</mapper>

xml文件里的方法名要和java类里对应上,还要在config文件里做绑定:

<!-- 就像这样 -->
<mapper class="com.edisoncgh.dao.BookMapper"/>

以上是纯手工做mybatis的dao配置,事实上Mapper文件和类都可以通过Mybatis generator生成工具来自动生成,只不过要使用它需要先在maven里做一下引入。

      <!-- generator -->
      <plugin>
        <groupId>org.mybatis.generator</groupId>
        <artifactId>mybatis-generator-maven-plugin</artifactId>
        <version>1.3.5</version>
        <configuration>
          <configurationFile>src/main/resources/generatorConfig.xml
          </configurationFile>
          <overwrite>true</overwrite>
          <verbose>true</verbose>
        </configuration>
      </plugin>
      <!-- generator -->

generator插件在pom.xml里的位置是build->plugins->plugin。

Spring

由于我们这次是借助SSM体系进行开发,所以Spring的配置也必不可少。
spring整合service(spring-service.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- spring整合service -->

    <!-- 扫描service下的包 -->
    <context:component-scan base-package="com.edisoncgh.service"/>
    <!-- 扫描service下的包 -->

    <!-- 将BookServiceImpl注入到IOC容器中 -->
    <!-- 通过配置实现 -->
    <bean id="BookServiceImpl" class="com.edisoncgh.service.impl.BookServiceImpl">
        <property name="bookMapper" ref="bookMapper"/>
    </bean>

    <!-- 将ManagerServiceImpl注入到IOC容器中 -->
    <bean id="ManagerServiceImpl" class="com.edisoncgh.service.impl.ManagerServiceImpl">
        <property name="managerMapper" ref="managerMapper"/>
    </bean>

    <!-- 将UserServiceImpl注入到IOC容器中 -->
    <bean id="UserServiceImpl" class="com.edisoncgh.service.impl.UserServiceImpl">
        <property name="userMapper" ref="userMapper"/>
    </bean>

    <!-- 将LoanServiceImpl注入到IOC容器中 -->
    <bean id="LoanServiceImpl" class="com.edisoncgh.service.impl.LoanServiceImpl">
        <property name="loanMapper" ref="loanMapper"/>
    </bean>

    <!-- 将ViewServiceImpl注入到IOC容器中 -->
    <bean id="ViewServiceImpl" class="com.edisoncgh.service.impl.ViewServiceImpl">
        <property name="viewMapper" ref="viewMapper"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置事务管理器 -->

</beans>

spring整合MVC(spring-mvc.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置SpringMVC -->

    <!-- SpringMVC注解驱动 -->
    <mvc:annotation-driven/>
    <!-- SpringMVC注解驱动 -->

    <!-- 配置静态资源默认servlet-->
    <mvc:default-servlet-handler/>
    <!-- 配置静态资源默认servlet-->

    <!-- 配置jsp,显示ViewResolver视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 配置jsp,显示ViewResolver视图解析器 -->

    <!-- 扫描web相关的bean -->
    <context:component-scan base-package="com.edisoncgh.controller"/>
    <!-- 扫描web相关的bean -->

</beans>

spring整合mybatis(spring-dao.xml),使用c3p0连接池:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        Spring配置整合mybatis
        使用c3p0连接池
    -->

    <!-- 关联数据库配置文件 -->
    <context:property-placeholder location="classpath:database.properties"/>
    <!-- 关联数据库配置文件 -->

    <!-- c3p0可以自动的加载配置文件并设置到对象里 -->
    <!-- 可参考:https://blog.csdn.net/qq_41934990/article/details/80690987 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

        <!-- 配置连接池属性 -->
        <!-- 这里的"¥"应该换成英文输入状态下的美元符号 -->
        <!-- WordPress基于php,如果我这里打出来这个符号的话文章会被非正常解析 -->
        <!-- 从而导致乱码 -->
        <property name="driverClass" value="¥{jdbc.driver}"/>
        <property name="jdbcUrl" value="¥{jdbc.url}"/>
        <property name="user" value="¥{jdbc.username}"/>
        <property name="password" value="¥{jdbc.password}"/>

        <!-- c3p0连接池的私有属性 -->
        <property name="maxPoolSize" value="30"/>
        <property name="minPoolSize" value="10"/>
        <!-- 关闭连接后不自动commit -->
        <property name="autoCommitOnClose" value="false"/>
        <!-- 连接超时时间 -->
        <property name="checkoutTimeout" value="10000"/>
        <!-- 连接失败重试次数 -->
        <property name="acquireRetryAttempts" value="2"/>

    </bean>

    <!-- 配置SqlSessionFactory对象 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml"/>
    </bean>
    <!-- 配置SqlSessionFactory对象 -->

    <!-- 动态实现Dao接口注入spring容器 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- 注入sqlSessionFactory -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 配置目标Dao接口(包) -->
        <property name="basePackage" value="com.edisoncgh.dao"/>
    </bean>
    <!-- 动态实现Dao接口注入spring容器 -->

</beans>

整合spring所有的配置文件(applicationContext.xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- spring整合配置文件 -->
    <import resource="spring-dao.xml"/>
    <import resource="spring-service.xml"/>
    <import resource="spring-mvc.xml"/>
    <!-- spring整合配置文件 -->

</beans>

到这里我们的配置文件基本就都完成了,接下来会带过一点点controller层和Service层的内容。

内容开发

考虑到篇幅问题,这里就以最基础的图书增删查改模块做演示。
要实现图书的增删查改,我们肯定会需要一个页面来展示所有的图书。然后需要三个交互按钮,分别提供增、删、改功能,最好还要有一个文本框,满足查找功能的交互。
明确了需求,就从最基本的图书实体开始写吧。

实体类

图书的实体类很简单,有基础属性和get/set方法就行。

package com.edisoncgh.pojo;

public class Book {
    private String ISBN;

    private String bookName;

    private Byte classNo;

    private Integer bookAmount;

    private String author;

    public String getISBN() {
        return ISBN;
    }

    public void setISBN(String ISBN) {
        this.ISBN = ISBN == null ? null : ISBN.trim();
    }

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName == null ? null : bookName.trim();
    }

    public Byte getClassNo() {
        return classNo;
    }

    public void setClassNo(Byte classNo) {
        this.classNo = classNo;
    }

    public Integer getBookAmount() {
        return bookAmount;
    }

    public void setBookAmount(Integer bookAmount) {
        this.bookAmount = bookAmount;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author == null ? null : author.trim();
    }
}

实体类是所有功能实现的基础。

Service层

首先搞一个BookService接口,他在service包里。Service层的作用是实现数据交互的逻辑。
我们虽然在DAO层里实现了所有可能需要用到的数据访问手段,但dao层在ssm结构里只用于封装方法,提供接口,但并不进行操作。Service层的任务正是根据实际业务需求,去具体地调用dao层的方法,然后把拿到的切合需求的数据传给下一层。

BookService接口

package com.edisoncgh.service;

import com.edisoncgh.pojo.Book;
import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface BookService {
    /**
     * 增加一本书
     * @param book 书的实体对象
     * @return 成功与否
     */
    boolean addBook(Book book);

    /**
     * 删除一本书
     * @param ISBN 书的ISBN
     * @return 成功与否
     */
    boolean deleteBookById(@Param("ISBN") String ISBN);

    /**
     * 更新目标书籍的信息
     * @param book 书的实体对象
     * @return 成功与否
     */
    boolean updateBook(Book book);

    /**
     * 按id查询一本书
     * @param ISBN 目标ISBN
     * @return 查询到的书的实体对象
     */
    Book findBookById(@Param("ISBN") String ISBN);

    /**
     * 返回库中所有书
     * @return 库中所有书的对象列表
     */
    List<Book> findAllBook();
}

BookServiceImpl实现类:

package com.edisoncgh.service.impl;

import com.edisoncgh.dao.BookMapper;
import com.edisoncgh.pojo.Book;
import com.edisoncgh.pojo.BookExample;
import com.edisoncgh.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * BookServiceImpl注入到IOC容器中
 * 通过@Service和@Autowired注解实现
 * 可参考:https://blog.csdn.net/yangguosb/article/details/84594129
 */
@Service
public class BookServiceImpl implements BookService {
    // 设置一个set接口来调用dao层的操作
    private BookMapper bookMapper;
    // @Autowired注解如果加在变量上会提示"Field injection is not recommended"
    // 所以我选择加载构造方法上
    // 可参考:https://blog.csdn.net/zhangjingao/article/details/81094529

    @Autowired
    public void setBookMapper(BookMapper bookMapper) {
        this.bookMapper = bookMapper;
    }

    @Override
    public boolean addBook(Book book) {
        return bookMapper.insert(book)>0;
    }

    @Override
    public boolean deleteBookById(String ISBN) {
        return bookMapper.deleteByPrimaryKey(ISBN)>0;
    }

    @Override
    public boolean updateBook(Book book) {
        return bookMapper.updateByPrimaryKey(book)>0;
    }

    @Override
    public Book findBookById(String ISBN) {
        return bookMapper.selectByPrimaryKey(ISBN);
    }

    @Override
    public List<Book> findAllBook() {
        BookExample bookExample = new BookExample();
        return bookMapper.selectByExample(bookExample);
    }
}

controller层

controller层在ssm三层结构中只负责接受和处理请求。请求一般从前端页面post,然后我们会在controller层里具体地去处理它们。每一个处理请求的方法会被分配一个url用以定位。
事实上,即使大多数方法都有与自己同名的jsp页面,这也并不代表着URL指向的是这个页面。就像我们前文提到的一样,url只用于定位方法,也就是说我们可以只用一个前端页面来实现所有功能,并不需要给每一个业务需求都配一个jsp页面(表单页面除外),这在原理上是可行的。

BookContrller类:

package com.edisoncgh.controller;

import com.edisoncgh.pojo.Book;
import com.edisoncgh.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/book")
public class BookController {
    // controller调service层
    @Autowired
    @Qualifier("BookServiceImpl")
    private BookService bookService;

    // 查询全部书籍,返回一个书籍展示页面
    @RequestMapping("/allBook")
    public String list(Model model) {
        List<Book> list = bookService.findAllBook();
        model.addAttribute("list", list);
        return "allBook";
    }

    // 跳转到新增书籍页面
    @RequestMapping("/toAddBook")
    public String toAddPaper() {
        return "addBook";
    }

    // 新增书籍的请求
    @RequestMapping("/addBook")
    public String addPaper(Book book) {
        bookService.addBook(book);
        return "redirect:/book/allBook";
    }

    // 跳转到修改页面
    @RequestMapping("/toUpdate")
    public  String toUpdatePage(String ISBN,Model model) {
        Book book = bookService.findBookById(ISBN);
        model.addAttribute("QBook", book);
        return "updateBook";
    }

    // 修改书籍
    @RequestMapping("/updateBook")
    public String updateBook(Book book) {
        boolean feedback = bookService.updateBook(book);
        if (feedback) {
            System.out.println("添加成功:"+book);
        }
        return "redirect:/book/allBook";
    }

    // 删除书籍
    @RequestMapping("/deleteBook")
    public String deleteBook(String ISBN) {
        bookService.deleteBookById(ISBN);
        return "redirect:/book/allBook";
    }
}

这样就实现了我们预计的所有功能。

视图层

为了开发的方便,我们采用了bootstrap框架来做页面的响应化和美化。这里展示的是最早版本图书页面,因为它用于内测调试,结构简单清晰。

allbook.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>书籍展示</title>
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
    <div class="container">
        <div class="row clearfix">
            <div class="col-md-12 column">
                <div class="page-header">
                    <h1>书籍列表————显示所有书籍</h1>
                </div>
            </div>
        </div>

        <div class="row">
            <div class="col-md-4 column">
                <a class="btn btn-primary" href="${pageContext.request.contextPath}/book/toAddBook">新增书籍</a>
            </div>
        </div>

        <div class="row clearfix">
            <div class="col-md-12 column">
                <table class="table table-hover table-striped">
                    <thead>
                        <tr>
                            <th>ISBN</th>
                            <th>书籍名称</th>
                            <th>书籍数量</th>
                            <th>书籍作者</th>
                            <th>书籍分类</th>
                            <th>操作</th>
                        </tr>
                    </thead>
                    <tbody>
                    <c:forEach var="book" items="${list}">
                        <tr>
                            <td>${book.ISBN}</td>
                            <td>${book.bookName}</td>
                            <td>${book.bookAmount}</td>
                            <td>${book.author}</td>
                            <td>${book.classNo}</td>
                            <td>
                                <a href="${pageContext.request.contextPath}/book/toUpdate?id=${book.ISBN}">修改</a>
                                  |  
                                <a href="${pageContext.request.contextPath}/book/deleteBook?id=${book.ISBN}">删除</a>
                            </td>
                        </tr>
                    </c:forEach>
                    </tbody>
                </table>
            </div>
        </div>


    </div>
</body>
</html>

结语

到这里,SSM框架的开发流程基本就结束了,更多的功能开发在流程上只是对上述内容的简单重复而已,也就不再赘述。