SSM 框架基本使用教程(小白版)

SSM = Spring + Spring MVC + MyBatis,是 Java Web 开发最经典的三大框架组合。

一、先搞懂三个框架各自干什么

用一个餐厅的比喻:


┌─────────────────────────────────────────────────────┐

│ SSM 餐厅 │

│ │

│ 🧑‍🍳 Spring → 餐厅经理(管理所有对象,协调一切) │

│ 🚪 Spring MVC → 前台服务员(接客人的点单,端菜上桌) │

│ 🗄️ MyBatis → 后厨(从仓库/数据库取出食材做菜) │

└─────────────────────────────────────────────────────┘

框架 一句话概括 干什么的
Spring 大管家 管理对象的创建和依赖关系(IoC/DI)
Spring MVC 接待员 接收用户请求,返回页面或数据
MyBatis 数据库翻译 把 Java 代码翻译成 SQL,操作数据库

二、项目结构长什么样


ssm-demo/

├── src/main/java/com/example/

│ ├── controller/ ← Spring MVC:接收请求

│ │ └── UserController.java

│ ├── service/ ← Spring:业务逻辑

│ │ ├── UserService.java

│ │ └── UserServiceImpl.java

│ ├── mapper/ ← MyBatis:操作数据库

│ │ └── UserMapper.java

│ └── entity/ ← 实体类(对应数据库表)

│ └── User.java

├── src/main/resources/

│ ├── mapper/ ← MyBatis 的 SQL 映射文件

│ │ └── UserMapper.xml

│ ├── spring/ ← Spring 配置

│ │ ├── applicationContext.xml

│ │ └── spring-mvc.xml

│ └── db.properties ← 数据库连接信息

└── pom.xml ← Maven 依赖管理


三、一步一步搭建

第1步:Maven 依赖(pom.xml)


<dependencies>

<!-- ========== Spring 核心 ========== -->

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.3.23</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-webmvc</artifactId>

<version>5.3.23</version>

</dependency>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-jdbc</artifactId>

<version>5.3.23</version>

</dependency>

<!-- ========== MyBatis ========== -->

<dependency>

<groupId>org.mybatis</groupId>

<artifactId>mybatis</artifactId>

<version>3.5.11</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.33</version>

</dependency>

<!-- 数据库连接池 -->

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>druid</artifactId>

<version>1.2.15</version>

</dependency>

<!-- ========== Servlet ========== -->

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>javax.servlet-api</artifactId>

<version>4.0.1</version>

<scope>provided</scope>

</dependency>

</dependencies>

💡 提示pom.xml 就是一个"购物清单",告诉 Maven 你需要哪些第三方库。


第2步:实体类(对应数据库表)


package com.example.entity;

/**

* 用户实体类 —— 与数据库的 user 表一一对应

*/

public class User {

private Integer id; // 对应数据库的 id 字段

private String username; // 用户名

private String password; // 密码

private String email; // 邮箱

// ---- getter 和 setter(必须有!框架靠它们读写数据)----

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 getEmail() { return email; }

public void setEmail(String email) { this.email = email; }

@Override

public String toString() {

return "User{id=" + id + ", username='" + username + "', email='" + email + "'}";

}

}

对应的数据库表:


CREATE TABLE user (

id INT PRIMARY KEY AUTO_INCREMENT,

username VARCHAR(50),

password VARCHAR(50),

email VARCHAR(100)

);

-- 插几条测试数据

INSERT INTO user VALUES (1, 'zhangsan', '123456', 'zhangsan@qq.com');

INSERT INTO user VALUES (2, 'lisi', '654321', 'lisi@qq.com');


第3步:MyBatis 层(操作数据库)

① Mapper 接口 —— 定义"能做哪些数据库操作":


package com.example.mapper;

import com.example.entity.User;

import java.util.List;

/**

* 用户 Mapper 接口

* 不用写实现类!MyBatis 会自动生成实现(通过 XML 中的 SQL)

*/

