spring整合
1.整合思路
项目中有两个工厂
- DispatcherServlet启动的SpringMVC工厂==负责生产C及SpringMVC自己的系统组件
- ComtextLoaderListener启动的Spring工厂==负责生产其他所有组件
- SpringMVC的工厂会被设置为Spring工厂的子工厂,可以随意获取Spring工厂中的组件
- 整合过程,就是累加:代码+依赖+配置。然后将service注入给controller即可
2.整合技巧
- 两个工厂不能有彼此的侵入,即生产的组件不能有重合
3.整合过程
- 导入依赖pom.xml
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>ssm01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--Spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<!--spring-mybatis整合-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.5</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.47</version>
</dependency>
<!--连接池druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!--SpringMVC依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<!--jstl支持-->
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<!--servlet编译环境-->
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<!--jsp编译环境-->
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>*.xml</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/resource</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</build>
</project>
- SpringMVC配置文件
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: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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd ">
<!--注解的扫描-->
<context:component-scan base-package="cn.ozl.web"/>
<!--启动mvc注解驱动-->
<mvc:annotation-driven>
<!--安装FastJson 转换器-->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!--声明转换类型:json-->
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!--视图解析器-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!--静态资源访问 匹配所有请求-->
<mvc:default-servlet-handler/>
</beans>
- Spring配置文件(整合Mybatis配置)
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns="http://www.springframework.org/schema/beans"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--DataSource的properties-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--DataSource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<!--基本配置-->
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<!--配置初始化大小,最小,最大-->
<property name="initialSize" value="${jdbc.init}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxActive" value="${jdbc.maxActive}"/>
<!--配置获取连接等待超时的时间-->
<property name="maxWait" value="60000"/>
<!--配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒-->
<property name="timeBetweenEvictionRunsMillis" value="60000"/>
<!--配置一个连接在池中最小生存的时间,单位是毫秒-->
<property name="minEvictableIdleTimeMillis" value="300000"/>
</bean>
<!--SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--注入连接池-->
<property name="dataSource" ref="dataSource"/>
<!--注入mapper文件信息-->
<property name="mapperLocations">
<list>
<value>classpath:cn/ozl/dao/*.xml</value>
</list>
</property>
<!--为mapper文件中的实体定义缺省包路径-->
<property name="typeAliasesPackage" value="cn.ozl.entity"></property>
</bean>
<!--Dao MappingScannerConfigurer-->
<!--管理DAO实现类的创建,并创建DAO对象,存入工厂管理-->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="cn.ozl.dao"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!--告知Spring注解位置,开启扫描注解-->
<context:component-scan base-package="cn.ozl"></context:component-scan>
<!--DataSourceTransactionManager-->
<!--引入一个事务管理器,其中依赖DataSource,借以获得连接,进而控制事务逻辑-->
<bean id="tx" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--@Transactional-->
<tx:annotation-driven transaction-manager="tx"></tx:annotation-driven>
</beans>
- 数据源属性文件
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false
jdbc.username=root
jdbc.password=root
jdbc.driver=com.mysql.jdbc.Driver
jdbc.init=1
jdbc.minIdle=1
jdbc.maxActive=3
- 配置web.xml
在项目启动时启动SpringMVC和Spring工厂
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--SpringMVC前端控制器
1.前端,接受所有请求
2.启动SpringMVC工厂 mvc.xml
3.SpringMVC调度管理
-->
<servlet>
<servlet-name>mvc_ozl</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc.xml</param-value>
</init-param>
<!--可选配置,不写就是懒汉式加载,写了就是饿汉式加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc_ozl</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!--过滤会进行:request.setCharacterEncoding("utf-8");-->
<filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--启动工厂-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
</web-app>
- 实体类
package cn.ozl.entity;
import java.util.Date;
public class User {
private Integer id;
private String username;
private String password;
private Boolean gender;
private Date registTime;
public User() {
}
public User(Integer id, String username, String password, Boolean gender, Date registTime) {
this.id = id;
this.username = username;
this.password = password;
this.gender = gender;
this.registTime = registTime;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", gender=" + gender +
", registTime=" + registTime +
'}';
}
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 Boolean getGender() {
return gender;
}
public void setGender(Boolean gender) {
this.gender = gender;
}
public Date getRegistTime() {
return registTime;
}
public void setRegistTime(Date registTime) {
this.registTime = registTime;
}
}
- Dao以及mapper
UserDao
public interface UserDao {
public List<User> queryUsers();
}
UserDao-Mapper.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="cn.ozl.dao.UserDao"><!--定位哪个Dao的接口进行描述-->
<select id="queryUsers" resultType="User">
select id,username,password,gender,regist_time registTime
from mybatis
</select>
</mapper>
- service以及实现类
UserService
public interface UserService {
List<User> queryUsers();
}
UserServiceImpl
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
@Transactional(propagation = Propagation.SUPPORTS)
public List<User> queryUsers() {
return userDao.queryUsers();
}
}
- 控制类
UserController
@Controller
public class UserController {
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
@GetMapping("/users")
public String queryUsers(Model model){
System.out.println("queryUsers");
List<User> users = userService.queryUsers();
model.addAttribute("users",users);
return "user";
}
@RequestMapping("/users/{id}")
public String queryOne(@PathVariable Integer id){
System.out.println("queryOne:"+id);
return "index";
}
@PutMapping("/users")
public String updateUser(User user){
System.out.println("updateUser:"+user);
return "index";
}
}
4.注意细节
- 因为DispatcherServlet启动的SpringMVC工厂是ContextLoadListener启动的Spring工厂的子容器.所以可以调用Spring工厂的bean组件
- SpringMVC和Spring配置文件都有注解扫描的配置
SpringMVC
<!--注解的扫描-->
<context:component-scan base-package="cn.ozl.web"/>
<!--启动mvc注解驱动-->
<mvc:annotation-driven>
<!--安装FastJson 转换器-->
<mvc:message-converters>
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!--声明转换类型:json-->
<property name="supportedMediaTypes">
<list>
<value>application/json</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
Spring
<!--告知Spring注解位置,开启扫描注解-->
<context:component-scan base-package="cn.ozl"></context:component-scan>
由于两个工厂注解扫描都扫了同个包下的controller,会造成工厂之间的侵入,所以需要另外配置解决侵入问题
SpringMVC
<!--注解的扫描-->
<context:component-scan base-package="cn.ozl.web" use-default-filters="false"><!--这个包下的所有注解都不识别-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/><!--只识别Controller注解的类下的注解-->
</context:component-scan>
Spring
<!--告知Spring注解位置,开启扫描注解-->
<!--包下的注解都扫描,除了Controller注解下的类的注解-->
<context:component-scan base-package="cn.ozl" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
为什么mvc配置注解扫描需要注解驱动?
- 因为使用springMVC必须配置的三大件:处理器映射器(HandlerMapping)、处理器适配器(HandlerApdaptor)、视图解析器,注解驱动代替了配置了处理器映射器和处理器适配
- 将 Object 数据转化为 JSON 数据,需要由消息转换器 HttpMessageConverter 完成。而转换器的开启,需要由注解驱动来完成