SSM框架整合实战:Spring+SpringMVC+MyBatis企业级开发指南 1. SSM框架整合概述SSMSpring Spring MVC MyBatis是目前Java企业级开发中最主流的框架组合之一。作为一名有多年Java开发经验的工程师我见证了这个技术栈从兴起到成为行业标准的过程。相比早期的SSHStruts2 Spring Hibernate组合SSM具有更轻量、更灵活、更适合现代Web开发的特点。在实际项目开发中我发现很多新手开发者虽然能单独使用这三个框架但在整合时总会遇到各种问题。本文将分享我在多个生产项目中总结出的SSM整合方案这个方案已经经过多个百万级用户项目的验证具有极高的稳定性和可维护性。2. 环境准备与项目搭建2.1 开发环境要求JDK 1.8Maven 3.6Tomcat 8.5MySQL 5.7IntelliJ IDEA/Eclipse提示强烈建议使用与教程一致的版本不同版本间可能存在兼容性问题。2.2 Maven项目初始化使用以下命令创建Maven项目骨架mvn archetype:generate -DgroupIdcom.example -DartifactIdssm-demo -DarchetypeArtifactIdmaven-archetype-webapp -DinteractiveModefalse2.3 目录结构调整标准的SSM项目目录结构如下src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ ├── controller/ │ │ ├── service/ │ │ │ ├── impl/ │ │ ├── dao/ │ │ ├── entity/ │ │ └── config/ │ ├── resources/ │ │ ├── spring/ │ │ ├── mybatis/ │ │ └── db.properties │ └── webapp/ │ ├── WEB-INF/ │ │ └── views/ │ └── resources/ └── test/ └── java/3. 核心框架配置3.1 Spring配置3.1.1 applicationContext.xml?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:txhttp://www.springframework.org/schema/tx xsi:schemaLocationhttp://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 !-- 扫描Service和DAO组件 -- context:component-scan base-packagecom.example context:exclude-filter typeannotation expressionorg.springframework.stereotype.Controller/ /context:component-scan !-- 加载数据库配置文件 -- context:property-placeholder locationclasspath:db.properties/ !-- 配置数据源 -- bean iddataSource classcom.alibaba.druid.pool.DruidDataSource property namedriverClassName value${jdbc.driver}/ property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ /bean !-- 配置事务管理器 -- bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManager property namedataSource refdataSource/ /bean !-- 开启注解事务 -- tx:annotation-driven transaction-managertransactionManager/ /beans3.1.2 db.propertiesjdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/ssm_demo?useSSLfalseuseUnicodetruecharacterEncodingUTF-8 jdbc.usernameroot jdbc.password1234563.2 Spring MVC配置3.2.1 spring-mvc.xml?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xmlns:contexthttp://www.springframework.org/schema/context xmlns:mvchttp://www.springframework.org/schema/mvc xsi:schemaLocationhttp://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 !-- 扫描Controller组件 -- context:component-scan base-packagecom.example.controller/ !-- 配置视图解析器 -- bean classorg.springframework.web.servlet.view.InternalResourceViewResolver property nameprefix value/WEB-INF/views// property namesuffix value.jsp/ /bean !-- 开启MVC注解驱动 -- mvc:annotation-driven/ !-- 静态资源处理 -- mvc:resources mapping/static/** location/static// /beans3.2.2 web.xml?xml version1.0 encodingUTF-8? web-app xmlnshttp://xmlns.jcp.org/xml/ns/javaee xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd version4.0 !-- 配置Spring上下文监听器 -- context-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/applicationContext.xml/param-value /context-param listener listener-classorg.springframework.web.context.ContextLoaderListener/listener-class /listener !-- 配置DispatcherServlet -- servlet servlet-namedispatcherServlet/servlet-name servlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class init-param param-namecontextConfigLocation/param-name param-valueclasspath:spring/spring-mvc.xml/param-value /init-param load-on-startup1/load-on-startup /servlet servlet-mapping servlet-namedispatcherServlet/servlet-name url-pattern//url-pattern /servlet-mapping !-- 字符编码过滤器 -- filter filter-namecharacterEncodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filter filter-mapping filter-namecharacterEncodingFilter/filter-name url-pattern/*/url-pattern /filter-mapping /web-app3.3 MyBatis配置3.3.1 mybatis-config.xml?xml version1.0 encodingUTF-8 ? !DOCTYPE configuration PUBLIC -//mybatis.org//DTD Config 3.0//EN http://mybatis.org/dtd/mybatis-3-config.dtd configuration settings !-- 开启驼峰命名自动映射 -- setting namemapUnderscoreToCamelCase valuetrue/ !-- 打印SQL语句 -- setting namelogImpl valueSTDOUT_LOGGING/ /settings typeAliases package namecom.example.entity/ /typeAliases /configuration3.3.2 Spring整合MyBatis配置在applicationContext.xml中添加!-- 配置SqlSessionFactory -- bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean property namedataSource refdataSource/ property nameconfigLocation valueclasspath:mybatis/mybatis-config.xml/ property namemapperLocations valueclasspath:mybatis/mapper/*.xml/ /bean !-- 配置Mapper扫描器 -- bean classorg.mybatis.spring.mapper.MapperScannerConfigurer property namebasePackage valuecom.example.dao/ /bean4. 业务代码实现4.1 实体类示例package com.example.entity; import java.io.Serializable; public class User implements Serializable { private Integer id; private String username; private String password; private String email; // getters and setters // toString() }4.2 DAO层实现4.2.1 接口定义package com.example.dao; import com.example.entity.User; import java.util.List; public interface UserDao { User selectById(Integer id); ListUser selectAll(); int insert(User user); int update(User user); int delete(Integer id); }4.2.2 Mapper XML?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.dao.UserDao resultMap iduserMap typeUser id propertyid columnid/ result propertyusername columnusername/ result propertypassword columnpassword/ result propertyemail columnemail/ /resultMap select idselectById resultMapuserMap SELECT * FROM user WHERE id #{id} /select select idselectAll resultMapuserMap SELECT * FROM user /select insert idinsert useGeneratedKeystrue keyPropertyid INSERT INTO user(username, password, email) VALUES(#{username}, #{password}, #{email}) /insert update idupdate UPDATE user SET username#{username}, password#{password}, email#{email} WHERE id#{id} /update delete iddelete DELETE FROM user WHERE id#{id} /delete /mapper4.3 Service层实现4.3.1 服务接口package com.example.service; import com.example.entity.User; import java.util.List; public interface UserService { User getUserById(Integer id); ListUser getAllUsers(); boolean addUser(User user); boolean updateUser(User user); boolean deleteUser(Integer id); }4.3.2 服务实现package com.example.service.impl; import com.example.dao.UserDao; import com.example.entity.User; import com.example.service.UserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; Service Transactional public class UserServiceImpl implements UserService { Autowired private UserDao userDao; Override public User getUserById(Integer id) { return userDao.selectById(id); } Override public ListUser getAllUsers() { return userDao.selectAll(); } Override public boolean addUser(User user) { return userDao.insert(user) 0; } Override public boolean updateUser(User user) { return userDao.update(user) 0; } Override public boolean deleteUser(Integer id) { return userDao.delete(id) 0; } }4.4 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) public class UserController { Autowired private UserService userService; GetMapping(/{id}) public String getUser(PathVariable Integer id, Model model) { User user userService.getUserById(id); model.addAttribute(user, user); return user/detail; } GetMapping(/list) public String listUsers(Model model) { ListUser users userService.getAllUsers(); model.addAttribute(users, users); return user/list; } GetMapping(/add) public String toAddPage() { return user/add; } PostMapping(/add) public String addUser(User user) { userService.addUser(user); return redirect:/user/list; } GetMapping(/edit/{id}) public String toEditPage(PathVariable Integer id, Model model) { User user userService.getUserById(id); model.addAttribute(user, user); return user/edit; } PutMapping(/edit) public String editUser(User user) { userService.updateUser(user); return redirect:/user/list; } DeleteMapping(/{id}) public String deleteUser(PathVariable Integer id) { userService.deleteUser(id); return redirect:/user/list; } }5. 视图层实现5.1 用户列表页面 (list.jsp)% page contentTypetext/html;charsetUTF-8 languagejava % % taglib prefixc urihttp://java.sun.com/jsp/jstl/core % html head title用户列表/title /head body h2用户列表/h2 a href/user/add新增用户/a table border1 tr thID/th th用户名/th th邮箱/th th操作/th /tr c:forEach items${users} varuser tr td${user.id}/td td${user.username}/td td${user.email}/td td a href/user/${user.id}查看/a a href/user/edit/${user.id}编辑/a a href/user/${user.id} onclickreturn confirm(确定删除吗)删除/a /td /tr /c:forEach /table /body /html5.2 用户详情页面 (detail.jsp)% page contentTypetext/html;charsetUTF-8 languagejava % html head title用户详情/title /head body h2用户详情/h2 pID: ${user.id}/p p用户名: ${user.username}/p p邮箱: ${user.email}/p a href/user/list返回列表/a /body /html6. 测试与验证6.1 单元测试package com.example.service; import com.example.entity.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.List; RunWith(SpringJUnit4ClassRunner.class) ContextConfiguration(locations classpath:spring/applicationContext.xml) public class UserServiceTest { Autowired private UserService userService; Test public void testCRUD() { // 测试新增 User user new User(); user.setUsername(testUser); user.setPassword(123456); user.setEmail(testexample.com); userService.addUser(user); // 测试查询 User dbUser userService.getUserById(user.getId()); System.out.println(dbUser); // 测试更新 dbUser.setEmail(newexample.com); userService.updateUser(dbUser); // 测试列表查询 ListUser users userService.getAllUsers(); users.forEach(System.out::println); // 测试删除 userService.deleteUser(user.getId()); } }6.2 集成测试启动Tomcat服务器访问http://localhost:8080/user/list测试各个功能点新增用户查看用户详情编辑用户信息删除用户7. 常见问题与解决方案7.1 事务不生效问题问题现象Service层方法执行异常时数据库操作没有回滚。解决方案确保在applicationContext.xml中配置了事务管理器确保开启了注解驱动tx:annotation-driven/在Service实现类上添加Transactional注解检查异常类型默认只对RuntimeException回滚可通过Transactional(rollbackForException.class)修改7.2 MyBatis映射文件找不到问题现象启动时报错提示找不到Mapper.xml文件。解决方案检查sqlSessionFactory的mapperLocations配置路径是否正确确保Mapper.xml文件放在了resources/mybatis/mapper目录下检查Mapper.xml的文件名是否与接口名一致Maven项目中确保resources目录被正确识别可在pom.xml中添加build配置7.3 静态资源访问不到问题现象CSS/JS/图片等静态资源无法加载。解决方案在spring-mvc.xml中配置mvc:resources确保静态资源放在了webapp/static目录下检查路径引用是否正确如link href/static/css/style.css relstylesheet7.4 中文乱码问题问题现象页面显示或数据库存储出现乱码。解决方案确保web.xml中配置了CharacterEncodingFilter检查数据库连接URL是否包含useUnicodetruecharacterEncodingUTF-8确保JSP页面设置了% page contentTypetext/html;charsetUTF-8 %检查Tomcat的server.xml中Connector配置了URIEncodingUTF-88. 性能优化建议8.1 数据库连接池优化推荐使用Druid连接池配置示例bean iddataSource classcom.alibaba.druid.pool.DruidDataSource init-methodinit destroy-methodclose property nameurl value${jdbc.url}/ property nameusername value${jdbc.username}/ property namepassword value${jdbc.password}/ property nameinitialSize value5/ property nameminIdle value5/ property namemaxActive value20/ property namemaxWait value60000/ property nametimeBetweenEvictionRunsMillis value60000/ property nameminEvictableIdleTimeMillis value300000/ property namevalidationQuery valueSELECT 1/ property nametestWhileIdle valuetrue/ property nametestOnBorrow valuefalse/ property nametestOnReturn valuefalse/ property namepoolPreparedStatements valuetrue/ property namemaxPoolPreparedStatementPerConnectionSize value20/ property namefilters valuestat,wall/ /bean8.2 MyBatis二级缓存启用MyBatis二级缓存可以显著提高查询性能在mybatis-config.xml中配置settings setting namecacheEnabled valuetrue/ /settings在Mapper.xml中添加缓存配置cache evictionLRU flushInterval60000 size512 readOnlytrue/8.3 SQL性能优化为常用查询字段添加索引避免使用SELECT *只查询需要的字段复杂查询考虑使用MyBatis的关联查询或多次简单查询大数据量查询考虑使用分页插件9. 项目扩展方向9.1 集成Redis缓存添加Redis依赖dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency配置RedisTemplateConfiguration public class RedisConfig { Bean public RedisTemplateString, Object redisTemplate(RedisConnectionFactory factory) { RedisTemplateString, Object template new RedisTemplate(); template.setConnectionFactory(factory); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); return template; } }9.2 添加Swagger接口文档添加Swagger依赖dependency groupIdio.springfox/groupId artifactIdspringfox-swagger2/artifactId version2.9.2/version /dependency dependency groupIdio.springfox/groupId artifactIdspringfox-swagger-ui/artifactId version2.9.2/version /dependency配置SwaggerConfiguration EnableSwagger2 public class SwaggerConfig { Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage(com.example.controller)) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(SSM项目API文档) .description(SSM框架整合示例项目) .version(1.0) .build(); } }9.3 日志系统集成推荐使用SLF4J Logback组合添加依赖dependency groupIdch.qos.logback/groupId artifactIdlogback-classic/artifactId version1.2.3/version /dependency配置logback.xml?xml version1.0 encodingUTF-8? configuration property nameLOG_HOME value/logs/ appender nameSTDOUT classch.qos.logback.core.ConsoleAppender encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/pattern /encoder /appender appender nameFILE classch.qos.logback.core.rolling.RollingFileAppender file${LOG_HOME}/ssm-demo.log/file rollingPolicy classch.qos.logback.core.rolling.TimeBasedRollingPolicy fileNamePattern${LOG_HOME}/ssm-demo.%d{yyyy-MM-dd}.log/fileNamePattern maxHistory30/maxHistory /rollingPolicy encoder pattern%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n/pattern /encoder /appender root levelINFO appender-ref refSTDOUT/ appender-ref refFILE/ /root logger namecom.example levelDEBUG/ /configuration10. 生产环境部署建议10.1 安全配置数据库密码加密使用Jasypt等工具加密配置文件中的敏感信息防止SQL注入使用MyBatis的#{}参数绑定XSS防护在Controller层对用户输入进行过滤CSRF防护Spring Security提供了CSRF防护支持10.2 性能调优Tomcat优化调整连接器配置启用NIO模式合理设置线程池参数JVM优化设置合适的堆内存大小选择合适的垃圾收集器配置GC日志监控10.3 监控方案使用Spring Boot Actuator监控应用健康状态集成Prometheus Grafana实现可视化监控使用ELK收集和分析日志配置告警机制对异常情况进行及时通知11. 总结与经验分享在实际项目开发中SSM框架的整合只是基础工作更重要的是理解每个框架的设计理念和最佳实践。以下是我在多个项目中总结的一些经验分层清晰严格遵循Controller-Service-Dao的分层架构每层只关注自己的职责事务控制事务应放在Service层且粒度要合理避免大事务异常处理使用统一的异常处理机制避免直接向上抛出原生异常代码规范遵循团队约定的代码规范保持风格一致测试驱动为关键业务逻辑编写单元测试和集成测试对于初学者建议从简单的CRUD功能开始逐步深入理解框架的各个组件。遇到问题时多查阅官方文档和源码这是最好的学习资料。