一、SSM概要
与SSH(Struts/Spring/Hibernate/)一样,Spring+SpringMVC+MyBatis也有一个简称SSM,Spring实现业务对象管理,Spring MVC负责请求的转发和视图管理, MyBatis作为数据对象持久化引擎。这样搭配的优点是:轻量、自由度高、Spring与Spring MVC契合度更好。通过一个商品管理示例完成SSM框架的集成,可以将前面学习过的一些内容整合起来。
1.1、SpringMVC
1.客户端发送请求到DispacherServlet(分发器)
2.由DispacherServlet控制器查询HanderMapping,找到处理请求的Controller
3.Controller调用业务逻辑处理后,返回ModelAndView
4.DispacherSerclet查询视图解析器,找到ModelAndView指定的视图
5.视图负责将结果显示到客户端

1.2、Spring
1.Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器架构,IOC容器包含并管理应用对象的配置和生命周期,你可以配置你的每个bean如何被创建,也可以配置每个bean是只有一个实例,还是每次需要时都生成一个新的实例,以及它们是如何相互关联的。
2.IOC思想最核心的地方在于,资源不由使用资源的双方管理,而由不使用资源的第三方管理,这可以带来很多好处。

第一,资源集中管理,实现资源的可配置和易管理。
第二,降低了使用资源双方的依赖程度,也就是我们说的耦合度。
3.容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能。
1.3、MyBatis
1.MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录。
2.MyBatis的操作都是围绕一个sqlSessionFactory实例展开的。MyBatis通过配置文件关联到各实体类的Mapper文件,Mapper文件中配置了每个类对数据库所需进行的sql语句映射。在每次与数据库交互时,通过sqlSessionFactory拿到一个sqlSession,再执行sql命令。

1.4、Maven多模块
JavaEE项目开发中为了便于后期的维护,一般会进行分层开发,分层之后,各个层之间的职责会比较明确,后期维护起来也相对比较容易。
《一个小时学会Maven》可以获得更多帮助
二、数据库
打开MySQL数据库,创建一个表,这里以goods表为例,一个用于存放商品的表,共4个字段id表示编号,name表示商品名称,picture表示图片,price表示价格。SQL脚本如下:
- SET FOREIGN_KEY_CHECKS=0;
- -- ----------------------------
- -- Table structure for `goods`
- -- ----------------------------
- DROP TABLE IF EXISTS `goods`;
- CREATE TABLE `goods` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(200) NOT NULL,
- `price` decimal(10,2) DEFAULT '0.00',
- `picture` varchar(100) DEFAULT 'default.jpg',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
- -- ----------------------------
- -- Records of goods
- -- ----------------------------
- INSERT INTO `goods` VALUES ('1', 'G7 中原G7三合一浓醇咖啡固体饮料1200', '66.50', '1.jpg');
- INSERT INTO `goods` VALUES ('2', '百草味东北松子200gx2袋 坚果炒货零', '42.90', '2.jpg');
- INSERT INTO `goods` VALUES ('3', '奈津香 桂圆干500gx2袋莆田特产5A桂', '39.90', '3.jpg');
- INSERT INTO `goods` VALUES ('4', '益达尊享护齿装草本40粒+冰柠40粒+西', '25.90', '4.jpg');
- INSERT INTO `goods` VALUES ('5', '猴坑茶业2016新茶原产地手工太平猴魁特', '168.00', '5.jpg');
- INSERT INTO `goods` VALUES ('6', '嘻鱿记 休闲零食 麻辣香辣奶香炭烧 5种', '39.80', '6.jpg');
- INSERT INTO `goods` VALUES ('7', '荣业鸿福五分瘦腊肠 香港土特产香肠腊味', '126.80', '7.jpg');
- INSERT INTO `goods` VALUES ('8', '蓓琳娜(BELLINA)3L PDO特级初榨橄榄油', '178.00', '8.jpg');
- INSERT INTO `goods` VALUES ('10', '荣业鸿福五分瘦腊肠 香港土特产香肠腊味', '30.60', '9.jpg');
结果:

三、创建多模块项目
3.1、各模块的功能

