Spring+SpringMVC+MyBatis框架整合

一、SSM框架整合

1.回顾

MyBatis环境

编写SqlMapConfig.xml核心配置文件,配置连接信息、加载mapper文件、别名等等

需要编写Mapper.xml和Mapper接口、使用namespace关联

需要引入mybatis依赖

Spring环境

编写application.xml核心配置文件,注入对象

配置包扫描,使用注解注入@Controller、@Service、@Repository、@Competent

使用@Autowird、@Qualifier、@Recource注解注入对象

配置aop切面、

配置aop事务,开启aop事务支持​​<tx:annotation-driven transaction-manager="transactionManager" />​​​并设置事务管理器使用、​​@Transacational​​注解配置aop事务

需要提供数据源、事务管理器

SpringMVC环境

编写dispatcher-servlet.xml核心配置文件

包扫描、开启springmvc注解支持​​<mvc:annotation-driven/>​​、放行静态资源、视图解析器、拦截器等

2.创建项目

SSM第九讲  Spring+SpringMVC+MyBatis框架整合_mybatis

整合所需依赖:

<dependencies> 
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--spring、springmvc依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--jdbc包(事务管理器在这里)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--aop包-->
<!--mybatis整合spring包-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--jstl包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!--servletAPI-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!--spring整合junit-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
<!--springmvc对象转json支持包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>

<!--显示 spring5、mybatis日志 依赖-->
<dependency><!-- log4j2的API实现包 -->
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.1</version>

</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.0</version>
</dependency>
</dependencies>

db.properties

druid.username=root
druid.password=123456
druid.url=jdbc:mysql:///privilege?characterEncoding=utf8
druid.driverClassName=com.mysql.jdbc.Driver

3.spring5 日志整合

spring中同样使用了日志进行信息的输出,但是spring4和spring5之间的日志又有些不同,spring5需要通过jcl和log4j2实现。

各种日志技术简述:

log4j,jcl,log4j2,slf4j

日志接口(slf4j)

slf4j是对所有日志框架制定的一种规范、标准、接口,并不是一个框架的具体的实现,因为接口并不能独立使用,需要和具体的日志框架实现配合使用(如slf4j-log4j12、log4j-slf4j-impl)

log4j

log4j是apache实现的一个开源日志组件

log4j2

og4j2是log4j 1.x和logback的改进版,采用了一些新技术(无锁异步、等等),使得日志的吞吐量、性能比log4j 1.x提高10倍,并解决了一些死锁的bug,而且配置更加简单灵活

jcl:

common.logging和log4j2的集成包

配置文件:


log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>

<Loggers>
<Logger name="cn.nyse.dao" level="trace" >
<AppenderRef ref="Console"/>
</Logger>
<Root level="debug">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>

4.Spring整合MyBatis

Spring整合MyBatis的核心就是把MyBatis的核心配置文件(SqlMapConfig.xml)给去除

让我们回想一下MyBatis的核心配置文件中都配了什么?


  1. 别名
  2. 数据源配置
  3. 加载mapper文件

mybatis-spring.jar

MyBatis和Spring的集成工作是由MyBatis团队完成的。所以我们首先要先引入MyBatis和Spring的集成依赖包


  • SqlSession Factory Bean
    为整合应用提供 SqlSession对象资源
  • MapperFactory Bean

根据指定 Mapper接口生成Bean实例

  • MapperScanner Configurer

根据指定包批量扫描 Mapper接口井生成实例


SqlSessionFactoryBean

在单独使用Mybatis时,所有操作都是围绕SqlSession展开的, Sqlsession是通过 SqlSession Factory获取的,Sqlsession Factory又是通过 Sqlsession Factory Builder创建生成在 Spring和 MyBatis整合应用时,同样需要 SqlSession,mybatis-spring ja提供了一个 SqlSession Factory Bean这个组件作用就是通过原 SqlSession Factory Builder生成SqlSession Factory对象,为整合应用提供 Sqlsession对象。

MapperScannerConfigurer

在定义MapperScannerConfigurer时,只需要指定一个basePackage即可, basePackage用于指定 Mapper接口所在的包,在这个包及其所有子包下面的 Mapper接口都将被搜索到,并把它们注册为一个个MapperFactory Bean对象,多个包之间可以使用逗号或者分号进行分隔


spring和mybatis整合配置类

/*
整合spring与mybatis
整合事务

1.读取配置文件,声明数据源对象
2.声明配置SqlSessionFactoryBean
3.声明配置MapperScannerConfigurer
4.声明配置事务管理器
5.开启事务注解支持
6.开启包扫描,扫码服务层
*/
@Configuration
//@PropertySource(encoding = "utf-8",value = "classpath:db.properties")
//开启mapper扫描,自动扫描mapper包下的接口,并且创建代理子类 替代MapperScannerConfigurer
//annotationClass指定注解标记类
@MapperScan(basePackages = {"cn.nyse.dao"})
@EnableTransactionManagement//开启事务注解支持
@ComponentScan(basePackages = "cn.nyse.service")
public class ContextConfig {

//如果Properties文件的属性名命名符合configFromPropety的参数Properties的命名规则,则自动赋值
@Bean
public DruidDataSource getDataSource(){
Properties props = new Properties();
try {
props.load(ContextConfig.class.getClassLoader().getResourceAsStream("db.properties"));
DruidDataSource dataSource = new DruidDataSource();
dataSource.configFromPropety(props);
return dataSource;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}


//DruidDataSource dataSource:spring容器会自动从自己的bean里面按照类型查找是否存在
//如果有则注入给改方法参数
@Bean
public SqlSessionFactoryBean getFactoryBean(DruidDataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
//1.配置数据源
factoryBean.setDataSource(dataSource);

//2.配置别名
factoryBean.setTypeAliasesPackage("cn.nyse.entity");


org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration ();
configuration.setLogImpl(Log4j2Impl.class);//配置mybatis 日志类

configuration.setMapUnderscoreToCamelCase(true);//开启支持驼峰命名
factoryBean.setConfiguration(configuration);
//xml映射文件 配置
// PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();
// try {
// factoryBean.setMapperLocations(pathMatchingResourcePatternResolver.getResources("classpath:/cn/nyse/dao/*.xml"));
// } catch (IOException e) {
// e.printStackTrace();
// }

return factoryBean;

}

//创建事务管理器bean
@Bean
public DataSourceTransactionManager getTransactionManager(DruidDataSource dataSource){
return new DataSourceTransactionManager(dataSource);

}

}

实体类

public class User {
private Integer id;
private String username;
private String password;
private String birthday;
private String address;

@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", birthday='" + birthday + '\'' +
", address='" + address + '\'' +
'}';
}

public Integer getId() {
return id;
}

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

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getBirthday() {
return birthday;
}

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

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}
}

