你的位置:首页 > Java教程

[Java教程]Spring整合MyBatis完整示例


为了梳理前面学习的内容《Spring整合MyBatis(Maven+MySQL)一》与《Spring整合MyBatis(Maven+MySQL)二》,做一个完整的示例完成一个简单的图书管理功能,主要使用到的技术包含Spring、MyBatis、Maven、MySQL及简单MVC等。最后的运行效果如下所示:

 

项目结构如下:

 

一、新建一个基于Maven的Web项目

1.1、创建一个简单的Maven项目,项目信息如下:

 1.2、修改层面信息,在项目上右键选择属性,再选择“Project Facets”,先设置java运行环境为1.7,先去掉"Dynamic Web Module"前的勾,然后保存关闭;再打开勾选上"Dynamic Web Module",版本选择“3.0”;这里在左下解会出现一个超链接,创建“Web Content”,完成关闭。

1.3、修改项目的部署内容。项目上右键属性,选择“Deplyment Assembly”,删除不需要发布的内容如:带“test”的两个目录,WebContent目录,再添加一个main下的webapp目录。

修改后的结果如下所示:

1.4、修改项目内容。将WebContent下的内容复制到/src/main/webapp下,再删除WebContent目录,修改后的结果如下所示:

1.5、添加“服务器运行时(Server Runtime)”,添加后的结果如下:

二、创建数据库与表

启动MySQL,创建数据库,新建表books,插入测试数据,完成后的表如下所示:

创建表的sql脚本如下:

/*Navicat MySQL Data TransferSource Server     : localhostSource Server Version : 50536Source Host      : localhost:3306Source Database    : db1Target Server Type  : MYSQLTarget Server Version : 50536File Encoding     : 65001Date: 2016-07-06 22:05:07*/SET FOREIGN_KEY_CHECKS=0;-- ------------------------------ Table structure for `books`-- ----------------------------DROP TABLE IF EXISTS `books`;CREATE TABLE `books` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号', `title` varchar(100) NOT NULL COMMENT '书名', `price` decimal(10,2) DEFAULT NULL COMMENT '价格', `publishDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '出版日期', PRIMARY KEY (`id`), UNIQUE KEY `title` (`title`)) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;-- ------------------------------ Records of books-- ----------------------------INSERT INTO `books` VALUES ('1', 'Java编程思想', '98.50', '2005-01-02 00:00:00');INSERT INTO `books` VALUES ('2', 'HeadFirst设计模式', '55.70', '2010-11-09 00:00:00');INSERT INTO `books` VALUES ('3', '第一行Android代码', '69.90', '2015-06-23 00:00:00');INSERT INTO `books` VALUES ('4', 'C++编程思想', '88.50', '2004-01-09 00:00:00');INSERT INTO `books` VALUES ('5', 'HeadFirst Java', '55.70', '2013-12-17 00:00:00');INSERT INTO `books` VALUES ('6', '疯狂Android', '19.50', '2014-07-31 00:00:00');

需特别注意的是书名是唯一键。

三、添加依赖包

项目主要依赖的jar包有Spring核心包、Spring AOP包、MyBatis ORM包、MyBatis-Spring适配包、JSTL、JUnit、Log4j2等,具体的pom.