common模块:通用模块,不依赖其它任何模块,主要有utils、可以在多个不同项目中得胜的内容
entitie模块:POJO、VO、DTO
dao模块:数据持久化,访问数据库,这里使用Mybatis
service模块:业务模块,处理业务逻辑
webui模块:B/S结构的表示层,主要用于在浏览器中显示数据,提供用户接口
3.2、创建项目结构
创建父模块,不使用骨架的maven普通项目

创建子模块commons

创建不使用骨架的maven普通项目

entity、dao、service模块创建方法与命名规范同上。
webui需要创建一个使用webapp骨架的maven项目:

完成的项目结构如下:

《一个小时学会Maven》可以获得更多帮助
四、添加各模块间的依赖
子模块默认是继承父模块的,这里全部使用按需依赖。
dao模块的pom:
- <dependencies>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-common</artifactId>
- </dependency>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-entity</artifactId>
- </dependency>
- </dependencies>
service的pom:
- <dependencies>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-dao</artifactId>
- </dependency>
- </dependencies>
因为依赖具有传递性,在service中可以间接的依赖到entity与common
webui的pom:
- <dependencies>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-service</artifactId>
- </dependency>
- </dependencies>
依赖完成的结果:

五、完成POJO实体模块
完成这一层之前先明确一下几个容易混淆的概念:
5.1、POJO
- POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJB混淆所创造的简称。
- 其中有一些属性及其getter、setter方法的类,没有业务逻辑,有时可以作为VO(value-object)或DTO(Data Transfer Object)来使用。不允许有业务方法,也不能携带connection之类的方法。
5.2、JavaBean
- JavaBean是Java语言写成的可重用组件。JavaBean则比 POJO复杂很多, Java Bean 是可复用的组件,对 Java Bean 并没有严格的规范,理论上讲,任何一个 Java 类都可以是一个 Bean 。EJB则是Enterprise JavaBean,是JavaEE的一部分,定义了一个用于开发基于组件的企业多重应用程序标准。
5.3、Entity
- 实体bean,一般是用于ORM对象关系映射,一个实体映射成一张表,一般无业务逻辑代码。
- 负责将数据库中的表记录映射为内存中的Entity对象,事实上,创建一个EntityBean对象相当于创建一条记录,删除一个EntityBean对象会同时从数据库中删除对应记录,修改一个Entity Bean时,容器会自动将Entity Bean的状态和数据库同步。
5.4、Domain Model
- 业务对象模型(也叫领域模型 domain model)是描述业务用例实现的对象模型。又称概念模型、领域对象模型、分析对象模型。领域模型中的实体类分为四种类型:VO、DTO、DO、PO

VO(View Object):视图对象,用于展示层,它的作用是把某个指定页面(或组件)的所有数据封装起来。
DTO(Data Transfer Object):数据传输对象,这个概念来源于J2EE的设计模式,原来的目的是为了EJB的分布式应用提供粗粒度的数据实体,以减少分布式调用的次数,从而提高分布式调用的性能和降低网络负载,但在这里,我泛指用于展示层与服务层之间的数据传输对象。
DO(Domain Object):领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。
PO(PersistentObject):持久化对象,它跟持久层(通常是关系型数据库)的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段(或若干个)就对应PO的一个(或若干个)属性。
5.5、实体模块
Goods商品POJO对象如下:
- package com.zhangguo.ssm01.entity;
- import java.io.Serializable;
- import java.math.BigDecimal;
- /**
- * 商品POJO
- */
- public class Goods implements Serializable {
- private int id;
- private String name;
- private BigDecimal price;
- private String picture;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public BigDecimal getPrice() {
- return price;
- }
- public void setPrice(BigDecimal price) {
- this.price = price;
- }
- public String getPicture() {
- return picture;
- }
- public void setPicture(String picture) {
- this.picture = picture;
- }
- @Override
- public String toString() {
- return "Goods{" +
- "id=" + id +
- ", name='" + name + '\'' +
- ", price=" + price +
- ", picture='" + picture + '\'' +
- '}';
- }
- }
六、完成Commons通用工具模块
commons通用模块主要是为项目中其它模块提供辅助功能,如utils工具类等内容:
依赖:
父模块的pom:

View Code
commons的pom:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>SSM01</artifactId>
- <groupId>com.zhangguo.ssm01</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>Ssm01-common</artifactId>
-
- <dependencies>
- <!--jackson-->
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-databind</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- </dependency>
- <!--apache-commons-->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- </dependency>
- </dependencies>
- </project>
添加相应的工具类:
如封装页面返回结果的JSON:

- package com.zhangguo.ssm01.common.utils;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * 返回数据封装
- */
- public class R extends HashMap<String, Object> {
- private static final long serialVersionUID = 1L;
-
- public R() {
- put("code", 1);
- put("msg", "success");
- }
- //错误时
- public static R error() {
- return error(500, "未知异常,请联系管理员");
- }
-
- public static R error(String msg) {
- return error(500, msg);
- }
-
- public static R error(int code, String msg) {
- R r = new R();
- r.put("code", code);
- r.put("msg", msg);
- return r;
- }
- //成功时
- public static R ok(String msg) {
- R r = new R();
- r.put("msg", msg);
- return r;
- }
-
- public static R ok(Map<String, Object> map) {
- R r = new R();
- r.putAll(map);
- return r;
- }
-
- public static R ok() {
- return new R();
- }
- public static R ok(Object data) {
- return new R().put("data",data);
- }
- @Override
- public R put(String key, Object value) {
- super.put(key, value);
- return this;
- }
- }
View Code
太多了这里不一一介绍。
结果:

七、完成DAO数据访问模块
Spring学习总结(六)——Spring整合MyBatis完整示例
7.1、添加依赖
父模块声明:

View Code
子模块引用:
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <artifactId>SSM01</artifactId>
- <groupId>com.zhangguo.ssm01</groupId>
- <version>1.0-SNAPSHOT</version>
- </parent>
- <modelVersion>4.0.0</modelVersion>
-
- <artifactId>Ssm01-dao</artifactId>
-
- <dependencies>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-common</artifactId>
- </dependency>
- <dependency>
- <groupId>com.zhangguo.ssm01</groupId>
- <artifactId>Ssm01-entity</artifactId>
- </dependency>
-
- <!--log4j日志包 -->
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-core</artifactId>
- </dependency>
- <!-- JUnit单元测试工具 -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <!--Spring框架核心库 -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-context</artifactId>
- </dependency>
- <!-- aspectJ AOP 织入器 -->
- <dependency>
- <groupId>org.aspectj</groupId>
- <artifactId>aspectjweaver</artifactId>
- </dependency>
- <dependency>
- <groupId>cglib</groupId>
- <artifactId>cglib</artifactId>
- </dependency>
-
- <!--mybatis-spring适配器 -->
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis-spring</artifactId>
- </dependency>
- <!--Spring java数据库访问包,在本例中主要用于提供数据源 -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-jdbc</artifactId>
- </dependency>
- <!--mysql数据库驱动 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
- <!-- mybatis ORM框架 -->
- <dependency>
- <groupId>org.mybatis</groupId>
- <artifactId>mybatis</artifactId>
- </dependency>
- <!--c3p0 连接池 -->
- <dependency>
- <groupId>c3p0</groupId>
- <artifactId>c3p0</artifactId>
- </dependency>
- </dependencies>
- </project>
7.2、数据库配置属性文件
在resources根目录中定义db.properties
- #mysql jdbc
- mysql.driver=com.mysql.jdbc.Driver
- mysql.url=jdbc:mysql://localhost:3306/gomall?useUnicode=true&characterEncoding=UTF-8
- mysql.uid=root
- mysql.pwd=uchr@123
7.3、Spring-mybatis集成
applicationContext.xml,用于完成Spring-mybatis集成使用
- <?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:p="http://www.springframework.org/schema/p"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:tx="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="${mysql.driver}" />
- <!-- url -->
- <property name="jdbcUrl" value="${mysql.url}" />
- <!-- 用户名 -->
- <property name="user" value="${mysql.uid}" />
- <!-- 密码 -->
- <property name="password" value="${mysql.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.ssm01.entity"></property>
- <!-- sql映射文件路径 -->
- <property name="mapperLocations" value="classpath*:mappers/*Mapper.xml"></property>
- <!--mybatis配置文件位置-->
- <property name="configLocation" value="classpath:mybatis-config.xml"></property>
- </bean>
-
- <!--4 自动扫描对象关系映射 -->
- <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <!--指定会话工厂,如果当前上下文中只定义了一个则该属性可省去 -->
- <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
- <!-- 指定要自动扫描接口的基础包,实现接口 -->
- <property name="basePackage" value="com.zhangguo.ssm01.dao"></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.ssm01.dao"></context:component-scan>
-
- <!--7 aspectj支持自动代理实现AOP功能 -->
- <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
- </beans>
7.4、路径引用问题
模块被引用后因为路径问题可能会现在异常,如:java.io.FileNotFoundException: Could not open ServletContext resource [/classpath*:mybatis-config.xml]
详细的异常日志如下:

