1、基本概念

1.1、Spring

Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框

1.2、SpringMVC

Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring MVC 分离了控制器、模型对象、分派器以及处理程序对象的角色,这种分离让它们更容易进行定制。

1.3、MyBatis

MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis 。MyBatis是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)MyBatis 消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。

2、环境搭建

2.1 构建Maven的web项目

2.2 搭建项目

3、SSM整合

3.1 添加MyBatis相关依赖

<!-- MyBatis核心包 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.0-SNAPSHOT</version>
</dependency>
<!-- MyBatis-Spring包 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.2.3</version>
</dependency>
<!-- 数据库驱动(mysql) -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>${mysql.version}</version>
</dependency>
 <!-- 导入dbcp的jar包,用来在Spring配置文件中配置数据库 -->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.2.2</version>
</dependency>

如果出现MyBatis依赖下载失败的问题,在pom.xml中添加仓库

<repositories>
    <repository>
        <id>mybatis-snapshot</id>
        <name>MyBatis Snapshot Repository</name>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>

3.2、建立JDBC属性文件

在src/main/resources中创建jdbc.properties配置文件(文件编码修改为utf-8)

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/spring-demo
username=root
password=celloud
#定义初始连接数
initialSize=0
#定义最大连接数
maxActive=20
#定义最大空闲
maxIdle=20
#定义最小空闲
minIdle=1
#定义最长等待时间
maxWait=60000

3.3 配置contextConfigLocation

在web.xml中加入配置

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/spring-mybatis.xml </param-value>
</context-param>

3.3 修改Spring配置文件

修改src/main/resources/springMVC.xml文件,加入以下配置:

配置数据源:

<!-- 引入配置文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:jdbc.properties"/>
</bean>

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="${driver}"/>
    <property name="url" value="${url}"/>
    <property name="username" value="${username}"/>
    <property name="password" value="${password}"/>
    <!-- 初始化连接大小 -->
    <property name="initialSize" value="${initialSize}"/>
    <!-- 连接池最大数量 -->
    <property name="maxActive" value="${maxActive}" />
    <!-- 连接池最大空闲 -->
    <property name="maxIdle" value="${maxIdle}" />
    <!-- 连接池最小空闲 -->
    <property name="minIdle" value="${minIdle}" />
    <!-- 获取连接最大等待时间 -->
    <property name="maxWait" value="${maxWait}" />
</bean>

配置Spring与MyBatis的整合:

<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->  
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />  
    <!-- 自动扫描mapping.xml文件 -->  
    <property name="mapperLocations" value="classpath:com/celloud/mapper/*.xml" />  
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.celloud.mapper"/>
    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
</bean>  

配置事务:

使用Spring的org.springframework.jdbc.datasource.DataSourceTransactionManager工具管理事务

<!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

需要添加spring-jdbc的依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>

注解方式配置事务(不推荐):

<!-- 注解方式配置事物 -->
<!-- <tx:annotation-driven transaction-manager="transactionManager" /> -->

拦截器方式配置事务:

 <!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 事务传递特性 -->
        <tx:method name="add*" propagation="REQUIRED"/>
        <tx:method name="create*" propagation="REQUIRED"/>
        <tx:method name="modify*" propagation="REQUIRED"/>
        <tx:method name="update*" propagation="REQUIRED"/>
        <tx:method name="delete*" propagation="REQUIRED"/>
        <tx:method name="remove*" propagation="REQUIRED"/>
        <tx:method name="find*" propagation="SUPPORTS"/>
        <tx:method name="query" propagation="SUPPORTS"/>
        <tx:method name="search*" propagation="SUPPORTS"/>
        <tx:method name="*" propagation="SUPPORTS"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="transactionPointcut" expression="execution(* com.celloud.service.*.*(..))"/>
    <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
</aop:config>

此配置需依赖AspectJ包,导入依赖:

<!-- 面向切面的框架 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.7.3</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.7.3</version>
</dependency>

4、测试

4.1、建立测试数据库及表结构

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(255) NOT NULL,
  `name` varchar(255) NOT NULL,
  `age` int(11) DEFAULT NULL,
  `birthday` date DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

4.2、利用MyBatis Generator自动创建代码

参考博文:http://blog.csdn.net/zhshulin/article/details/23912615

生成的model类:

package com.celloud.model;

import java.util.Date;

public class Student {
    private Integer id;

    private String code;

    private String name;

    private Integer age;

    private Date birthday;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code == null ? null : code.trim();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

生成的dao接口

package com.celloud.mapper;

import com.celloud.model.Student;

public interface StudentMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(Student record);

    int insertSelective(Student record);

    Student selectByPrimaryKey(Integer id);

    int updateByPrimaryKeySelective(Student record);

    int updateByPrimaryKey(Student record);
}

生成的mapper文件