<project ="http://maven.apache.org/POM/4.0.0" ="http://www.w3.org/2001/  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  <modelVersion>4.0.0</modelVersion>  <groupId>com.zhangguo</groupId>  <artifactId>BookStore</artifactId>  <version>0.0.1</version>  <packaging>war</packaging>  <properties>    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>    <spring.version>4.3.0.RELEASE</spring.version>  </properties>  <dependencies>    <!--Spring框架核心库 -->    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-context</artifactId>      <version>${spring.version}</version>    </dependency>    <!-- aspectJ AOP 织入器 -->    <dependency>      <groupId>org.aspectj</groupId>      <artifactId>aspectjweaver</artifactId>      <version>1.8.9</version>    </dependency>    <!-- Spring Web -->    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-web</artifactId>      <version>${spring.version}</version>    </dependency>    <!--mybatis-spring适配器 -->    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis-spring</artifactId>      <version>1.3.0</version>    </dependency>    <!--Spring java数据库访问包,在本例中主要用于提供数据源 -->    <dependency>      <groupId>org.springframework</groupId>      <artifactId>spring-jdbc</artifactId>      <version>${spring.version}</version>    </dependency>    <!--mysql数据库驱动 -->    <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <version>5.1.38</version>    </dependency>    <!--log4j日志包 -->    <dependency>      <groupId>org.apache.logging.log4j</groupId>      <artifactId>log4j-core</artifactId>      <version>2.6.1</version>    </dependency>    <!-- mybatis ORM框架 -->    <dependency>      <groupId>org.mybatis</groupId>      <artifactId>mybatis</artifactId>      <version>3.4.1</version>    </dependency>    <!-- JUnit单元测试工具 -->    <dependency>      <groupId>junit</groupId>      <artifactId>junit</artifactId>      <version>4.10</version>    </dependency>    <!--c3p0 连接池 -->    <dependency>      <groupId>c3p0</groupId>      <artifactId>c3p0</artifactId>      <version>0.9.1.2</version>    </dependency>    <!-- jstl -->    <dependency>      <groupId>javax.servlet</groupId>      <artifactId>jstl</artifactId>      <version>1.2</version>    </dependency>  </dependencies></project>

如果是第一次依赖相关的包,则需要下载时间,请耐心等待,如果下载失败请手动下载后复制到本地的资源库中。依赖后的项目结果如下:

四、新建POJO实体层

为了实现与数据库中的books表进行关系映射新建一个Book类,具体代码如下:

package com.zhangguo.bookstore.entities;import java.util.Date;/** * 图书实体 */public class Book {  /**   * 编号   */  private int id;  /**   * 书名   */  private String title;  /**   * 价格   */  private double price;  /**   * 出版日期   */  private Date publishDate;  public Book(int id, String title, double price, Date publishDate) {    this.id = id;    this.title = title;    this.price = price;    this.publishDate = publishDate;  }    public Book() {  }  public int getId() {    return id;  }  public void setId(int id) {    this.id = id;  }  public String getTitle() {    return title;  }  public void setTitle(String title) {    this.title = title;  }  public double getPrice() {    return price;  }  public void setPrice(double price) {    this.price = price;  }  public Date getPublishDate() {    return publishDate;  }  public void setPublishDate(Date publishDate) {    this.publishDate = publishDate;  }}

五、新建MyBatis SQL映射层

这个项目中我们采用接口与

package com.zhangguo.bookstore.mapper;import java.util.List;import org.apache.ibatis.annotations.Param;import com.zhangguo.bookstore.entities.Book;/** * 图书数据访问接口 */public interface BookDAO {  /**   * 获得所有图书   */  public List<Book> getAllBooks();  /**   * 根据图书编号获得图书对象   */  public Book getBookById(@Param("id") int id);  /**   * 添加图书   */  public int add(Book entity);  /**   * 根据图书编号删除图书   */  public int delete(int id);  /**   * 更新图书   */  public int update(Book entity);}

为MyBatis ORM创建的映射文件BookMapper.

<??><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--命名空间应该是对应接口的包名+接口名 --><mapper namespace="com.zhangguo.bookstore.mapper.BookDAO">  <!--id应该是接口中的方法,结果类型如没有配置别名则应该使用全名称 -->  <!--获得所有图书 -->  <select id="getAllBooks" resultType="Book">    select id,title,price,publishDate from books  </select>  <!--获得图书对象通过编号 -->  <select id="getBookById" resultType="Book">    select id,title,price,publishDate from books where id=#{id}  </select>  <!-- 增加 -->  <insert id="add">    insert into books(title,price,publishDate)    values(#{title},#{price},#{publishDate})  </insert>  <!-- 删除 -->  <delete id="delete">    delete from books where id=#{id}  </delete>  <!-- 更新 -->  <update id="update">    update books set title=#{title},price=#{price},publishDate=#{publishDate}    where id=#{id}  </update></mapper>

