1. SSM框架技术解析与实战总结
在Java企业级开发领域,SSM(Spring+SpringMVC+MyBatis)框架组合至今仍是许多中大型项目的首选技术栈。作为一名长期使用SSM进行业务开发的老兵,今天想系统梳理这套经典框架的技术要点和实战经验。不同于市面上泛泛而谈的教程,本文将重点分享那些官方文档不会告诉你的工程实践细节。
2. SSM框架核心组件精要
2.1 Spring IoC容器设计精要
Spring的核心在于其IoC容器设计。在实际项目中,我习惯采用JavaConfig配置方式替代传统的XML配置。这种配置方式不仅类型安全,还能利用IDE的代码提示功能减少配置错误。以下是一个典型的多环境配置示例:
@Configuration @Profile("dev") public class DevConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.H2) .addScript("classpath:schema.sql") .build(); } }关键经验:使用@Profile注解实现环境隔离时,务必在web.xml或启动类中显式设置spring.profiles.active参数,否则会导致配置不生效
2.2 SpringMVC请求处理机制
SpringMVC的拦截器(Interceptor)是经常被低估的利器。在电商项目中,我们通过自定义拦截器实现了以下功能:
- 接口耗时监控
- 权限校验
- 请求参数预处理
public class PerformanceInterceptor implements HandlerInterceptor { private static final Logger logger = LoggerFactory.getLogger(PerformanceInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { request.setAttribute("startTime", System.currentTimeMillis()); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { long startTime = (Long) request.getAttribute("startTime"); logger.info("Request '{}' cost {}ms", request.getRequestURI(), System.currentTimeMillis() - startTime); } }2.3 MyBatis高级特性应用
MyBatis的动态SQL能力在复杂查询场景中表现出色。以下是几个实用技巧:
- 使用 片段复用公共SQL块
- 利用 处理批量操作
- 通过 实现条件分支
<select id="searchProducts" resultType="Product"> SELECT * FROM products <where> <if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="minPrice != null"> AND price >= #{minPrice} </if> <choose> <when test="sortBy == 'price'"> ORDER BY price </when> <otherwise> ORDER BY create_time DESC </otherwise> </choose> </where> </select>3. SSM项目实战经验
3.1 事务管理最佳实践
Spring的声明式事务看似简单,实则暗藏玄机。在金融项目中,我们曾遇到事务不生效的问题,最终发现是以下原因导致:
- 方法修饰符非public
- 自调用问题(调用同类中的@Transactional方法)
- 异常类型未被捕获
解决方案表格:
| 问题现象 | 根本原因 | 解决方案 |
|---|---|---|
| 事务不生效 | 方法非public | 确保@Transactional标注在public方法上 |
| 事务回滚失败 | 捕获了Exception | 在@Transactional中指定rollbackFor |
| 部分操作未回滚 | 使用了try-catch | 在catch块中手动抛出RuntimeException |
3.2 性能优化方案
经过多个项目的性能调优,总结出以下有效手段:
- MyBatis二级缓存配置:
<settings> <setting name="cacheEnabled" value="true"/> <setting name="localCacheScope" value="STATEMENT"/> </settings>- 连接池参数优化(以Druid为例):
# 初始连接数 druid.initialSize=5 # 最大连接数 druid.maxActive=50 # 获取连接超时时间(ms) druid.maxWait=60000 # 间隔检测时间(ms) druid.timeBetweenEvictionRunsMillis=60000- SQL优化黄金法则:
- 避免SELECT *
- 合理使用索引
- 控制JOIN表数量
- 大数据量查询使用分页
4. 典型问题排查指南
4.1 中文乱码问题
SSM项目中的中文乱码通常出现在以下环节:
- 数据库连接配置:
jdbc.url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=UTF-8- SpringMVC消息转换器:
@Bean public HttpMessageConverter<String> responseBodyConverter() { return new StringHttpMessageConverter(StandardCharsets.UTF_8); }- web.xml过滤器配置:
<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> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter>4.2 跨域解决方案
前后端分离项目中常见的跨域问题,可以通过以下方式解决:
- 全局CORS配置:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .maxAge(3600); } }- 控制器级别配置:
@RestController @RequestMapping("/api") @CrossOrigin(origins = "http://localhost:8080") public class ApiController { // 控制器方法 }5. 项目结构设计建议
经过多个SSM项目的实践,推荐采用以下分层结构:
src/main/java ├── com.example │ ├── config # Spring配置类 │ ├── controller # 控制器层 │ ├── service # 业务逻辑层 │ │ ├── impl # 服务实现 │ ├── dao # 数据访问层 │ ├── entity # 实体类 │ ├── dto # 数据传输对象 │ ├── util # 工具类 │ └── exception # 异常处理 src/main/resources ├── mapper # MyBatis映射文件 ├── static # 静态资源 └── application.properties在微服务架构下,SSM仍然可以作为单个服务的实现框架。最近在物流系统中,我们采用SSM+Dubbo的方案实现了分布式服务,其中MyBatis的Mapper接口直接作为Dubbo服务接口实现,既保持了架构简单性又满足了分布式需求。