public interface UserMapper {

// 查询所有用户

List<User> findAll();

// 根据 id 查一个用户

User findById(Integer id);

// 添加用户

int insert(User user);

// 修改用户

int update(User user);

// 删除用户

int deleteById(Integer id);

}

② Mapper XML —— 写具体的 SQL:


<?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 接口的全类名

这样 MyBatis 就知道:这个 XML 里的 SQL 是给哪个接口用的

-->

<mapper namespace="com.example.mapper.UserMapper">

<!--

resultMap:告诉 MyBatis 数据库字段 和 Java 属性的对应关系

如果字段名和属性名完全一样,可以不写

-->

<resultMap id="userMap" type="com.example.entity.User">

<id property="id" column="id"/>

<result property="username" column="username"/>

<result property="password" column="password"/>

<result property="email" column="email"/>

</resultMap>

<!-- 查询所有 -->

<select id="findAll" resultMap="userMap">

SELECT id, username, password, email FROM user

</select>

<!-- 根据 id 查询 -->

<select id="findById" parameterType="int" resultMap="userMap">

SELECT id, username, password, email FROM user

WHERE id = #{id}

</select>

<!-- 添加用户 -->

<!-- useGeneratedKeys:插入后自动把数据库生成的 id 回填到对象里 -->

<insert id="insert" parameterType="com.example.entity.User"

useGeneratedKeys="true" keyProperty="id">

INSERT INTO user (username, password, email)

