前言
最近接手了一个跑了五六年的老项目,SSM(Spring + Spring MVC + MyBatis)架构,XML 配置堆成山,启动要等两分钟,每次加个需求都要折腾半天。
老板说:能不能给它升级一下?
于是花了两周时间,把这个老古董从 SSM 搬到了 Spring Boot 3.x。记录一下踩过的坑和实战经验,希望对你有帮助。
一、迁移前的老项目长什么样
典型的 SSM 项目结构:
src/ ├── main/ │ ├── java/ │ │ └── com/xxx/ │ │ ├── controller/ │ │ ├── service/ │ │ ├── dao/ │ │ └── entity/ │ └── resources/ │ ├── spring/ │ │ ├── spring-context.xml │ │ ├── spring-mvc.xml │ │ └── spring-mybatis.xml │ ├── mybatis/ │ │ └── mapper/ │ ├── jdbc.properties │ └── log4j.properties └── webapp/ └── WEB-INF/ └── web.xml痛点很明显:
- XML 配置文件 5 个起步,互相引用,改一个漏一个
- 依赖版本全靠手动维护,jar 包冲突是家常便饭
- 没有内嵌 Tomcat,开发调试依赖外部容器
- 包扫描、拦截器、视图解析器全部手配
二、迁移的核心思路
迁移不是重写,不要动业务逻辑。我的原则是:
只改框架层,不改业务代码
整体步骤
1. 新建 Spring Boot 项目 2. 逐层替换配置文件 3. 复制业务代码(Service/Controller/Mapper) 4. 改造 MyBatis 配置 5. 测试验证三、具体实施过程
3.1 新建 Spring Boot 项目
用 Spring Initializr 生成,选择依赖:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.3</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.20</version></dependency></dependencies>新项目结构:
src/main/java/com/xxx/ ├── controller/ ├── service/ ├── mapper/ ├── entity/ └── XxxApplication.java3.2 配置文件迁移
SSM 时期— 一堆 XML:
<!-- spring-mybatis.xml --><beanid="dataSource"class="com.alibaba.druid.pool.DruidDataSource"><propertyname="driverClassName"value="${jdbc.driver}"/><propertyname="url"value="${jdbc.url}"/><propertyname="username"value="${jdbc.username}"/><propertyname="password"value="${jdbc.password}"/></bean><beanclass="org.mybatis.spring.SqlSessionFactoryBean"><propertyname="dataSource"ref="dataSource"/><propertyname="mapperLocations"value="classpath:mybatis/mapper/*.xml"/></bean><beanclass="org.mybatis.spring.mapper.MapperScannerConfigurer"><propertyname="basePackage"value="com.xxx.dao"/></bean>Spring Boot 时期— application.yml 搞定一切:
spring:datasource:url:jdbc:mysql://localhost:3306/xxx?useUnicode=true&characterEncoding=utf-8username:rootpassword:123456driver-class-name:com.mysql.cj.jdbc.Drivertype:com.alibaba.druid.pool.DruidDataSourcemybatis:mapper-locations:classpath:mapper/*.xmltype-aliases-package:com.xxx.entityconfiguration:map-underscore-to-camel-case:truelog-impl:org.apache.ibatis.logging.stdout.StdOutImpl以前 50 行的 XML,现在 15 行配置搞定。
3.3 web.xml 替换
SSM 的 web.xml:
<servlet><servlet-name>dispatcher</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></servlet><filter><filter-name>encoding</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>Spring Boot 里直接加一个配置类替代:
@ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(newLoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login","/css/**","/js/**");}@BeanpublicFiltercharacterEncodingFilter(){CharacterEncodingFilterfilter=newCharacterEncodingFilter();filter.setEncoding("UTF-8");filter.setForceEncoding(true);returnfilter;}}3.4 最坑的地方 — MyBatis 兼容问题
坑 1:MyBatis 3.5+ 废弃了useGeneratedKeys的默认行为
老项目 Mapper 里如果用了selectKey,需要显式声明:
<insertid="insert"useGeneratedKeys="true"keyProperty="id">INSERT INTO user(name) VALUES(#{name})</insert>坑 2:日期类型处理
老项目用的java.util.Date,Spring Boot 3.x 默认走java.time系列。加一个配置解决:
spring:jackson:date-format:yyyy-MM-dd HH:mm:sstime-zone:Asia/Shanghai坑 3:分页插件版本不兼容
老项目 PageHelper 4.x → 升级到 PageHelper 6.x:
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><version>2.1.0</version></dependency>pagehelper:helper-dialect:mysqlreasonable:true3.5 日志配置迁移
SSM 时期:
log4j.rootLogger=INFO, Console log4j.appender.Console=org.apache.log4j.ConsoleAppender log4j.appender.Console.layout=org.apache.log4j.PatternLayout log4j.appender.Console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %m%nSpring Boot 时期(logback-spring.xml):
<?xml version="1.0" encoding="UTF-8"?><configuration><appendername="CONSOLE"class="ch.qos.logback.core.ConsoleAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern></encoder></appender><rootlevel="INFO"><appender-refref="CONSOLE"/></root></configuration>四、踩坑总结
| 编号 | 坑 | 解决 |
|---|---|---|
| 1 | javax.*迁移到jakarta.* | Spring Boot 3.x 全部用 jakarta,替换 import |
| 2 | 拦截器不走 | 配置类加@Configuration+implements WebMvcConfigurer |
| 3 | 静态资源 404 | 加spring.web.resources.static-locations配置 |
| 4 | JSP 无法渲染 | Spring Boot 官方不推荐 JSP,建议逐步替换为 Thymeleaf |
| 5 | 事务不生效 | 确保@EnableTransactionManagement+ DataSource 配置正确 |
五、迁移前后对比
| 指标 | SSM(老) | Spring Boot(新) |
|---|---|---|
| 配置文件数量 | 6 个 XML + 2 个 properties | 1 个 yml |
| 应用启动时间 | ~120 秒 | ~15 秒 |
| 构建方式 | Maven + 手动部署 | Maven + java -jar |
| 部署方式 | 打 war 丢 Tomcat | 打 jar 直接跑 |
| 开发体验 | 改一行配置重启半天 | 热更新秒级生效 |
六、写在最后
SSM 迁移 Spring Boot 这件事,技术难度不高,但对耐心和细心的要求很高。
一个合理的迁移节奏是:
第1天:梳理老项目配置和依赖 → 第2天:搭新项目框架 第3-5天:逐模块迁移 → 第6-7天:联调测试如果你也有老项目要迁移,遇到搞不定的问题,欢迎私信交流。
接老项目迁移 / Java 后端开发,有需要可私信联系。