六、完成Spring整合MyBatis配置

6.1、在源代码的根目录下新建 db.properties文件,用于存放数据库连接信息,文件内容如下:

#mysql jdbcjdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/db1?useUnicode=true&characterEncoding=UTF-8jdbc.uid=rootjdbc.pwd=root

6.2、在源代码的根目录下新建 applicationContext.

<??><beans ="http://www.springframework.org/schema/beans"  ="http://www.w3.org/2001/   ="http://www.springframework.org/schema/p"  ="http://www.springframework.org/schema/aop"   ="http://www.springframework.org/schema/context"  ="http://www.springframework.org/schema/tx"  xsi:schemaLocation="http://www.springframework.org/schema/beans    http://www.springframework.org/schema/beans/spring-beans.xsd    http://www.springframework.org/schema/context    http://www.springframework.org/schema/context/spring-context-4.3.xsd    http://www.springframework.org/schema/aop    http://www.springframework.org/schema/aop/spring-aop-4.3.xsd    http://www.springframework.org/schema/tx    http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">  <!--1 引入属性文件,在配置中占位使用 -->  <context:property-placeholder location="classpath*:db.properties" />  <!--2 配置C3P0数据源 -->  <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">    <!--驱动类名 -->    <property name="driverClass" value="${jdbc.driver}" />    <!-- url -->    <property name="jdbcUrl" value="${jdbc.url}" />    <!-- 用户名 -->    <property name="user" value="${jdbc.uid}" />    <!-- 密码 -->    <property name="password" value="${jdbc.pwd}" />    <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数 -->    <property name="acquireIncrement" value="5"></property>    <!-- 初始连接池大小 -->    <property name="initialPoolSize" value="10"></property>    <!-- 连接池中连接最小个数 -->    <property name="minPoolSize" value="5"></property>    <!-- 连接池中连接最大个数 -->    <property name="maxPoolSize" value="20"></property>  </bean>    <!--3 会话工厂bean sqlSessionFactoryBean -->  <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    <!-- 数据源 -->    <property name="dataSource" ref="datasource"></property>    <!-- 别名 -->    <property name="typeAliasesPackage" value="com.zhangguo.bookstore.entities"></property>    <!-- sql映射文件路径 -->    <property name="mapperLocations" value="classpath*:com/zhangguo/bookstore/mapper/*Mapper.></property>  </bean>    <!--4 自动扫描对象关系映射 -->  <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">    <!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>    <!-- 指定要自动扫描接口的基础包,实现接口 -->    <property name="basePackage" value="com.zhangguo.bookstore.mapper"></property>  </bean>    <!--5 声明式事务管理 -->  <!--定义事物管理器,由spring管理事务 -->  <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    <property name="dataSource" ref="datasource"></property>  </bean>  <!--支持注解驱动的事务管理,指定事务管理器 -->  <tx:annotation-driven transaction-manager="transactionManager"/>  <!--6 容器自动扫描IOC组件 -->  <context:component-scan base-package="com.zhangguo.bookstore"></context:component-scan>    <!--7 aspectj支持自动代理实现AOP功能 -->  <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy></beans>

共有7处配置,第7处配置非必要,另外关于事务管理可以选择AOP拦截式事务管理。 

七、创建服务层

 创建BookService服务类,完成图书管理业务,有些项目中也叫业务层,这里我们叫服务层,具体实现如下:

package com.zhangguo.bookstore.service;import java.util.List;import javax.annotation.Resource;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import com.zhangguo.bookstore.entities.Book;import com.zhangguo.bookstore.mapper.BookDAO;@Servicepublic class BookService{  @Resource  BookDAO bookdao;    public List<Book> getAllBooks() {    return bookdao.getAllBooks();  }    public Book getBookById(int id){    return bookdao.getBookById(id);  }    public int add(Book entity) throws Exception {    if(entity.getTitle()==null||entity.getTitle().equals("")){      throw new Exception("书名必须不为空");    }    return bookdao.add(entity);  }    @Transactional  public int add(Book entity1,Book entityBak){    int rows=0;    rows=bookdao.add(entity1);    rows=bookdao.add(entityBak);    return rows;  }  public int delete(int id) {    return bookdao.delete(id);  }    /**   * 多删除   */  public int delete(String[] ids){    int rows=0;    for (String idStr : ids) {      int id=Integer.parseInt(idStr);      rows+=delete(id);    }    return rows;  }  public int update(Book entity) {    return bookdao.update(entity);  }}

服务层不只是一个dao的接力棒,认为他可有可无,其实是因为我们现在的的示例中没有涉及到更多的复杂业务,所以显得比较空,实现开发可能有更多的业务逻辑要在这里处理。另外给bookdao成员变量注解为自动装配,service类注解为IOC组件。

八、JUnit测试服务类

为了确保服务类中的每个方法正确,先使用JUnit进行单元测试,测试代码如下:

package com.zhangguo.bookstore.test;import static org.junit.Assert.*;import java.util.Date;import java.util.List;import org.junit.BeforeClass;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathimport com.zhangguo.bookstore.entities.Book;import com.zhangguo.bookstore.service.BookService;public class TestBookService {  static BookService bookservice;    @BeforeClass  public static void before(){    ApplicationContext ctx=new ClassPath);    bookservice=ctx.getBean(BookService.class);  }    @Test  public void testGetAllBooks() {    List<Book> books=bookservice.getAllBooks();    assertNotNull(books);  }  @Test  public void testAdd() {    Book entity=new Book(0, "Hibernate 第七版", 78.1, new Date());    try {      assertEquals(1, bookservice.add(entity));    } catch (Exception e) {      e.printStackTrace();    }  }  @Test  public void testDeleteInt() {    assertEquals(1, bookservice.delete(9));  }  @Test  public void testDeleteStringArray() {    String[] ids={"7","11","12"};    assertEquals(3, bookservice.delete(ids));  }  @Test  public void testUpdate() {    Book entity=new Book(7, "Hibernate 第二版", 79.1, new Date());    try {      assertEquals(1, bookservice.update(entity));    } catch (Exception e) {      e.printStackTrace();    }  }    @Test  public void testGetBookById()  {    assertNotNull(bookservice.getBookById(1));  }    @Test  public void testAddDouble(){    //因为书名相同,添加第二本会失败,用于测试事务    Book entity1=new Book(0, "Hibernate 第八版", 78.1, new Date());    Book entity2=new Book(0, "Hibernate 第八版", 78.1, new Date());    assertEquals(2, bookservice.add(entity1, entity2));  }}

所有的测试均通过,有一个想法就是能否测试完成后数据库还原,如删除的数据在测试后不被真正删除。

九、加载Spring容器与获得容器对象

9.1、修改web.

<??><web-app ="http://www.w3.org/2001/  ="http://java.sun.com/  xsi:schemaLocation="http://java.sun.com/  id="WebApp_ID" version="3.0" >  <welcome-file-list>    <welcome-file>index.jsp</welcome-file>  </welcome-file-list>    <listener>    <description>Spring容器加载监听器</description>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>  <context-param>    <description>设置Spring加载时的配置文件位置,默认位置在web-inf/lib下</description>    <param-name>contextConfigLocation</param-name>    <param-value>classpath*:applicationContext.</param-value>  </context-param></web-app>

类org.springframework.web.context.ContextLoaderListener处在Spring-web.jar包中,要记得在pom.

9.2、为了方便获得Spring容器实例,定义一个CtxUtil工具类,工具类的代码如下:

package com.zhangguo.bookstore.action;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/** * Spring容器上下文工具类,用于获取当前的Spring容器 * 实现了接口ApplicationContextAware且该类被Spring管理 *则会自动调用setApplicationContext方法获取Spring容器对象 */@Componentpublic class CtxUtil implements ApplicationContextAware {  public static ApplicationContext ctx;    @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {    ctx=applicationContext;  }  /**   * 根据类型获得bean   */  public static <T> T getBean(Class<T> clazz){    return ctx.getBean(clazz);  }  /**   * 根据名称名称获得bean   */  public static Object getBean(String name){    return ctx.getBean(name);  }}

十、简单MVC控制器封装

 为了实现一个简单的MVC基础控制器,定义了一个叫BaseController的Servlet,可以让其它的Servlet继承该Servlet获得部分MVC功能,具体代码如下:

package com.zhangguo.bookstore.action;import java.io.IOException;import java.lang.reflect.*;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;/** * Servlet基类 * 自定义控制器基类 */public class BaseController extends HttpServlet {  private static final long serialVersionUID = 1L;  protected void service(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {    request.setCharacterEncoding("UTF-8");    response.setCharacterEncoding("UTF-8");    response.setContentType("text/html;charset=utf-8");    // 获得要执行的方法名    String act = request.getParameter("act");    // 如果用户没有提供方法名    if (act == null || act.equals("")) {      // 默认方法      act = "execute";    }    // 根据方法名获得方法信息获得方法信息    Method method;    try {      // 在对象中获得类型信息,在类型中获得方法通过方法名,与参数类型      method = this.getClass().getMethod(act, HttpServletRequest.class, HttpServletResponse.class);      // 调用方法,在当前对象中调用,传递参数request与response,获得返回结果      String targetUri = method.invoke(this, request, response) + "";      // 如果返回的url是以redirect开始,则是重定向      if (targetUri.startsWith("redirect:")) {        response.sendRedirect(targetUri.substring(9, targetUri.length()));      } else {        // 转发        request.getRequestDispatcher(targetUri).forward(request, response);      }    } catch (Exception e) {      response.sendError(400, e.getMessage());      e.printStackTrace();    }  }  public void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {    response.sendError(400, "请使用参数act指定您要访问的方法");  }}

十一、完成图书管理功能

11.1、定义BookController控制器

该控制器继承BaseController,中间每一个参数为(HttpServletRequest request,HttpServletResponse response)的方法都充当一个Action,代码如下:

package com.zhangguo.bookstore.action;import java.io.IOException;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.zhangguo.bookstore.entities.Book;import com.zhangguo.bookstore.service.BookService;@WebServlet("/BookController.do")public class BookController extends BaseController {  private static final long serialVersionUID = 1L;  BookService bookservice;  @Override  public void init() throws ServletException {    bookservice = CtxUtil.getBean(BookService.class);  }  // 图书列表Action  public String ListBook(HttpServletRequest request, HttpServletResponse response) {    request.setAttribute("books", bookservice.getAllBooks());    return "ListBook.jsp";  }  // 删除图书Action  public String Delete(HttpServletRequest request, HttpServletResponse response) {    int id = Integer.parseInt(request.getParameter("id"));    request.setAttribute("message", bookservice.delete(id) > 0 ? "删除成功!" : "删除失败!");    request.setAttribute("books", bookservice.getAllBooks());    return "ListBook.jsp";  }  // 多删除图书Action  public String Deletes(HttpServletRequest request, HttpServletResponse response) {    String[] ids = request.getParameterValues("ids");    if (ids!=null&&ids.length > 0) {      request.setAttribute("message", bookservice.delete(ids) > 0 ? "删除成功!" : "删除失败!");    } else {      request.setAttribute("message", "请选择删除项!");    }    request.setAttribute("books", bookservice.getAllBooks());    return "ListBook.jsp";  }  // 添加图书Action  public String AddBook(HttpServletRequest request, HttpServletResponse response) {    return "AddBook.jsp";  }  // 保存添加图书Action  public String AddBookPost(HttpServletRequest request, HttpServletResponse response) {    try {      String title = request.getParameter("title");      double price = Double.parseDouble(request.getParameter("price"));      SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");      Date publishDate = simpleDateFormat.parse(request.getParameter("publishDate"));      Book entity = new Book(0, title, price, publishDate);      if (bookservice.add(entity) > 0) {        request.setAttribute("model", new Book());        request.setAttribute("message", "添加成功!");      } else {        request.setAttribute("model", entity);        request.setAttribute("message", "添加失败!");      }    } catch (Exception exp) {      request.setAttribute("message", exp.getMessage());      exp.printStackTrace();    }    return "AddBook.jsp";  }      //编辑图书Action    public String EditBook(HttpServletRequest request, HttpServletResponse response) {      int id = Integer.parseInt(request.getParameter("id"));      Book model=bookservice.getBookById(id);      request.setAttribute("model", model);      return "EditBook.jsp";    }    // 保存编辑图书Action    public String EditBookPost(HttpServletRequest request, HttpServletResponse response) {      try {        int id=Integer.parseInt(request.getParameter("id"));                String title = request.getParameter("title");        double price = Double.parseDouble(request.getParameter("price"));        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");        Date publishDate = simpleDateFormat.parse(request.getParameter("publishDate"));        Book entity = new Book(id, title, price, publishDate);        request.setAttribute("message", bookservice.update(entity) > 0 ? "更新成功!" : "更新失败!");        request.setAttribute("model", entity);      } catch (Exception exp) {        request.setAttribute("message", exp.getMessage());        exp.printStackTrace();      }      return "EditBook.jsp";    }}

11.2、图书列表与删除

定义视图ListBook.jsp,用于完成图书管理,实现图书的列表、删除与多删除功能,页面脚本如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %><!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link href="styles/main.css" type="text/css" rel="stylesheet" /><title>图书管理</title></head><body>  <div class="main">    <h2 class="title"><span>图书管理</span></h2>    <form action="BookController.do?act=Deletes" method="post">    <table border="1" width="100%" class="tab">      <tr>        <th><input type="checkbox" id="chbAll"></th>        <th>编号</th>        <th>书名</th>        <th>价格</th>        <th>出版日期</th>        <th>操作</th>      </tr>      <c:forEach var="book" items="${books}">        <tr>          <th><input type="checkbox" name="ids" value="${book.id}"></th>          <td>${book.id}</td>          <td>${book.title}</td>          <td>${book.price}</td>          <td><fmt:formatDate value="${book.publishDate}" pattern="yyyy年MM月dd日"/></td>          <td>          <a href="BookController.do?act=Delete&id=${book.id}" class="abtn">删除</a>          <a href="BookController.do?act=EditBook&id=${book.id}" class="abtn">编辑</a>          </td>        </tr>      </c:forEach>    </table>    <p style="color: red">${message}</p>    <p>      <a href="BookController.do?act=AddBook" class="abtn">添加</a>      <input type="submit" value="删除选择项" class="btn"/>    </p>  </form>  </div></body></html>

运行时效果如下图所示:

11.3、新增图书功能

定义页面AddBook.jsp完成添加图书功能,在控制器中有两个Action对应新增功能,一个是AddBook,完成页面展示;另一个是AddBookPost处理保存事件,页面脚本如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link href="styles/main.css" type="text/css" rel="stylesheet" /><title>新增图书</title></head><body>  <div class="main">    <h2 class="title"><span>新增图书</span></h2>    <form action="BookController.do?act=AddBookPost" method="post">    <fieldset>      <legend>图书</legend>      <p>        <label for="title">图书名称:</label>        <input type="text" id="title" name="title" value="${model.title}"/>      </p>      <p>        <label for="title">图书价格:</label>        <input type="text" id="price" name="price" value="${model.price}"/>      </p>      <p>        <label for="title">出版日期:</label>        <input type="text" id="publishDate" name="publishDate" value="${model.publishDate}"/>      </p>      <p>       <input type="submit" value="保存" class="btn">      </p>    </fieldset>    </form>    <p style="color: red">${message}</p>    <p>      <a href="BookController.do?act=ListBook" class="abtn">返回列表</a>    </p>  </div></body></html>

运行成功时的状态如下:

11.4、编辑图书功能

定义页面EditBook.jsp完成更新图书功能,在控制器中有两个Action对应更新功能,一个是EditBook,完成页面展示与加载要编辑图书实体的信息;另一个是EditBookPost处理保存事件,页面脚本如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%><%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%><!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link href="styles/main.css" type="text/css" rel="stylesheet" /><title>编辑图书</title></head><body>  <div class="main">    <h2 class="title"><span>编辑图书</span></h2>    <form action="BookController.do?act=EditBookPost" method="post">    <fieldset>      <legend>图书</legend>      <p>        <label for="title">图书名称:</label>        <input type="text" id="title" name="title" value="${model.title}"/>      </p>      <p>        <label for="title">图书价格:</label>        <input type="text" id="price" name="price" value="${model.price}"/>      </p>      <p>        <label for="title">出版日期:</label>        <input type="text" id="publishDate" name="publishDate" value="<fmt:formatDate value="${model.publishDate}" pattern="yyyy-MM-dd"/>"/>      </p>      <p>        <input type="hidden" id="id" name="id" value="${model.id}"/>       <input type="submit" value="保存" class="btn">      </p>    </fieldset>    </form>    <p style="color: red">${message}</p>    <p>      <a href="BookController.do?act=ListBook" class="abtn">返回列表</a>    </p>  </div></body></html>

运行时的状态如下所示:

11.5、首页与样式

定义index.jsp页面,让其转发到指定的控制器(有点类似路由功能了),页面代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%><jsp:forward page="BookController.do?act=ListBook"></jsp:forward>

定义了一个简陋的样式main.css,样式表脚本如下:

 

@CHARSET "UTF-8";* {  margin: 0;  padding: 0;  font-family: microsoft yahei;  font-size: 14px;}body {  padding-top: 20px;}.main {  width: 90%;  margin: 0 auto;  border: 1px solid #777;  padding: 20px;}.main .title {  font-size: 20px;  font-weight: normal;  border-bottom: 1px solid #ccc;  margin-bottom: 15px;  padding-bottom: 5px;  color: blue;}.main .title span {  display: inline-block;  font-size: 20px;   background : blue;  color: #fff;  padding: 0 8px;  background: blue;}a {  color: blue;  text-decoration: none;}a:hover {  color: orangered;}.tab td, .tab, .tab th {  border: 1px solid #777;  border-collapse: collapse;}.tab td, .tab th {  line-height: 26px;  height: 26px;  padding-left: 5px;}.abtn {  display: inline-block;  height: 20px;  line-height: 20px;  background: blue;  color: #fff;  padding: 0 5px;}.btn {  height: 20px;  line-height: 20px;  background: blue;  color: #fff;  padding: 0 8px;  border:0;}.abtn:hover,.btn:hover{  background: orangered;  color: #fff;}p{  padding:5px 0;}fieldset{    border: 1px solid #ccc;    padding:5px 10px;}fieldset legend{  margin-left:10px;  font-size:16px;}

十二、总结与示例下载

这个Demo起到了承前启后的作用,通过该示例将前面学习过的Spring IOC、MyBatis、JSP、Servlet、Maven及Spring整合MyBatis的内容进行巩固,也为后面学习Spring MVC作好了铺垫。示例中隐约的实现了一些MVC的功能,这远远不够,在URL的处理、表单验证、自动映射表单等方面还可以完善,只想有一个抛砖引玉的作用就满意了,谢谢您的阅读,谢谢!

示例下载