VALUES (#{username}, #{password}, #{email})

</insert>

<!-- 修改用户 -->

<update id="update" parameterType="com.example.entity.User">

UPDATE user

SET username = #{username}, password = #{password}, email = #{email}

WHERE id = #{id}

</update>

<!-- 删除用户 -->

<delete id="deleteById" parameterType="int">

DELETE FROM user WHERE id = #{id}

</delete>

</mapper>

💡 提示

  • #{id} 是占位符,相当于 JDBC 的 ?,会自动防 SQL 注入
  • id="findAll" 必须和接口方法名一样!这就是映射关系

第4步:Service 层(业务逻辑)

① 接口


package com.example.service;

import com.example.entity.User;

import java.util.List;

public interface UserService {

List<User> findAll();

User findById(Integer id);

void add(User user);

void modify(User user);

void remove(Integer id);

}

② 实现类


package com.example.service;

import com.example.entity.User;

import com.example.mapper.UserMapper;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import java.util.List;

@Service // 告诉 Spring:这个类由你来管理(自动创建对象)

public class UserServiceImpl implements UserService {

@Autowired // 告诉 Spring:自动帮我注入 UserMapper 对象

private UserMapper userMapper;

@Override

public List<User> findAll() {

return userMapper.findAll();

}

@Override

public User findById(Integer id) {

return userMapper.findById(id);

}

@Override

public void add(User user) {

userMapper.insert(user);

}

@Override

public void modify(User user) {

userMapper.update(user);

}

@Override

public void remove(Integer id) {

userMapper.deleteById(id);

}

}

💡 @Autowired 的神奇之处:你不用 new UserServiceImpl(),Spring 自动帮你创建好并注入进来。


第5步:Controller 层(接收请求)


package com.example.controller;

import com.example.entity.User;

import com.example.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.*;

import java.util.List;

@Controller // 标记为控制器

@RequestMapping("/user") // 所有请求路径以 /user 开头

public class UserController {

@Autowired

private UserService userService;

/**

* 查询所有用户

* 请求:GET /user/list

* 返回:跳转到 user/list.jsp 页面

*/

@GetMapping("/list")

public String list(Model model) {

List<User> users = userService.findAll();

model.addAttribute("users", users); // 把数据塞到页面上

return "user/list"; // 返回页面路径

}

/**

* 根据 id 查询用户

* 请求:GET /user/1

*/

@GetMapping("/{id}")

public String detail(@PathVariable Integer id, Model model) {

User user = userService.findById(id);

model.addAttribute("user", user);

return "user/detail";

}

/**

* 添加用户 —— 显示表单

* 请求:GET /user/add

*/

@GetMapping("/add")

public String addForm() {

return "user/add"; // 返回添加页面

}

/**

* 添加用户 —— 提交表单

* 请求:POST /user/add

*/

@PostMapping("/add")

public String add(User user) {

userService.add(user);

return "redirect:/user/list"; // 添加成功后跳转到列表页

}

/**

* 删除用户

* 请求:GET /user/delete/1

*/

@GetMapping("/delete/{id}")

public String delete(@PathVariable Integer id) {

userService.remove(id);

return "redirect:/user/list";

}

/**

* (前后端分离方式)返回 JSON 数据

* 请求:GET /user/api/list

*/

@GetMapping("/api/list")

@ResponseBody // 加了这个就不跳页面了,直接返回数据

public List<User> apiList() {

return userService.findAll();

}

}

💡 常用注解速记

注解 意思
@Controller 这是个控制器
@RequestMapping("/user") URL 映射
@GetMapping 只处理 GET 请求
@PostMapping 只处理 POST 请求
@PathVariable 从 URL 里取参数,如 /user/{id}
@RequestParam 从 ?key=value 取参数
@ResponseBody 返回 JSON 而不是页面
@RestController @Controller + @ResponseBody

第6步:Spring 配置文件

数据库配置 (db.properties):


jdbc.driver=com.mysql.cj.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/ssm_demo?useSSL=false&serverTimezone=Asia/Shanghai

jdbc.username=root

jdbc.password=123456

Spring 核心配置 (applicationContext.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

http://www.springframework.org/schema/context/spring-context.xsd">

<!-- 1. 加载数据库配置文件 -->

<context:property-placeholder location="classpath:db.properties"/>

<!-- 2. 配置数据源(数据库连接池) -->

<bean id="dataSource" 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>

<!-- 3. 配置 MyBatis 的 SqlSessionFactory(核心!) -->

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<property name="mapperLocations" value="classpath:mapper/*.xml"/>

<property name="typeAliasesPackage" value="com.example.entity"/>

</bean>

<!-- 4. 扫描 Mapper 接口,自动创建实现类 -->

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">

<property name="basePackage" value="com.example.mapper"/>

</bean>

<!-- 5. 扫描 Service 层的注解(@Service, @Autowired 等) -->

<context:component-scan base-package="com.example.service"/>

</beans>

Spring MVC 配置 (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

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. 开启注解驱动(让 @GetMapping 等注解生效) -->

<mvc:annotation-driven/>

<!-- 3. 配置视图解析器(决定返回的页面在哪里) -->

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">

<property name="prefix" value="/WEB-INF/views/"/> <!-- 前缀 -->

<property name="suffix" value=".jsp"/> <!-- 后缀 -->

</bean>

<!-- 4. 放行静态资源(css/js/图片等) -->

<mvc:default-servlet-handler/>

</beans>


第7步:web.xml(启动入口)


<?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 容器) -->

<context-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:spring/applicationContext.xml</param-value>

</context-param>

<listener>

<listener-class>

org.springframework.web.context.ContextLoaderListener

</listener-class>

</listener>

<!-- 2. 配置 Spring MVC 的前端控制器(所有请求都先经过它) -->

<servlet>

<servlet-name>dispatcherServlet</servlet-name>

<servlet-class>

org.springframework.web.servlet.DispatcherServlet

</servlet-class>

<init-param>

<param-name>contextConfigLocation</param-name>

<param-value>classpath:spring/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>

<!-- 3. 字符编码过滤器(解决中文乱码) -->

<filter>

<filter-name>encodingFilter</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>encodingFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</web-app>


四、请求流转的完整过程


用户浏览器 你的代码

│ GET /user/list

┌──────────────────┐

│ web.xml │ DispatcherServlet 拦截请求

│ (前端控制器) │

└────────┬─────────┘

┌──────────────────┐

│ Spring MVC │ 根据 @RequestMapping 找到

│ (找Controller) │ UserController.list()

└────────┬─────────┘

┌──────────────────┐

│ Controller │ 调用 userService.findAll()

│ (处理请求) │

└────────┬─────────┘

┌──────────────────┐

│ Service │ 调用 userMapper.findAll()

│ (业务逻辑) │

└────────┬─────────┘

┌──────────────────┐

│ Mapper + XML │ 执行 SQL: SELECT * FROM user

│ (操作数据库) │ MyBatis 把结果转成 User 对象

└────────┬─────────┘

数据逐层返回

Controller 把数据塞到 Model 里

视图解析器拼接路径: /WEB-INF/views/user/list.jsp

渲染 JSP 页面返回给浏览器

用户看到页面 ✅


五、常用注解速查表

Spring 注解


@Component // 通用组件,Spring 管理它

@Service // 等于 @Component,语义上表示"业务层"

@Repository // 等于 @Component,语义上表示"数据层"

@Autowired // 自动注入依赖对象

@Qualifier // 当有多个同类型对象时,指定注入哪个

Spring MVC 注解


@Controller // 控制器

@RestController // = @Controller + @ResponseBody(返回 JSON)

@RequestMapping // URL 映射(可以加在类和方法上)

@GetMapping // 等于 @RequestMapping(method=GET)

@PostMapping // 等于 @RequestMapping(method=POST)

@PathVariable // 从 URL 路径取值:/user/{id} → id

@RequestParam // 从查询参数取值:?name=xx → name

@ResponseBody // 返回数据(JSON),不走视图解析

@RequestBody // 接收 JSON 格式的请求体

MyBatis XML 中的标签


<select> 查询

<insert> 插入

<update> 修改

<delete> 删除

<if> 条件判断

<where> 智能 WHERE(自动去掉多余的 AND/OR)

<foreach> 循环(常用于 IN 查询和批量插入)


六、动态 SQL 示例(MyBatis 精华)


<!-- 条件查询:根据传入的参数动态拼 SQL -->

<select id="search" parameterType="com.example.entity.User" resultMap="userMap">

SELECT * FROM user

<where>

<if test="username != null and username != ''">

AND username LIKE CONCAT('%', #{username}, '%')

</if>

<if test="email != null and email != ''">

AND email = #{email}

</if>

</where>

</select>

<!-- 批量删除 -->

<delete id="batchDelete" parameterType="list">

DELETE FROM user WHERE id IN

<foreach collection="list" item="id" open="(" separator="," close=")">

#{id}

</foreach>

</delete>

💡 <where> 的好处:如果里面所有 <if> 都不成立,就不会生成 WHERE 子句;如果第一个条件成立,会自动去掉多余的 AND


七、总结:三层架构对应关系


┌───────────────────────────────────────────────────────────────┐

│ 用户请求 │

│ ▼ │

│ ┌──────────┐ @Controller 处理请求、返回页面/JSON │

│ │Controller │────────────────────────────────────────── │

│ └────┬─────┘ │

│ ▼ │

│ ┌──────────┐ @Service 写业务逻辑(判断、计算等) │

│ │ Service │────────────────────────────────────────── │

│ └────┬─────┘ │

│ ▼ │

│ ┌──────────┐ Mapper + XML 操作数据库(增删改查) │

│ │ Mapper │────────────────────────────────────────── │

│ └────┬─────┘ │

│ ▼ │

│ ┌──────────┐ │

│ │ 数据库 │ MySQL │

│ └──────────┘ │

└───────────────────────────────────────────────────────────────┘

调用方向:Controller → Service → Mapper → 数据库

依赖注入:Spring 通过 @Autowired 自动把下层对象传给上层

Controller 接活,Service 干活,Mapper 拿货

Controller 接收请求,Service 处理业务逻辑,Mapper 操作数据库。


八、现在流行的替代方案

SSM 是经典配置式开发,现在更流行注解式 / 自动配置

传统 SSM 现代替代
手写 XML 配置 Spring Boot 自动配置
手写 SQL MyBatis-Plus 自动生成 CRUD
JSP 页面 前后端分离(Vue/React + JSON API)

更多推荐