SSM框架(Spring + SpringMVC + MyBatis)是Java后端开发的经典组合,也是面试高频考点,更是很多开发者入门后端的“敲门砖”。但很多人用SSM写业务,只停留在“配置XML、写接口、调方法”的CRUD层面,对三大框架的核心作用、底层原理、整合逻辑一知半解,遇到配置报错、接口异常、性能问题,只能盲目百度,无法从根源上解决。
这篇笔记彻底拆解SSM框架,先逐个讲透Spring、SpringMVC、MyBatis的核心原理和核心用法,再详细讲解三者整合的完整流程(XML配置+注解配置双版本),补充实战避坑和面试重点,帮你真正吃透SSM,做到知其然更知其所以然。
一、先搞懂:SSM三大框架各自的核心定位
SSM不是一个框架,而是三个框架的组合,三者各司其职、协同工作,共同完成一个完整的Java Web项目开发,核心定位可以总结为:
-
Spring:核心中的核心,负责Bean的管理、依赖注入、事务控制,是整个项目的“容器”,整合SpringMVC和MyBatis,解耦各个模块。
-
SpringMVC:负责接收前端请求、处理请求、返回响应,是前端与后端的“桥梁”,专注于Web层的交互。
-
MyBatis:负责与数据库交互,简化JDBC操作,专注于数据访问层(DAO层),将Java代码与SQL语句解耦。
简单类比:Spring是“管家”,统筹管理所有组件;SpringMVC是“前台接待”,对接前端请求;MyBatis是“后勤”,负责和数据库打交道,三者协同,构成一个完整的开发体系。
二、逐个拆解:三大框架核心原理与核心用法
2.1 Spring:Bean的容器,解耦的核心
2.1.1 核心思想:IOC和DI
Spring的核心是IOC(控制反转)和DI(依赖注入),目的是彻底解决代码耦合问题,让开发者无需手动创建对象、管理对象依赖,由Spring容器统一管理。
-
IOC(控制反转):将对象的创建、初始化、销毁的控制权,从开发者手中转移到Spring容器中,开发者无需new对象,直接从容器中获取对象。
-
DI(依赖注入):Spring容器在创建对象时,自动将该对象依赖的其他对象注入到其中(如Service依赖Dao,Spring自动将Dao对象注入到Service中),无需手动赋值。
2.1.2 Spring核心组件
-
BeanFactory:Spring最基础的容器,负责创建和管理Bean,是IOC的核心接口。
-
ApplicationContext:BeanFactory的子接口,功能更强大,支持国际化、事件监听、资源加载,实际开发中常用(如ClassPathXmlApplicationContext)。
-
Bean:Spring容器管理的对象,几乎所有的业务类(Service、Dao)都要交给Spring管理,成为Bean。
2.1.3 Bean的创建方式
-
XML配置方式(传统方式)
-
注解方式(实战主流):通过@Component、@Service、@Dao、@Controller注解标识Bean,Spring自动扫描并创建对象。
-
Java配置方式(SpringBoot常用):通过@Configuration、@Bean注解配置Bean,替代XML配置。
2.1.4 Spring事务管理
Spring提供声明式事务管理,无需手动编写事务代码(try-catch),通过配置或注解即可实现事务的提交、回滚,是SSM开发中必不可少的功能。
<!-- XML配置方式:配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 开启事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
// 注解方式:在Service方法上添加@Transactional,开启事务
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;
// 声明式事务:方法执行成功自动提交,出现异常自动回滚
@Transactional(rollbackFor = Exception.class)
@Override
public void addUser(User user) {
userDao.insert(user);
// 模拟异常,事务自动回滚
int i = 1 / 0;
}
}
2.2 SpringMVC:Web层的核心,前后端交互的桥梁
2.2.1 核心作用
SpringMVC是基于Spring的Web框架,核心作用是接收前端请求、处理请求逻辑、返回响应结果,替代传统的Servlet,简化Web层开发,实现前后端分离(或传统JSP开发)。
2.2.2 SpringMVC核心执行流程(面试高频)
-
前端发送请求(如http://localhost:8080/user/add),请求被**DispatcherServlet**(前端控制器)接收。
-
DispatcherServlet调用HandlerMapping(处理器映射器),根据请求路径找到对应的Controller方法。
-
HandlerMapping返回Handler(Controller方法),DispatcherServlet调用HandlerAdapter(处理器适配器),执行Controller方法。
-
Controller方法执行完成,返回ModelAndView(模型数据+视图路径)。
-
DispatcherServlet调用ViewResolver(视图解析器),根据视图路径解析出具体的视图(如JSP、HTML)。
-
视图渲染模型数据,生成最终的响应页面,返回给前端。
核心结论:DispatcherServlet是SpringMVC的核心,负责统筹所有请求的流转;HandlerMapping负责“找Controller”,HandlerAdapter负责“执行Controller”,ViewResolver负责“解析视图”。
2.2.3 核心注解(实战必备)
-
@Controller:标识该类为SpringMVC的Controller,接收前端请求。
-
@RequestMapping:映射请求路径,可用于类上(指定统一前缀)和方法上(指定具体路径),支持GET、POST等请求方式。
-
@RequestParam:接收前端请求参数(GET请求参数、POST表单参数)。
-
@RequestBody:接收前端传递的JSON数据(POST请求,前后端分离常用)。
-
@ResponseBody:将Controller方法的返回值转为JSON格式,直接返回给前端(无需解析视图,前后端分离常用)。
-
@RestController:@Controller + @ResponseBody的组合,用于前后端分离的接口开发(最常用)。
2.2.4 实战示例(前后端分离接口)
// @RestController:标识为接口控制器,返回JSON
@RestController
@RequestMapping("/user") // 统一请求前缀
public class UserController {
// 依赖注入Service
@Autowired
private UserService userService;
// GET请求:根据ID查询用户
@GetMapping("/{id}")
public Result getUserById(@PathVariable("id") Integer id) {
User user = userService.getUserById(id);
return Result.success(user);
}
// POST请求:新增用户,接收JSON参数
@PostMapping("/add")
public Result addUser(@RequestBody User user) {
userService.addUser(user);
return Result.success("新增成功");
}
}
2.3 MyBatis:数据访问层核心,简化JDBC操作
2.3.1 核心作用
MyBatis是一款持久层框架,核心作用是简化JDBC操作,将Java代码与SQL语句解耦,无需手动编写JDBC的Connection、Statement、ResultSet,只需编写SQL语句,MyBatis自动完成数据的查询、插入、更新、删除。
MyBatis的核心是“ORM(对象关系映射)”:将Java中的实体类(POJO)与数据库中的表对应,实体类的属性与表的字段对应,实现“面向对象”的数据库操作。
2.3.2 MyBatis核心组件
-
SqlSessionFactory:MyBatis的核心工厂,负责创建SqlSession,通过MyBatis配置文件初始化。
-
SqlSession:MyBatis的会话对象,负责执行SQL语句,获取Mapper接口的代理对象。
-
Mapper接口:Dao层接口,无需编写实现类,MyBatis通过动态代理自动生成实现类,SQL语句写在Mapper.xml中。
-
Mapper.xml:存放SQL语句,配置实体类与表的映射关系,是MyBatis的核心配置文件。
2.3.3 核心配置(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">
<configuration>
<!-- 配置环境(数据库连接) -->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</dataSource>
</environment>
</environments>
<!-- 配置Mapper.xml路径 -->
<mappers>
<mapper resource="com/example/dao/mapper/UserMapper.xml"/>
</mappers>
</configuration>
2.3.4 Mapper接口与Mapper.xml实战
// Mapper接口(Dao层),无需编写实现类
public interface UserMapper {
// 方法名与Mapper.xml中的SQL id一致
User selectById(Integer id);
void insert(User user);
}
<?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">
<!-- namespace:对应Mapper接口的全路径 -->
<mapper namespace="com.example.dao.UserMapper">
<!-- 配置实体类与表的映射(可选,简化SQL) -->
<resultMap id="userMap" type="com.example.pojo.User">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
</resultMap>
<!-- 查询:id与Mapper接口方法名一致 -->
<select id="selectById" resultMap="userMap">
select * from user where id = #{id}
</select>
<!-- 新增 -->
<insert id="insert" parameterType="com.example.pojo.User">
insert into user(username, password) values(#{username}, #{password})
</insert>
</mapper>
2.3.5 核心特性(实战常用)
-
动态SQL:根据条件动态生成SQL,避免SQL拼接的麻烦和安全问题。
-
分页查询:结合PageHelper插件,快速实现分页功能,无需手动编写分页SQL。
-
参数传递:支持#{}(预编译,防止SQL注入)和${}(字符串拼接,慎用)两种参数传递方式。
三、SSM整合实战(XML配置+注解配置,两种版本)
SSM整合的核心是“将三个框架协同起来”:Spring管理Bean和事务,SpringMVC处理Web请求,MyBatis负责数据库交互,整合的关键是“配置Spring,让Spring整合SpringMVC和MyBatis”。
3.1 整合前提:导入依赖(Maven)
<!-- Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<!-- SpringMVC依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!-- MyBatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- Spring整合MyBatis依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- 数据库驱动、连接池 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.11</version>
</dependency>
<!-- Web相关依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
3.2 版本1:XML配置整合(传统方式,面试常考)
步骤1:配置Spring核心配置文件(applicationContext.xml)
核心:配置数据源、整合MyBatis、扫描Service和Dao层Bean、配置事务。
<?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: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.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 扫描Service和Dao层(排除Controller,交给SpringMVC扫描) -->
<context:component-scan base-package="com.example">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 2. 配置数据源(Druid连接池) -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!-- 3. 整合MyBatis:配置SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 配置MyBatis核心配置文件路径 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 配置Mapper.xml路径 -->
<property name="mapperLocations" value="classpath:com/example/dao/mapper/*.xml"/>
</bean>
<!-- 4. 扫描Mapper接口,自动生成代理对象 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.dao"/>
</bean>
<!-- 5. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 6. 开启事务注解驱动 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
步骤2:配置SpringMVC核心配置文件(spring-mvc.xml)
核心:扫描Controller、配置视图解析器、开启注解驱动、释放静态资源。
<?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">
<!-- 1. 扫描Controller层 -->
<context:component-scan base-package="com.example.controller"/>
<!-- 2. 开启SpringMVC注解驱动(支持@RequestMapping等注解) -->
<mvc:annotation-driven/>
<!-- 3. 释放静态资源(CSS、JS、图片等,避免被SpringMVC拦截) -->
<mvc:default-servlet-handler/>
<!-- 4. 配置视图解析器(传统JSP开发用,前后端分离可省略) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
步骤3:配置Web.xml(入口配置)
核心:配置DispatcherServlet、加载Spring和SpringMVC配置文件、设置字符编码过滤器。
<?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">
<!-- 1. 配置Spring容器监听器,加载Spring核心配置文件 -->
<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>
<!-- 2. 配置DispatcherServlet(SpringMVC前端控制器) -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 3. 配置字符编码过滤器(解决中文乱码) -->
<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>
3.3 版本2:注解配置整合(实战主流,替代XML)
用Java配置类替代XML配置,更简洁、更灵活,是当前SSM开发的主流方式。
步骤1:Spring核心配置类(SpringConfig.java)
@Configuration // 标识为配置类,替代applicationContext.xml
@ComponentScan(basePackages = "com.example",
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)) // 排除Controller
@EnableTransactionManagement // 开启事务注解驱动
public class SpringConfig {
// 1. 配置数据源(Druid)
@Bean
public DataSource dataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/ssm_db?serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
// 2. 配置SqlSessionFactory
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
// 配置MyBatis核心配置
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setMapUnderscoreToCamelCase(true); // 开启下划线转驼峰
sqlSessionFactoryBean.setConfiguration(configuration);
// 配置Mapper.xml路径
sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
.getResources("classpath:com/example/dao/mapper/*.xml"));
return sqlSessionFactoryBean.getObject();
}
// 3. 扫描Mapper接口
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.example.dao");
return mapperScannerConfigurer;
}
// 4. 配置事务管理器
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
步骤2:SpringMVC配置类(SpringMvcConfig.java)
@Configuration // 标识为配置类,替代spring-mvc.xml
@ComponentScan(basePackages = "com.example.controller") // 扫描Controller
@EnableWebMvc // 开启SpringMVC注解驱动
public class SpringMvcConfig implements WebMvcConfigurer {
// 1. 释放静态资源
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// 2. 配置视图解析器(可选,前后端分离可省略)
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
// 3. 配置字符编码(替代字符编码过滤器)
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> characterEncodingFilter() {
FilterRegistrationBean<CharacterEncodingFilter> registrationBean = new FilterRegistrationBean<>();
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
registrationBean.setFilter(filter);
registrationBean.addUrlPatterns("/*");
return registrationBean;
}
}
步骤3:Web入口配置类(WebConfig.java)
// 替代Web.xml,配置DispatcherServlet和Spring容器
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
// 加载Spring核心配置类
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
// 加载SpringMVC配置类
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
// 配置DispatcherServlet的映射路径
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
四、SSM实战避坑指南(告别CRUD踩坑)
-
包扫描范围错误 Spring扫描Service和Dao,SpringMVC扫描Controller,若扫描范围重叠或遗漏,会导致Bean无法注入、接口404。
-
MyBatis映射错误 Mapper接口的方法名与Mapper.xml的SQL id不一致、namespace与Mapper接口全路径不一致、实体类属性与表字段不匹配,都会导致SQL执行失败。
-
事务不生效 @Transactional注解只能用在public方法上、同类方法内部调用不触发事务、异常类型不是RuntimeException且未指定rollbackFor,都会导致事务不生效。
-
中文乱码问题 未配置字符编码过滤器,或配置错误,会导致前端传递的中文参数乱码,需确保CharacterEncodingFilter配置正确,且url-pattern为/*。
-
依赖冲突 Spring、SpringMVC、MyBatis的版本不兼容,会导致项目启动失败,建议统一版本(如Spring 5.3.x + MyBatis 3.5.x)。
-
静态资源被拦截 未配置<mvc:default-servlet-handler/>或configureDefaultServletHandling,SpringMVC会拦截静态资源(CSS、JS),导致页面样式失效。
-
SqlSessionFactory配置错误 未配置数据源、Mapper.xml路径错误,会导致MyBatis无法初始化,无法执行SQL。
五、SSM面试高频考点
-
Spring的核心思想是什么?IOC和DI的区别和联系。
-
Spring Bean的创建方式有哪些?Bean的作用域有哪些?
-
SpringMVC的核心执行流程是什么?DispatcherServlet的作用是什么?
-
MyBatis的动态SQL有哪些标签?#{}和${}的区别?
-
SSM整合的核心步骤是什么?Spring如何整合SpringMVC和MyBatis?
-
Spring事务不生效的原因有哪些?
-
MyBatis的一级缓存和二级缓存的区别?