View Code
spring在构造sqlSessionFactory这个bean时报错,原因是找不到配置文件:
Could not open ServletContext resource [/classpath*:mybatis-config.xml]
spring查找的路径是:/classpath*:mybatis-config.xml
而这个路径根本不是我们想要的,根本就是找错了地方。
但是我们配置文件给出的路径是:classpath*:mybatis-config.xml
我们将配置文件中下面的配置稍作修改,去掉classpath后面的 *
- <property name="configLocation" value="classpath*:mybatis-config.xml" />
改为:
- <property name="configLocation" value="classpath:mybatis-config.xml" />
之后,启动正常,没有报错。
不同的类加载器 classLoader 在处理 classpath* 时存在可移植性问题。如果在使用 classpath* 时报错,那么就应该去掉 * 直接使用classpath: ,如果还是报错,那么可以去掉classpath直接使用路径,在stackoverflow上有一个例子:http://stackoverflow.com/questions/6035464/could-not-open-servletcontext-resource
classpath* 和 classpath的区别:
classpath* prefix specifies that all classpath resources that match the given name must be obtained (internally, this essentially happens via a ClassLoader.getResources(...) call), and then merged to form the final application context definition.
1)classpath* 它会搜索所有的 classpath,找到所有符合条件的文件,包括jar文件中的配置文件。而classpath不会到jar文件中去寻找。
2)classpath* 存在可移植性问题,遇到问题时,应该使用classpath.
3)其实一般情况下我们根本没有必要去使用classpath*,直接使用classpath就好了。
7.5、SqlSessionFactoryBean
能被Spring IOC容器管理的原因就是FactoryBean这个接口了,这是个支持泛型的接口:
- 能被Spring IOC容器管理的原因就是FactoryBean这个接口了,这是个支持泛型的接口:
- public interface FactoryBean<T> {
- @Nullable
- T getObject() throws Exception;
-
- @Nullable
- Class<?> getObjectType();
-
- default boolean isSingleton() {
- return true;
- }
- }
- 当实现了这个接口的Bean在配置为被Spring接管时,存入IOC容器中的实例类型将会是实例化泛型的那个类型,从IOC容器中获取时也是实例化泛型的那个类型,这种情况下,Spring 将会在应用启动时为你 创建SqlSessionFactory对象,然后将它以 SqlSessionFactory为名来存储。当把这个bean注入到Spring中去了以后,IOC容器中的其他类型就可以拿到SqlSession实例了,就可以进行相关的SQL执行任务了。
7.6、定义映射器与数据访问接口
goodsMapper.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.zhangguo.ssm01.dao.GoodsDao">
- <!--id应该是接口中的方法,结果类型如没有配置别名则应该使用全名称 -->
- <select id="getAll" resultType="Goods">
- SELECT
- goods.id,
- goods.`name`,
- goods.price,
- goods.picture
- FROM
- goods
- <where>
- <if test="name!=null and name!=''">
- and NAME like concat(concat('%',#{name}),'%')
- </if>
- </where>
- </select>
- </mapper>
GoodsDao接口
- package com.zhangguo.ssm01.dao;
- import com.zhangguo.ssm01.entity.Goods;
- import org.apache.ibatis.annotations.Param;
- import java.util.List;
- public interface GoodsDao {
- /**获得所有商品*/
- public List<Goods> getAll(@Param("name") String name);
- }
7.7、测试及运行结果
GoodsDaoTest测试类
- package com.zhangguo.ssm01.dao;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- import org.springframework.stereotype.Service;
- @Service
- public class GoodsDaoTest {
- @Autowired
- GoodsDao dao;
- public static void main(String[] args) {
- ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
- GoodsDao dao=ctx.getBean(GoodsDao.class);
- System.out.println(dao.getAll("特产"));
- }
- }
测试结果

此时的项目结构

7.8、使用JUnit+Spring测试
1、添加引用
除了junit4和spring的jar包,还需要spring-test.jar。引入如下依赖:
版本
- <junit.version>4.12</junit.version>
- <spring-test.version>4.3.18.RELEASE</spring-test.version>
依赖
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit.version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-test</artifactId>
- <version>${spring-test.version}</version>
- </dependency>
2、编写测试用例
- package dao.test;
- import com.zhangguo.ssm01.dao.GoodsDao;
- 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;
- //指定bean注入的配置文件
- @ContextConfiguration(locations = { "classpath:applicationContext.xml"})
- //使用标准的JUnit @RunWith注释来告诉JUnit使用Spring TestRunner
- @RunWith(SpringJUnit4ClassRunner.class)
- public class GoodsDaoTest {
- @Autowired
- GoodsDao dao;
- @Test
- public void testGetAll(){
- System.out.println(dao.getAll(null));
- }
- }
解释
- @RunWith(SpringJUnit4ClassRunner.class)
- //SpringJUnit支持,由此引入Spring-Test框架支持!
- @ContextConfiguration(locations = "classpath:applicationContext.xml")
- //多个配置文件的话可以用数组表示{“applicationContext.xml”,“applicationContext1.xml”},下面我会贴我的配置文件,只有一个配置文件;
- @ContextConfiguration("/spring-context.xml")
- //放在根路径下(即类路径下),然后<import resource="spring-dao.xml" />所有的配置文件和资源文件
- @Transactional
- //这个非常关键,如果不加入这个注解配置,事务控制就会完全失效!
- @TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
- //这里的事务关联到配置文件中的事务控制器(transactionManager = "transactionManager"),同时指定自动回滚(defaultRollback = true)。这样做操作的数据才不会污染数据库!
- @AbstractTransactionalDataSourceSpringContextTests
- //要想构建这一系列的无污染纯绿色事务测试框架就必须找到这个基类!(即所有事务均不生效)
- @ActiveProfiles(value="dev")
- //配置环境选择
运行结果:

3、让spring管理事务又不污染数据库
- package dao.test;
- import com.zhangguo.ssm01.dao.GoodsDao;
- import org.junit.Assert;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.test.annotation.Rollback;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
- import org.springframework.test.context.transaction.TransactionConfiguration;
- import org.springframework.transaction.annotation.Transactional;
- import java.util.ArrayList;
- import java.util.List;
- @ContextConfiguration({"classpath:applicationContext.xml"})
- @RunWith(SpringJUnit4ClassRunner.class)
- @Transactional
- //@TransactionConfiguration(defaultRollback = true) //被弃用
- @Rollback(true) //是否回滚
- public class GoodsDaoTestPro {
- @Autowired
- GoodsDao dao;
- @Test
- public void testGetAll(){
- System.out.println(dao.getAll(null));
- }
- @Test
- public void testDeleteByIds(){
- List<Integer> ids=new ArrayList<Integer>();
- ids.add(1);
- ids.add(2);
- ids.add(5);
- int rows=dao.deleteByIds(ids);
- Assert.assertEquals(3,rows);
- }
- }
结果:

数据并没有被删除,回滚了

4、注意事项
*SpringJUnit4ClassRunner requires JUnit 4.12 or higher,Junit要求4.12或更高版本
*测试方法命名不能叫test方法,类也不能叫Test类
八、完成Service服务模块
服务接口:
- package com.zhangguo.ssm01.service;
- import com.zhangguo.ssm01.entity.Goods;
- import java.util.List;
- public interface GoodsService {
- List<Goods> queryGoodsByName(String name);
- }
服务实现:
- package com.zhangguo.ssm01.service.impl;
- import com.zhangguo.ssm01.dao.GoodsDao;
- import com.zhangguo.ssm01.entity.Goods;
- import com.zhangguo.ssm01.service.GoodsService;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.List;
- @Service
- public class GoodServiceImpl implements GoodsService {
- @Autowired
- GoodsDao goodsDao;
- @Override
- public List<Goods> queryGoodsByName(String name) {
- if(StringUtils.isEmpty(name)){
- name=null;
- }
- return goodsDao.getAll(name);
- }
- }
九、完成WebUI表示模块
9.1、创建目录

9.2、添加依赖
pom.xml
9.3、配置Spring MVC中心控制器
web.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://java.sun.com/xml/ns/javaee"
- xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
- 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.xml</param-value>
- </context-param>
-
- <!--Spring MVC 前置Servlet,中心控制器 -->
- <servlet>
- <servlet-name>springmvc</servlet-name>
- <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
- <init-param>
- <param-name>contextConfigLocation</param-name>
- <!--Spring MVC配置文件路径 -->
- <param-value>classpath*:springmvc-servlet.xml</param-value>
- </init-param>
- <!-- 启动动优先级,越小越早加载 -->
- <load-on-startup>1</load-on-startup>
- <!--Servlet3.0以上文件上传配置 -->
- <multipart-config>
- <!--上传文件的最大限制5MB -->
- <max-file-size>5242880</max-file-size>
- <!--请求的最大限制20MB -->
- <max-request-size>20971520</max-request-size>
- <!--当文件的大小超过临界值时将写入磁盘 -->
- <file-size-threshold>0</file-size-threshold>
- </multipart-config>
- </servlet>
- <!-- Servlet访问的路径映射,所有的访问都必须经过调度用的前置控制品 -->
- <servlet-mapping>
- <servlet-name>springmvc</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
-
- <!--编码过滤器 -->
- <filter>
- <filter-name>characterEncodingFilter</filter-name>
- <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
- <init-param>
- <param-name>encoding</param-name>
- <param-value>UTF-8</param-value>
- </init-param>
- <init-param>
- <param-name>forceEncoding</param-name>
- <param-value>true</param-value>
- </init-param>
- </filter>
- <!-- 路径映射 -->
- <filter-mapping>
- <filter-name>characterEncodingFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
- </web-app>
9.4、配置Spring MVC
springmvc-servlet.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"
- xmlns:mvc="http://www.springframework.org/schema/mvc"
- 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/mvc
- http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
-
- <!-- 自动扫描包,实现支持注解的IOC -->
- <context:component-scan base-package="com.zhangguo.ssm01" />
-
- <!-- Spring MVC不处理静态资源 -->
- <mvc:default-servlet-handler />
-
- <!-- 支持mvc注解驱动 -->
- <mvc:annotation-driven enable-matrix-variables="true" />
-
- <!-- 配置映射媒体类型的策略 -->
- <bean
- class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
- <property name="removeSemicolonContent" value="false" />
- </bean>
-
- <!-- 内部视图解析器,JSP与JSTL模板 -->
- <bean
- class="org.springframework.web.servlet.view.InternalResourceViewResolver"
- id="internalResourceViewResolver">
- <!--指定视图渲染类 -->
- <property name="viewClass"
- value="org.springframework.web.servlet.view.JstlView" />
- <!--自动添加到路径中的前缀 -->
- <property name="prefix" value="/WEB-INF/views/" />
- <!--自动添加到路径中的后缀 -->
- <property name="suffix" value=".jsp" />
- <!--设置所有视图的内容类型,如果视图本身设置内容类型视图类可以忽略 -->
- <property name="contentType" value="text/html;charset=UTF-8" />
- <!-- 优先级,越小越前 -->
- <property name="order" value="1" />
- </bean>
-
- <!--文件上传解析器 -->
- <!--Spring MVC默认不能识别multipart格式的文件内容 -->
- <bean id="multipartResolver"
- class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
- </bean>
-
- </beans>
RequestMappingHandlerMapping,主要做的工作是将Contoller的带RequestMapping方法,添加到处理方法映射器和路径方法解决器中。
RequestMappingHandlerAdapter主要是解决请求的,会话,请求头部处理,数据的绑定等,然后从容器中,获取handlerMethod,处理业务逻辑,获取数据,并渲染视图,返回。
RequestMappingHandlerMapping会把Controller里面带有@RequestMapping注解的方法都加到一个容器里面,然后RequestMappingHandlerAdapter根据里面的自定义配置可以对经过这些方法的请求的数据做一些额外的处理。例如我想对带有@RequestMapping注解的方法的相应数据做一些处理,比如方法返回的都是实体对象类型的数据,我想配置把这些实体对象转换成json串再返回给前端,可以像如下这么配置:
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
-
- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
- <property name="webBindingInitializer"><!-- 日期绑定 -->
- <bean class="com.qlk.cloud.baymax.common.utils.BindingInitializer"/>
- <!-- <bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
- <property name="conversionService">
- <bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean"></bean>
- </property>
- </bean> -->
- </property>
- <property name="messageConverters">
- <list>
- <ref bean="stringHttpMessageConverter"/>
- <ref bean="mappingJacksonHttpMessageConverter"/>
- </list>
- </property>
- </bean>
-
- <bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter">
- <constructor-arg value="UTF-8"/>
- <property name="supportedMediaTypes">
- <list>
- <value>text/plain;charset=UTF-8</value>
- <value>application/json;charset=UTF-8</value>
- </list>
- </property>
- </bean>
-
- <!-- 处理JSON数据转换的 -->
- <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
- <!-- 为了处理返回的JSON数据的编码,默认是ISO-88859-1的,这里把它设置为UTF-8,解决有乱码的情况 -->
- <property name="supportedMediaTypes">
- <list>
- <value>text/plain;charset=UTF-8</value>
- <value>application/json;charset=UTF-8</value>
- </list>
- </property>
- </bean>
-
9.5、添加控制器
GoodsController.java
- package com.zhangguo.ssm01.weui.controller;
- import com.zhangguo.ssm01.service.GoodsService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- @Controller
- @RequestMapping("/goods")
- public class GoodsController {
- @Autowired
- GoodsService goodsService;
- @RequestMapping("/queryGoods")
- public String queryGoods(Model model,String name){
- model.addAttribute("goods",goodsService.queryGoodsByName(name));
- return "goods/queryGoods";
- }
- }
9.6、添加视图
queryGoods.jsp
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <html>
- <head>
- <title>商品列表</title>
- <meta http-equiv="content-type" content="text/html;charset=utf-8" />
- </head>
- <body>
- <h2>商品列表</h2>
-
- <table width="100%" border="1">
- <c:forEach items="${goods}" var="item">
- <tr>
- <td>${item.id}</td>
- <td>${item.name}</td>
- <td>${item.price}</td>
- <td>${item.picture}</td>
- </tr>
- </c:forEach>
- </table>
-
- </body>
- </html>
十、测试并运行
配置tomcat,添加部署项目:

运行结果

十一、示例下载
https://git.dev.tencent.com/zhangguo5/SSM01.git
十二、视频
https://www.bilibili.com/video/av16991874/
十三、作业
1、完成一个商品管理功能,要求如下:
1.1、SSM、必须使用Spring+Spring MVC+MyBatis框架集成
1.2、两个表,(商品,类型)
1.3、查询,可多条件搜索,如按名称与价格(区间)
1.4、删除,提示
1.5、多删除
1.6、添加,验证
1.7、多添加(选作)
1.8、更新
1.9、分页
1.10、上传图片
1.11、导出Excel
1.12、上传并导入Excel(选作)
1.13、同时使用JSTL与AJAX完成
UI风格如下所示:

周二检查,周五前考试
2、完成个人项目前后台所有页面,周一展示。
3、SSM内部测试
要求使用SSM+Maven+MySQL+AJAX+JSTL实现一个简单的会员管理系统
3.1、用户注册(用户名、密码、邮箱、手机号、注册时间) (30分)
密码要求MD5加密,存储在数据库中的密码使用MD5加密

注册时要求用户名与手机号不能重复。
3.2、用户登录 (15分)
登录时验证用户名与密码是否正确,密码不要需要解密,只需要将用户提交的密码MD5加密后比较即可
登录成功后后台显示当前用户的用户名如:当前用户:张果
如果用户没有登录是不允许直接绕到后台的,如在浏览器输入后台地址直接进入,可以使用过滤器或其它验证方式

后台首页 (5分)

3.3、会员管理
编辑会员 (10分)
重置密码 (5分)
删除会员 (5分)
多条件查询会员(用户名、邮箱、手机号)(10分)
分页 (5分)
退出系统 (5分)
导出所有会员CSV (5分)
导入(选作)(5分)

素材下载