# 是什么 SSM
SSM 是三个框架的简写,本别是 Spring,SpringMVC,Mybatis,这三个框架作为 JavaWeb 强有力的支撑件,极大地提高了开发效率,降低了维护成本,是 Java 程序员学习 Web 技术的必经之路(至少现在是这样)
在此之前,我希望你能熟练掌握,额,哪怕不熟练也要了解 Web 部分的老祖:请求,响应以及 Servlet 技术,这些技术能帮助你更好、更快、更流畅的掌握 SSM 技术。
其次本文主要讲解 SSM 整合的相关细节,并不会深入讲解 Spring,SpringMVC,Mybatis 每个框架的知识,希望大家在看本文之前能了解 Spring,SpringMVC,Mybatis 单个框架的使用方法。
# 整合开始
首先我先放出最终的整合状态,其实也不一定非要按照我这样来做。
![]() |
bean 包:大多数的实体类 config 包:整合的核心配置类 controller 包:外部控制器暴露点 mapper 包:Mybiats SQL 标准化 service 包:业务逻辑,包含接口以及实现 resource 包:资源文件、配置文件 webapp:前端资源 |
---|
那么接下来我将带着大家一步一步的来做,从创建项目到最终完成整合。
# 创建项目(Maven 构建方式)
选择新建一个项目(或模块),选择 Maven Archetype 形式创建,我给他命名叫做 SSM_demo。
JDK:1.8(Java 8)
Archetype:选择最后以 webapp 结尾的,这是一个创建模板
组 ID:公司域名反写
# 创建包结构
在 main 目录下创建 java 目录和必要的包结构
# 依赖导入、必要启动配置
我们需要在 pom.xml 文件下导入我们 SSM 所需要的依赖,并配置必要的启动项。
# 导入详解
第一步:导包
需要思考我们需要什么依赖:
junit:单元测试。
spring-webmvc:整个依赖就比较强大了她不仅包含了 SpringMVC 的部分也包含了 Spring-Context 部分,其实也不难理解,因为 SpringMVC 是基于 Spring 开发的,那也就必然包含了 Spring 框架的部分。
至此我们还剩下数据库的部分,我们继续将其填充完整。
Mybatis:这个是 Mybatis 的核心依赖。
mybatis-spring:整个是将 Mybatis 与 Spring 进行整合。
spring-jdbc:简化 Java 应用程序与数据库之间的交互,Spring JDBC 是 MyBatis-Spring 的底层依赖,提供了连接管理、事务管理等基础功能。
mysql-connector-java:这个是 MySQL 的驱动依赖。
druid:数据库连接池。
servlet-api:Spring MVC 架构是基于 Servlet 规范的。它使用 Servlet API 来处理和分发 Web 请求,以及与 Web 容器进行交互。
jackson-databind:用于在 Java 对象和 JSON 数据之间进行序列化(对象到 JSON)和反序列化(JSON 到对象)的核心部分。
<dependencies> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.13.2</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-webmvc</artifactId> | |
<version>5.2.10.RELEASE</version> | |
</dependency> | |
<dependency> | |
<groupId>org.mybatis</groupId> | |
<artifactId>mybatis</artifactId> | |
<version>3.5.9</version> | |
</dependency> | |
<dependency> | |
<groupId>org.mybatis</groupId> | |
<artifactId>mybatis-spring</artifactId> | |
<version>2.0.7</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-jdbc</artifactId> | |
<version>6.0.6</version> | |
</dependency> | |
<dependency> | |
<groupId>mysql</groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
<version>8.0.31</version> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>servlet-api</artifactId> | |
<version>2.5</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-databind</artifactId> | |
<version>2.13.4</version> | |
</dependency> | |
</dependencies> |
一定要为我们的 servlet-api 配置作用域为 provided,这是非常大的一个坑点!!!
如果您不将 servlet-api
的作用域设置为 provided
,而是将其作用域设置为默认的 compile
,则可能会导致以下问题和影响:
- 冲突问题: 如果您的应用程序包含了自己的 Servlet API 实现(例如 jar 包),而 Web 容器也提供了自己的实现,可能会导致冲突和不稳定性。
- 版本不一致: 不同的 Web 容器可能使用不同版本的 Servlet API,如果您将 API 包含在应用程序中,可能会导致版本不一致的问题。
- 应用程序大小增加: 将 Servlet API 包含在应用程序中会增加应用程序的大小,尽管这在绝大多数情况下可能不会对性能产生明显影响,但仍然会浪费一些资源。
- 维护困难: 如果您在多个项目中重复地包含 Servlet API,可能会导致维护上的困难,特别是在更新版本或切换到不同的 Web 容器时。
<scope>provided</scope> |
第二步:启动配置
在这里你可以选择外挂 Tomcat 和 Maven 插件的两种启动方式,在这里我选择插件法,因为外挂启动真的是太慢了 QWQ
pom.xml 文件中的 build 标签下配置 tomcat 插件:
<build> | |
<finalName>SSM_demo</finalName> | |
<plugins> | |
<plugin> | |
<groupId>org.apache.tomcat.maven</groupId> | |
<artifactId>tomcat7-maven-plugin</artifactId> | |
<version>2.2</version> | |
<configuration> | |
<port>80</port> | |
<path>/</path> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> |
80 端口为启动端口,你也可以进行修改,例如修改到 8090
<port>8090</port> |
第三步:Java 版本配置
其实这是一个坑点我们需要在 pom 文件加上这两行:
<properties> | |
<maven.compiler.source>8</maven.compiler.source> | |
<maven.compiler.target>8</maven.compiler.target> | |
</properties> |
这是在声明我们的 Java 版本为 java8,这个一定要根据我们项目的 java 版本来填写
# 最终展示
<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/maven-v4_0_0.xsd"> | |
<modelVersion>4.0.0</modelVersion> | |
<groupId>com.KarryCode</groupId> | |
<artifactId>SSM_demo</artifactId> | |
<packaging>war</packaging> | |
<properties> | |
<maven.compiler.source>8</maven.compiler.source> | |
<maven.compiler.target>8</maven.compiler.target> | |
</properties> | |
<version>1.0-SNAPSHOT</version> | |
<name>SSM_demo Maven Webapp</name> | |
<url>http://maven.apache.org</url> | |
<dependencies> | |
<dependency> | |
<groupId>junit</groupId> | |
<artifactId>junit</artifactId> | |
<version>4.13.2</version> | |
<scope>test</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-webmvc</artifactId> | |
<version>5.2.10.RELEASE</version> | |
</dependency> | |
<dependency> | |
<groupId>org.mybatis</groupId> | |
<artifactId>mybatis</artifactId> | |
<version>3.5.9</version> | |
</dependency> | |
<dependency> | |
<groupId>org.mybatis</groupId> | |
<artifactId>mybatis-spring</artifactId> | |
<version>2.0.7</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework</groupId> | |
<artifactId>spring-jdbc</artifactId> | |
<version>5.0.2.RELEASE</version> | |
</dependency> | |
<dependency> | |
<groupId>mysql</groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
<version>8.0.31</version> | |
</dependency> | |
<dependency> | |
<groupId>com.alibaba</groupId> | |
<artifactId>druid</artifactId> | |
<version>1.2.16</version> | |
</dependency> | |
<dependency> | |
<groupId>javax.servlet</groupId> | |
<artifactId>servlet-api</artifactId> | |
<version>2.5</version> | |
<scope>provided</scope> | |
</dependency> | |
<dependency> | |
<groupId>com.fasterxml.jackson.core</groupId> | |
<artifactId>jackson-databind</artifactId> | |
<version>2.13.4</version> | |
</dependency> | |
</dependencies> | |
<build> | |
<finalName>SSM_demo</finalName> | |
<plugins> | |
<plugin> | |
<groupId>org.apache.tomcat.maven</groupId> | |
<artifactId>tomcat7-maven-plugin</artifactId> | |
<version>2.2</version> | |
<configuration> | |
<port>80</port> | |
<path>/</path> | |
</configuration> | |
</plugin> | |
</plugins> | |
</build> | |
</project> |
# 创建 JDBC.properties 文件
在 resource
目录下创建 jdbc.properties
jdbc.driver = com.mysql.cj.jdbc.Driver | |
jdbc.url = | |
jdbc.username = | |
jdbc.password = |
等号后面的根据自己的需要进行填写
为了测试,我还创建的一张表:
这是我的生成脚本:
create table tb_book | |
( | |
id int auto_increment | |
primary key, | |
type varchar(20) null, | |
name varchar(50) null, | |
description varchar(255) null | |
); |
# 创建 mapper 代理包
首先在 resource 目录下创建与 java 源代码目录一样的包,切记一定要以 “/” 的分割形式去创建,
例如:com/KarryCode/mapper
创建好后,后置在这个目录下创建对应的 xml,我们稍后再说!
# 创建配置文件(配置类)
这部分将以配置类的形式进行配置。
# Spring_Mybatis 整合配置
首先在 config 包下创建 Spring_Mybatis 配置类
package com.KarryCode.config; | |
import com.alibaba.druid.pool.DruidDataSource; | |
import org.mybatis.spring.SqlSessionFactoryBean; | |
import org.mybatis.spring.annotation.MapperScan; | |
import org.springframework.beans.factory.annotation.Value; | |
import org.springframework.context.annotation.Bean; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.context.annotation.PropertySource; | |
import org.springframework.jdbc.datasource.DataSourceTransactionManager; | |
import org.springframework.transaction.PlatformTransactionManager; | |
import org.springframework.transaction.annotation.EnableTransactionManagement; | |
import javax.sql.DataSource; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @ClassName SpringConfig | |
* @Description TODO Spring 核心配置类 | |
* @Version 1.0 | |
*/ | |
@Configuration //TODO 核心配置唯一标识 | |
@ComponentScan({"com.KarryCode.service","com.KarryCode.bean"}) //TODO 注解扫描指定包 | |
@PropertySource("classpath:jdbc.properties") //TODO 加载 JDBC 配置类 | |
@MapperScan("com.KarryCode.mapper") //TODO MyBatis 基于包扫描方式识别 Mapper | |
@EnableTransactionManagement //TODO 事务的自动代理,注解驱动 | |
public class Spring_MybatisConfig { | |
@Bean | |
//TODO DruidDataSource 数据源的产生 | |
public DataSource dataSource( | |
@Value("${jdbc.driver}") String driver, | |
@Value("${jdbc.url}") String url, | |
@Value("${jdbc.username}") String username, | |
@Value("${jdbc.password}") String password | |
) { | |
DruidDataSource dataSource = new DruidDataSource(); | |
dataSource.setDriverClassName(driver); | |
dataSource.setUrl(url); | |
dataSource.setUsername(username); | |
dataSource.setPassword(password); | |
// 里面还可以配置更多关于数据库连接池的选项....... | |
return dataSource; | |
} | |
@Bean | |
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) { | |
//TODO sqlSessionFactoryBean MybatisBeans 加载 | |
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean(); | |
sqlSessionFactoryBean.setDataSource(dataSource); | |
return sqlSessionFactoryBean; | |
} | |
@Bean | |
public PlatformTransactionManager transactionManager(DataSource dataSource) { | |
//TODO 平台事务管理 | |
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(); | |
dataSourceTransactionManager.setDataSource(dataSource); | |
return dataSourceTransactionManager; | |
} | |
} |
具体内容不展开讲解,主要概述一下注解以及方法的作用:
@MapperScan:指定包扫描的路径。
DataSource dataSource:数据源的产生。
PlatformTransactionManager transactionManager:事务交由 Spring 管理。
# SpringMVC 整合配置
同样地,在 config 包下创建 SpringMvcConfig
package com.KarryCode.config; | |
import org.springframework.context.annotation.ComponentScan; | |
import org.springframework.context.annotation.Configuration; | |
import org.springframework.web.servlet.config.annotation.EnableWebMvc; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @PackageName com.KarryCode.config | |
* @ClassName SpringMvcConfig | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
@Configuration | |
@EnableWebMvc | |
@ComponentScan("com.KarryCode.controller") | |
public class SpringMvcConfig { | |
} |
# Servlet-api 整合配置
同样地,在 config 包下创建 ServletConfig
package com.KarryCode.config; | |
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; | |
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { | |
@Override | |
protected Class<?>[] getRootConfigClasses() { | |
return new Class[]{Spring_MybatisConfig.class}; | |
} | |
@Override | |
protected Class<?>[] getServletConfigClasses() { | |
return new Class[]{SpringMvcConfig.class}; | |
} | |
@Override | |
protected String[] getServletMappings() { | |
return new String[]{"/"}; | |
} | |
} |
此时的目录结构是这样的:
至此,整合已经基本完成!
# Bean 实体类创建
根据数据库里的以及逻辑关系创建 Bean 实体,在这里我先创建一个 Book 实体
package com.KarryCode.bean; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @PackageName com.KarryCode.bean | |
* @ClassName Book | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
public class Book { | |
private Integer id; | |
private String type; | |
private String name; | |
private String description; | |
// 省略 getter/setter/ 构造器(有参 / 无参)/toString | |
} |
# mapper 接口创建
在 mapper 包下创建一个 mapper 接口 BookMapper
package com.KarryCode.mapper; | |
import com.KarryCode.bean.Book; | |
import org.apache.ibatis.annotations.*; | |
import java.util.List; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @PackageName com.KarryCode.mapper | |
* @ClassName BookMapper | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
public interface BookMapper { | |
@Insert("insert into ssm_db.tb_book values (null,#{type},#{name},#{description})") | |
int save(Book book); | |
@Update("update ssm_db.tb_book set type=#{type},name=#{name},description=#{description} where id=#{id}") | |
int update(Book book); | |
@Delete("delete from ssm_db.tb_book where tb_book.id=#{id}") | |
int delete(Integer id); | |
@Select("select * from ssm_db.tb_book where id=#{id}") | |
@ResultType(Book.class) | |
Book getBookById(Integer id); | |
@Select("select * from ssm_db.tb_book") | |
List<Book> getBookList(); | |
} |
通过注解方式配置了增删改查四种方法
# mapper 代理 xml 创建
虽然没啥用,但是创建了也没什么坏处,在 resource 的对应目录下创建 BookMapper.xml
<?xml version="1.0" encoding="UTF-8" ?> | |
<!DOCTYPE mapper | |
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | |
"https://mybatis.org/dtd/mybatis-3-mapper.dtd"> | |
<mapper namespace="com.KarryCode.mapper.BookMapper"> | |
</mapper> |
# Service 逻辑创建
BookService 接口
package com.KarryCode.service; | |
import com.KarryCode.bean.Book; | |
import org.springframework.transaction.annotation.Transactional; | |
import java.util.List; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @ClassName BookService | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
@Transactional | |
public interface BookService { | |
/** | |
* @param book | |
* @return boolean | |
* @Author KarryLiu_刘珂瑞 | |
* @Date 2023/8/14 下午 10:58 | |
* @Description TODO 保存 | |
*/ | |
boolean save(Book book); | |
/** | |
* @param book | |
* @return boolean | |
* @Author KarryLiu_刘珂瑞 | |
* @Date 2023/8/14 下午 10:58 | |
* @Description TODO 修改 | |
*/ | |
boolean update(Book book); | |
/** | |
* @param id | |
* @return boolean | |
* @Author KarryLiu_刘珂瑞 | |
* @Date 2023/8/14 下午 10:58 | |
* @Description TODO 根据 id 删除 | |
*/ | |
boolean delete(Integer id); | |
/** | |
* @param id | |
* @return edu.beihua.bean.Book | |
* @Author KarryLiu_刘珂瑞 | |
* @Date 2023/8/14 下午 10:59 | |
* @Description TODO 根据 id 查询 | |
*/ | |
Book getBookById(Integer id); | |
/** | |
* @param | |
* @return java.util.List<edu.beihua.bean.Book> | |
* @Author KarryLiu_刘珂瑞 | |
* @Date 2023/8/14 下午 10:59 | |
* @Description TODO 查询全部 | |
*/ | |
List<Book> getBookList(); | |
} |
BookService 接口实现
package com.KarryCode.service.impl; | |
import com.KarryCode.bean.Book; | |
import com.KarryCode.mapper.BookMapper; | |
import com.KarryCode.service.BookService; | |
import org.springframework.stereotype.Service; | |
import javax.annotation.Resource; | |
import java.util.List; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @Date 2023/8/14 下午 10:43 | |
* @ClassName BookServiceImpl | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
@Service | |
public class BookServiceImpl implements BookService { | |
@Resource | |
private BookMapper bookMapper; | |
@Override | |
public boolean save(Book book) { | |
System.out.println("save=====>Service"); | |
int save = bookMapper.save(book); | |
if (save>0){ | |
return true; | |
}else { | |
return false; | |
} | |
} | |
@Override | |
public boolean update(Book book) { | |
System.out.println("update=====>Service"); | |
bookMapper.update(book); | |
return true; | |
} | |
@Override | |
public boolean delete(Integer id) { | |
System.out.println("delete=====>Service"); | |
bookMapper.delete(id); | |
return true; | |
} | |
@Override | |
public Book getBookById(Integer id) { | |
System.out.println("getBookById=====>Service"); | |
Book book = bookMapper.getBookById(id); | |
return book; | |
} | |
@Override | |
public List<Book> getBookList() { | |
System.out.println("getBookList=====>Service"); | |
return bookMapper.getBookList(); | |
} | |
} |
# Spring—Mybatis 通路检测
编写测试类,观察输出
import com.KarryCode.bean.Book; | |
import com.KarryCode.config.Spring_MybatisConfig; | |
import com.KarryCode.service.BookService; | |
import org.junit.Test; | |
import org.springframework.context.annotation.AnnotationConfigApplicationContext; | |
import java.util.List; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @PackageName PACKAGE_NAME | |
* @ClassName mybatisTest | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
public class mybatisSpringTest { | |
@Test | |
public void testMybatisSpring(){ | |
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Spring_MybatisConfig.class); | |
BookService bookService = annotationConfigApplicationContext.getBean(BookService.class); | |
List<Book> bookList = bookService.getBookList(); | |
System.out.println(bookList); | |
} | |
} |
输出
信息: {dataSource-1} inited
getBookList=====>Service
[Book {id=1, type=‘计算机’, name=‘软件工程’, description=‘吼吼吼吼’}, Book {id=2, type=‘文学’, name=‘儒家经典’, description=‘儒家好书啊!!!!!’}, Book {id=3, type=‘科技’, name=‘百科全书’, description=‘真不错!!!!’}, Book {id=4, type=‘美术’, name=‘当代顶流美术’, description=‘好书啊好书!!!!’}, Book {id=6, type=‘科技’, name=‘百科全书’, description=‘真不错!!!!’}, Book {id=7, type=‘科技’, name=‘百科全书’, description=‘真不错!!!!’}]
进程已结束,退出代码 0
至此,Spring—Mbatis 整合完成
# 构建 Controller
在 controller 包下创建 BookController
package com.KarryCode.controller; | |
import com.KarryCode.bean.Book; | |
import com.KarryCode.service.BookService; | |
import org.springframework.transaction.annotation.Transactional; | |
import org.springframework.web.bind.annotation.*; | |
import javax.annotation.Resource; | |
import java.util.List; | |
/** | |
* @Author KarryLiu | |
* @Creed may all the beauty be blessed | |
* @PackageName com.KarryCode.controller | |
* @ClassName BookController | |
* @Description TODO | |
* @Version 1.0 | |
*/ | |
@RestController | |
@Transactional | |
@RequestMapping("/books") | |
public class BookController { | |
@Resource | |
private BookService bookService; | |
@PostMapping | |
public boolean save(@RequestBody Book book) { | |
return bookService.save(book); | |
} | |
@PutMapping | |
public boolean update(@RequestBody Book book) { | |
return bookService.update(book); | |
} | |
@DeleteMapping("/{id}") | |
public boolean delete(@PathVariable Integer id) { | |
return bookService.delete(id); | |
} | |
@GetMapping("/{id}") | |
public Book getBookById(@PathVariable Integer id) { | |
return bookService.getBookById(id); | |
} | |
@GetMapping | |
public List<Book> getBookList() { | |
return bookService.getBookList(); | |
} | |
} |
符合 Restful 设计建议。
# 启动 Tomcat
# Postman 接口测试
# 存书测试
success
# 查书测试
# 查询全部
# 指定 id 查书
# 更新书
# 删除测试
所有接口测试调通,至此 SSM 整合完毕
# 总结
其实 SSM 整合还是比较简单的,通过三个框架的配置就可以完成了,后面的工作都是在进行业务创建。
好了!本篇文章到这里就结束了,有什么不理解的地方或者有疑问的地方请在评论区留言,或者添加我的联系方式,欢迎各位大佬积极批评讨论!谢谢!