SSM全解析:Spring+SpringMVC+MyBatis实战教程

4 阅读7分钟

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的创建方式

  1. XML配置方式(传统方式)

  2. 注解方式(实战主流):通过@Component、@Service、@Dao、@Controller注解标识Bean,Spring自动扫描并创建对象。

  3. 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核心执行流程(面试高频)

  1. 前端发送请求(如http://localhost:8080/user/add),请求被**DispatcherServlet**(前端控制器)接收。

  2. DispatcherServlet调用HandlerMapping(处理器映射器),根据请求路径找到对应的Controller方法。

  3. HandlerMapping返回Handler(Controller方法),DispatcherServlet调用HandlerAdapter(处理器适配器),执行Controller方法。

  4. Controller方法执行完成,返回ModelAndView(模型数据+视图路径)。

  5. DispatcherServlet调用ViewResolver(视图解析器),根据视图路径解析出具体的视图(如JSP、HTML)。

  6. 视图渲染模型数据,生成最终的响应页面,返回给前端。

核心结论: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"&gt;
&lt;configuration&gt;
    <!-- 配置环境(数据库连接) -->
    <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&gt;

    <!-- 配置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"&gt;
<!-- namespace:对应Mapper接口的全路径 -->
<mapper namespace="com.example.dao.UserMapper"&gt;
    <!-- 配置实体类与表的映射可选简化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}
    &lt;/select&gt;

    <!-- 新增 -->
    <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"&gt;

    <!-- 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"/&gt;
        <!-- 配置Mapper.xml路径 -->
        <property name="mapperLocations" value="classpath:com/example/dao/mapper/*.xml"/&gt;
    &lt;/bean&gt;

    <!-- 4. 扫描Mapper接口自动生成代理对象 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.example.dao"/&gt;
    &lt;/bean&gt;

    <!-- 5. 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/&gt;
    &lt;/bean&gt;

    <!-- 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"&gt;

    <!-- 1. 扫描Controller层 -->
    <context:component-scan base-package="com.example.controller"/&gt;

    <!-- 2. 开启SpringMVC注解驱动支持@RequestMapping等注解-->
    &lt;mvc:annotation-driven/&gt;

    <!-- 3. 释放静态资源(CSS、JS、图片等,避免被SpringMVC拦截) -->
    &lt;mvc:default-servlet-handler/&gt;

    <!-- 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"&gt;

    <!-- 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>
    &lt;/context-param&gt;

    <!-- 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&gt;

    <!-- 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踩坑)

  1. 包扫描范围错误 Spring扫描Service和Dao,SpringMVC扫描Controller,若扫描范围重叠或遗漏,会导致Bean无法注入、接口404。

  2. MyBatis映射错误 Mapper接口的方法名与Mapper.xml的SQL id不一致、namespace与Mapper接口全路径不一致、实体类属性与表字段不匹配,都会导致SQL执行失败。

  3. 事务不生效 @Transactional注解只能用在public方法上、同类方法内部调用不触发事务、异常类型不是RuntimeException且未指定rollbackFor,都会导致事务不生效。

  4. 中文乱码问题 未配置字符编码过滤器,或配置错误,会导致前端传递的中文参数乱码,需确保CharacterEncodingFilter配置正确,且url-pattern为/*。

  5. 依赖冲突 Spring、SpringMVC、MyBatis的版本不兼容,会导致项目启动失败,建议统一版本(如Spring 5.3.x + MyBatis 3.5.x)。

  6. 静态资源被拦截 未配置&lt;mvc:default-servlet-handler/&gt;或configureDefaultServletHandling,SpringMVC会拦截静态资源(CSS、JS),导致页面样式失效。

  7. SqlSessionFactory配置错误 未配置数据源、Mapper.xml路径错误,会导致MyBatis无法初始化,无法执行SQL。


五、SSM面试高频考点

  1. Spring的核心思想是什么?IOC和DI的区别和联系。

  2. Spring Bean的创建方式有哪些?Bean的作用域有哪些?

  3. SpringMVC的核心执行流程是什么?DispatcherServlet的作用是什么?

  4. MyBatis的动态SQL有哪些标签?#{}和${}的区别?

  5. SSM整合的核心步骤是什么?Spring如何整合SpringMVC和MyBatis?

  6. Spring事务不生效的原因有哪些?

  7. MyBatis的一级缓存和二级缓存的区别?