SSM的整合
SSM整合的整体框架
创建Web Maven项目
之前有说过,不会创建Web Maven项目的的可以看这篇文章
导入依赖
<properties>
<spring.version>5.3.22</spring.version>
</properties>
<dependencies>
<!-- SpringMVC的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring 持久化层的依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Mybatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.10</version>
</dependency>
<!-- Spring+Mybatis的整合依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<!-- 日志框架 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.11</version>
</dependency>
<!-- Spring与thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.15.RELEASE</version>
</dependency>
<!-- junit5 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
<!-- 默认的JSON依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
配置相关文件
配置web.xml文件
<!-- 配置核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 将spring-mvc.xml文件放在resources目录下 -->
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- encoding参数指定要使用的字符集名称 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 请求强制编码 -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 响应强制编码 -->
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这里使用的是html页面,如果想要默认支持jsp中的EL表达式,那么就更换以下的命名空间。这样就不用在每一个jsp页面都修改支持EL的属性 isELIgnored="false"了。
<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_3_1.xsd"
version="3.1">
配置 spring-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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置扫描的基包,例如扫描 @Component(组件)、@Service(服务)、@Controller(控制器)、@Repository(数据仓库)-->
<context:component-scan base-package="com.zhang"/>
<!-- 开启SpringMVC的注解驱动 -->
<mvc:annotation-driven/>
<!-- 开放静态资源,也就是说没有@RequestMapping的请求将放行 -->
<mvc:default-servlet-handler/>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
配置jdbc.properties文件
jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm_csdn
jdbc.driver=com.mysql.cj.jdbc.Driver
配置日志文件
# rootLogger是所有日志的根日志,修改该日志属性将对所有日志起作用
# 下面的属性配置中,所有日志的输出级别是info,输出源是con
log4j.rootLogger=debug, stdout
# MyBatis logging configuration...
log4j.logger.org.apache.ibatis=debug
## 指定类设置不同的输出级别
##log4j.logger.com.bjwl.test.TestMyBatis=debug
## 包名
log4j.logger.com.zhang=debug
# 定义输出源的输出位置是控制台
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
# 定义输出日志的布局采用的类
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.Target=System.out
# 定义日志输出布局
log4j.appender.stdout.layout.ConversionPattern=%d{MM-dd HH:mm:ss}[%p]%c%n -%m%n
创建实体类和dao层
实体类
@Data
public class User {
private Integer id;
private String userName;
private String password;
}
UserDao接口
@Repository("userDao")
public interface UserDao {
void add(User user);
User getUserById(Integer id);
}
在数据库中创建表
create table user(
id int not null primary key auto_increment,
username varchar(20),
password varchar(20)
)
UserDao接口的映射文件UserMapper.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.zhang.dao.UserDao">
<insert id="add" parameterType="user">
insert into user (username,password) values(#{username},#{password})
</insert>
<select id="getUserById" resultType="User">
select * from user where id = #{id}
</select>
</mapper>
配置mybatis-config.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- 通过这个配置完成Mybatis与数据库的连接 -->
<configuration>
<!-- 引入 jdbc.properties 文件-->
<properties resource="jdbc.properties"/>
<!-- 配置实体类的别名 -->
<typeAliases>
<package name="com.zhang.pojo"/>
</typeAliases>
<!-- 配置事务管理器 -->
<environments default="development">
<environment id="development">
<!--配置事务管理,采用JDBC的事务管理 -->
<transactionManager type="JDBC"></transactionManager>
<!-- POOLED:mybatis自带的数据源,JNDI:基于tomcat的数据源 -->
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>
</environment>
</environments>
<!-- 将mapper文件加入到配置文件中 -->
<mappers>
<!-- 因为还未创建任何映射文件,因此此时先不指向映射文件 -->
<mapper resource="com/zhang/mapper/UserMapper.xml"/>
</mappers>
</configuration>
配置spring-mybatis.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入连接数据库的属性文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 配置数据源DataSource -->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 配置SessionFactory -->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="druidDataSource"/>
<!-- 文件映射器,指定类文件,引入mybatis-config.xml文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 因为上面已经引入了mybatis-config.xml文件,且在mybatis-config.xml文件中配置了类的别名以及映射文件,因此不需要下面的配置了 -->
<!--<property name="mapperLocations" value="classpath:com/zhang/mapper/UserMapper.xml"/>-->
</bean>
<!-- Mapper 扫描指定的dao接口,生成代理类对象,放入容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zhang.dao"/>
<property name="sqlSessionFactoryBeanName" value="sessionFactory"/>
</bean>
</beans>
进行测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("springm-ybatis.xml");
UserDao UserDao = (UserDao) context.getBean("UserDao");
User user = new User();
user.setUsername("曹操");
user.setPassword("2345");
UserDao.add(user);
}
这里运行看 Spring与Mybatis 整合是否成功。如果数据插入成功,则意味着整合成功!
也就是说我们已经从 Dao --> SessionFactory
编写Service层和Controller层代码
业务层
public interface UserService {
void add(User user);
User getUserById(Integer id);
}
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserDao userDao;
@Override
public void add(User user) {
userDao.add(user);
}
@Override
public User getUserById(Integer id) {
return userDao.getUserById(id);
}
}
控制层
@RestController
public class UserController {
@Resource
private UserService userService;
@RequestMapping("/get")
public User getUser(Integer id){
return userService.getUserById(id);
}
}
再次完善之前的web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 将spring-mybatis.xml文件放在resources目录下 -->
<param-value>classpath:spring-mybatis.xml</param-value>
</context-param>
<!-- 通过ContextLoaderListener监听 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 配置核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 将spring-mvc.xml文件放在resources目录下 -->
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- encoding参数指定要使用的字符集名称 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 请求强制编码 -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 响应强制编码 -->
<init-param>
<param-name>forceResponseEncoding</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>
此时已经完成了SpringMVC 和Spring的整合。
说明一下整个文件的关联:web.xml --> spring-mvc.xml 和 spring-mybatis.xml --> mybatis-config.xml。
最后启动Tomcat服务器进行完整的SSM测试。启动成功后访问http://localhost:8080/get?id=1,如果返回了数据,则代表SSM整合成功了。
说明一下在web.xml中配置ContextLoaderListener的作用
首先在进行ssm整合的时候,此时会存在两个容器,一个是ContextLoaderListener创建的父容器(Spring容器),还有一个是DispatcherServlet创建的子容器(SpringMVC容器)。
然后这里的ContextLoaderListener初始化的时候如果检查到已经存在了根级别的IOC容器,那么就会抛出异常。而DispatcherServlet 创建的IOC容器会在初始化的时候先检查当前环境下是否存在已经创建好的IOC容器。如果有的话,则将已存在的这个IOC容器设置为自己的父容器;如果没有,则将自己设置为根级别的IOC容器。
因此:我们这里需要配置一个 ContextLoaderListener 监听器,避免创建两个IOC容器,出现错误。
第二种方法整合SpringMVC和Spring
这种方法是不需要在web.xml中引入spring-mybatis.xml文件以及配置ContextLoaderListener 监听器,而是在spring-mvc.xml配置文件中引入spring-mybatis.xml的配置文件。其他配置一模一样。
web.xml文件的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- <context-param>-->
<!-- <param-name>contextConfigLocation</param-name>-->
<!-- <!– 将spring-mybatis.xml文件放在resources目录下 –>-->
<!-- <param-value>classpath:spring-mybatis.xml</param-value>-->
<!-- </context-param>-->
<!-- <!– ContextLoaderListener监听容器 –>-->
<!-- <listener>-->
<!-- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
<!-- </listener>-->
<!-- 配置核心控制器 -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!-- 将spring-mvc.xml文件放在resources目录下 -->
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理乱码 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<!-- encoding参数指定要使用的字符集名称 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<!-- 请求强制编码 -->
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<!-- 响应强制编码 -->
<init-param>
<param-name>forceResponseEncoding</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>
在spring-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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 配置扫描的基包,例如扫描 @Component(组件)、@Service(服务)、@Controller(控制器)、@Repository(数据仓库)-->
<context:component-scan base-package="com.zhang"/>
<!-- 开启SpringMVC的注解驱动 -->
<mvc:annotation-driven enable-matrix-variables="true">
<mvc:message-converters register-defaults="false">
<bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 加入支持的媒体类型: 返回contentType -->
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 开放静态资源,也就是说没有@RequestMapping的请求将放行 -->
<mvc:default-servlet-handler/>
<!-- 配置视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="order" value="1"/>
<property name="characterEncoding" value="UTF-8"/>
<property name="templateEngine">
<bean class="org.thymeleaf.spring5.SpringTemplateEngine">
<property name="templateResolver">
<bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
<!-- 视图前缀 -->
<property name="prefix" value="/WEB-INF/templates/"/>
<!-- 视图后缀 -->
<property name="suffix" value=".html"/>
<property name="templateMode" value="HTML5"/>
<property name="characterEncoding" value="UTF-8" />
</bean>
</property>
</bean>
</property>
</bean>
<!-- 导入spring-mybatis -->
<import resource="spring-mybatis.xml"/>
</beans>
只需要改这两个配置文件即可,其他的不用改。
使用第三方的JSON
之前使用的是 jackson jar,现在我们换成第三方的JSON依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
在spring-mvc.xml文件中修改配置
<mvc:annotation-driven enable-matrix-variables="true">
<mvc:message-converters register-defaults="false">
<bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<!-- 加入支持的媒体类型: 返回contentType -->
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
进行全局的异常处理
在spring-mvc.xml文件中配置
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<!-- 配置异常映射关系 -->
<property name="exceptionMappings">
<props>
<!-- 异常类型和跳转处理页面映射 -->
<!-- key属性: 指定异常类型 -->
<!-- 文本标签体: 和异常类型对应的逻辑视图 -->
<prop key="java.lang.ClassNotFoundException">404</prop><!--跳转到404页面,这里还需要经过DispatcherServlet前端控制器-->
<prop key="java.lang.Exception">error</prop>
</props>
</property>
<!-- 使用exceptionAttribute属性配置将异常对象存入请求域时使用的属性名,属性名默认是exception -->
<property name="exceptionAttribute" value="exception"/>
</bean>
使用分页插件
导入分页插件的依赖
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</dependency>
在spring-mybatis.xml文件中配置
<!-- 配置 SqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 这里还有其他配置,例如引入mybatis-config.xml文件、配置数据源等配置 -->
<!-- 在 plugins 属性中配置 Mybatis 插件 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<props>
<!-- 设置 reasonable 为 true 表示将页码进行合理化修正。页码的有效范围:1~总页数 -->
<prop key="reasonable">true</prop>
<!-- 数据库方言:同样都是 SQL 语句,拿到不同数据库中,在语法上会有差异 -->
<!-- 默认情况下,按照 MySQL 作为数据库方言来运行 -->
<prop key="helperDialect">mysql</prop>
</props>
</property>
</bean>
</array>
</property>
</bean>
在控制层接收请求,这里是返回JSON格式的数据
@RequestMapping("/list/{pageNo}")
public PageInfo<User> getPage(@PathVariable("pageNo") Integer pageNo){
PageInfo<User> pageInfo = userService.list(pageNo);
return pageInfo;
}
在业务层写方法
@Override
public PageInfo<User> list(Integer pageNo) {
// 确定每页显示数据的条数
int pageSize = 1;
// 设定分页数据:开启分页功能。开启后,后面执行的 SELECT 语句会自动被附加 LIMIT 子句.而且会自动查询总记录数
PageHelper.offsetPage(pageNo,pageSize);
List<User> userList = userDao.list();
return new PageInfo<>(userList);
}
在dao层写接口
List<User> list();
在UserMapper.xml文件中写Sql语句
<select id="list" resultType="User">
select * from user
</select>