<?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.celloud.mapper.StudentMapper" >
  <resultMap id="BaseResultMap" type="com.celloud.model.Student" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="code" property="code" jdbcType="VARCHAR" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="age" property="age" jdbcType="INTEGER" />
    <result column="birthday" property="birthday" jdbcType="DATE" />
  </resultMap>
  <sql id="Base_Column_List" >
    id, code, name, age, birthday
  </sql>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select 
    <include refid="Base_Column_List" />
    from student
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from student
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.celloud.model.Student" >
    insert into student (id, code, name, 
      age, birthday)
    values (#{id,jdbcType=INTEGER}, #{code,jdbcType=VARCHAR}, #{name,jdbcType=VARCHAR}, 
      #{age,jdbcType=INTEGER}, #{birthday,jdbcType=DATE})
  </insert>
  <insert id="insertSelective" parameterType="com.celloud.model.Student" >
    insert into student
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        id,
      </if>
      <if test="code != null" >
        code,
      </if>
      <if test="name != null" >
        name,
      </if>
      <if test="age != null" >
        age,
      </if>
      <if test="birthday != null" >
        birthday,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="id != null" >
        #{id,jdbcType=INTEGER},
      </if>
      <if test="code != null" >
        #{code,jdbcType=VARCHAR},
      </if>
      <if test="name != null" >
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        #{age,jdbcType=INTEGER},
      </if>
      <if test="birthday != null" >
        #{birthday,jdbcType=DATE},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.celloud.model.Student" >
    update student
    <set >
      <if test="code != null" >
        code = #{code,jdbcType=VARCHAR},
      </if>
      <if test="name != null" >
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="age != null" >
        age = #{age,jdbcType=INTEGER},
      </if>
      <if test="birthday != null" >
        birthday = #{birthday,jdbcType=DATE},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.celloud.model.Student" >
    update student
    set code = #{code,jdbcType=VARCHAR},
      name = #{name,jdbcType=VARCHAR},
      age = #{age,jdbcType=INTEGER},
      birthday = #{birthday,jdbcType=DATE}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

4.3、建立Service接口和实现类

StudentService接口

package com.celloud.service;

import com.celloud.model.Student;

public interface StudentService {

    public boolean addStudent(Student student);

    public Student getById(int id);

}

StudentServiceImpl实现类

package com.celloud.service.impl;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.celloud.mapper.StudentMapper;
import com.celloud.model.Student;
import com.celloud.service.StudentService;

@Service("student")
public class StudentServiceImpl implements StudentService{
    @Resource
    private StudentMapper mapper;

    @Override
    public boolean addStudent(Student student) {
        return mapper.insert(student)>0;
    }

    @Override
    public Student getById(int id) {
        return mapper.selectByPrimaryKey(id);
    }

}

4.4、启动tomcat出现异常

严重: Servlet [springMVC] in web application [/springMVC-demo] threw load() exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.celloud.mapper.StudentMapper] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@javax.annotation.Resource(shareable=true, lookup=, name=, description=, authenticationType=CONTAINER, type=class java.lang.Object, mappedName=)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1373)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1119)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.autowireResource(CommonAnnotationBeanPostProcessor.java:508)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.getResource(CommonAnnotationBeanPostProcessor.java:486)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor$ResourceElement.getResourceToInject(CommonAnnotationBeanPostProcessor.java:615)
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:308)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:835)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:667)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:633)
    at org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:681)
    at org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:552)
    at org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:493)
    at org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:136)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1284)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1197)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1087)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:5253)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5543)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardContext.reload(StandardContext.java:4020)
    at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:425)
    at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1344)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1545)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1555)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1555)
    at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1523)
    at java.lang.Thread.run(Thread.java:745)

异常原因:com.celloud.mapper包下的xml文件没有发布到target下,故tomcat找不到StudentMapper接口对应的配置文件。

解决方式:在pom.xml中加入配置

<resources>
    <resource>
        <directory>${basedir}/src/main/java</directory>
        <targetPath>${basedir}/target/classes</targetPath>
        <includes>
            <include>**/*.xml</include>
        </includes>
    </resource>
</resources>

4.5、建立测试类

使用Spring提供的单元测试工具进行单元测试

需加入依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${spring.version}</version>
    <scope>test</scope>
</dependency>

单元测试类:

package com.celloud.service;

import java.util.Date;

import javax.annotation.Resource;

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

import com.celloud.model.Student;

@RunWith(SpringJUnit4ClassRunner.class) // 表示继承了SpringJUnit4ClassRunner类
@ContextConfiguration(locations = { "classpath:springMVC.xml" })
public class StudentServiceTest {
    @Resource
    private StudentService service;

    @Test
    public void testAddStudent() {
        service.getById(0);
    }

    @Test
    public void testGetById() {
        Student student = new Student();
        student.setAge(22);
        student.setBirthday(new Date());
        student.setCode("1002");
        student.setName("王二麻子");
        service.addStudent(student);
    }

}

/src/main/resources中的配置文件复制到/src/test/resources

运行单元测试,如无异常,表示成功。