dao层

public interface UserMapper {
@Select("select * from user where id=#{id}")
User findById(Integer id);
}

5.spring声明式事务


  • 事务管理是企业级应用程序开发中必不可少的技术, 用来确保数据的完整性和一致性.。
  • 事务就是一系列的动作, 它们被当做一个单独的工作单元. 这些动作要么全部完成, 要么全部不起作用。

事务的四个关键属性(ACID):

属性

解释

原子性(atomicity)

事务是一个原子操作, 由一系列动作组成. 事务的原子性确保动作要么全部完成要么完全不起作用

一致性(consistency)

一旦所有事务动作完成, 事务就被提交. 数据和资源就处于一种满足业务规则的一致性状态中

隔离性(isolation)

可能有许多事务会同时处理相同的数据, 因此每个事物都应该与其他事务隔离开来, 防止数据损坏

持久性(durability)

一旦事务完成, 无论发生什么系统错误, 它的结果都不应该受到影响. 通常情况下, 事务的结果被写到持久化存储器中


  • Spring 的核心事务管理抽象是PlatformTransactionManager它为事务管理封装了一组独立于技术的方法. 无论使用Spring 的哪种事务管理策略(编程式或声明式), 事务管理器都是必须的。
  • DataSourceTransactionManager:在应用程序中只需要处理一个数据源, 而且通过 JDBC 存取。
  • JtaTransactionManager: 在 JavaEE 应用服务器上用 JTA(Java Transaction API) 进行事务管理
  • HibernateTransactionManager:用 Hibernate 框架存取数据库
  • 事务管理器以普通的 Bean 形式声明在 Spring IOC 容器中


spring注解事务配置:

1.引入事务依赖包

2.在spring配置文件中添加spring事务管理器

3.在spring配置文件中开启事务注解支持

4.在需要管理事务的服务层上添加事务注解


service层

public interface UserService {
User findById(Integer id);
}
@Service            //注入到ioc容器
@Transactional
public class UserServiceImpl implements UserService {

@Autowired
private UserMapper userMapper;

public User findById(Integer id){
return userMapper.findById(id);
}
//通过模拟异常查看事务回滚情况
public User insertBatch(User user){
int result = userMapper.insert(user);
String str = null;//模拟异常
str.length;
result += userMapper.insert(user);
return result;
}


}

测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ContextConfig.class)
public class TestSSM {


@Autowired
UserService userService;


@Test
public void testFindById(){
User user = userService.findById(1);
System.out.println(user);
}
}

6.Spring整合SpringMVC

配置web.xml:

<!--监听web容器启动就加载ioc容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<!--配置全局参数,让监听器能够识别到spring的配置文件所在-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>cn.nyse.config.ContextConfig</param-value>
</context-param>
<!--spring核心(前端控制器)-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置springmvc配置文件的位置-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>cn.nyse.config.SpringmvcConfig</param-value>
</init-param>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<!--拦截除jsp之外所有请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>


<!--处理中文乱码过滤器-->
<filter>
<filter-name>characterEncoding</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>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>


ContextLoderListener,DispatcherServlet两者都是通过加载配置文件创建spring容器实例

ContextLoderListener:

监听器,启动Web容器时,自动通过context-param的配置装配spring容器的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。context-param的作用就是设置监听器的初始化属性

通过ContextLoderListener创建的spring容器,是应用中的spring父容器,其他spring子容器共用父容器

常用于加载除Controller层以外的service层、dao层等组件

DispatcherServlet:

servlet,web容器启动后实例化,比listener、filter的实例化都要晚,通过读取init-param来配置装配spring容器的配置信息。

通过dispatcherServlet创建的spring容器是子容器,会自动将spring父容器传入

用于加载Controller层


springmvc配置类

@Configuration
@ComponentScan(basePackages = "cn.nyse.controller")//开启报扫描
@EnableWebMvc//开启mvc注解支持
public class SpringmvcConfig implements WebMvcConfigurer {

//容器管理视图bean
@Bean
public InternalResourceViewResolver getResourvler(){
return new InternalResourceViewResolver("/WEB-INF/view/",".jsp");// /WEB-INF/view/fee/fee_list.jsp
}


//配置默认静态资源放行

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();//放行静态资源
}




}

controller:

package com.dfbz.controller;

import com.dfbz.entity.User;
import com.dfbz.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/user")
public class UserController {

@Autowired
private UserService userService;

@RequestMapping("/findById")
@ResponseBody
public User findById(Integer id){

return userService.findById(id);
}
}