1. SSM框架整合实战:从零搭建企业级Java应用
在Java企业级应用开发领域,SSM(Spring+SpringMVC+MyBatis)框架组合长期占据重要地位。这套技术栈以Spring为核心,整合了轻量级的Web框架SpringMVC和持久层框架MyBatis,形成了完整的MVC开发体系。我曾在多个电商和ERP系统中采用SSM架构,其模块化设计和可扩展性尤其适合快速迭代的中大型项目。
1.1 为什么选择SSM组合?
Spring的IoC容器和AOP支持为应用提供了基础设施,SpringMVC处理Web层请求路由,MyBatis则简化了数据库操作。这种组合相比传统SSH(Spring+Struts+Hibernate)更加轻量,且MyBatis的SQL可控性在复杂查询场景下优势明显。最新统计显示,国内70%以上的JavaWeb项目仍在使用或兼容SSM架构。
2. 环境准备与基础配置
2.1 开发环境搭建
推荐使用以下环境组合:
- JDK 1.8(长期支持版本)
- Apache Maven 3.6+(依赖管理)
- Tomcat 9.x(Servlet容器)
- IntelliJ IDEA/Eclipse(开发工具)
在pom.xml中需包含的核心依赖:
xml复制<!-- Spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<!-- MyBatis整合包 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
2.2 配置文件结构
标准SSM项目通常包含以下配置文件:
code复制src/main/resources/
├── applicationContext.xml # Spring主配置
├── spring-mvc.xml # MVC相关配置
├── mybatis-config.xml # MyBatis全局配置
└── jdbc.properties # 数据库连接配置
重要提示:建议采用分模块配置方式,避免单个配置文件过大。现代项目更推荐使用Java Config替代XML配置。
3. 核心整合流程详解
3.1 Spring与MyBatis整合关键步骤
- 配置数据源(以Druid为例):
xml复制<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
- 配置SqlSessionFactory:
xml复制<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
- 配置Mapper扫描:
xml复制<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.dao"/>
</bean>
3.2 SpringMVC整合要点
在web.xml中配置DispatcherServlet:
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-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
4. 实战开发技巧与优化
4.1 事务管理配置
声明式事务配置示例:
xml复制<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
4.2 性能优化建议
- MyBatis二级缓存配置:
xml复制<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
- 连接池参数调优(Druid推荐值):
properties复制# 初始连接数
druid.initialSize=5
# 最大连接数
druid.maxActive=20
# 获取连接超时时间(ms)
druid.maxWait=60000
5. 常见问题排查指南
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 404错误 | 控制器未扫描 | 检查component-scan包路径 |
| SQL语句不执行 | 事务未生效 | 添加@Transactional注解 |
| 参数绑定失败 | 日期格式问题 | 配置Formatter或使用@DateTimeFormat |
经验之谈:遇到MyBatis映射问题时,先检查XML文件中namespace是否与Mapper接口全限定名一致,这是新手最容易出错的地方。
6. 项目结构最佳实践
推荐的项目目录结构:
code复制src/
├── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ ├── controller/ # 控制器层
│ │ ├── service/ # 业务层
│ │ ├── dao/ # 数据访问层
│ │ └── entity/ # 实体类
│ └── resources/
│ ├── mapper/ # MyBatis映射文件
│ └── static/ # 静态资源
└── test/ # 测试代码
在实际项目中,我习惯采用分层打包方式,每个模块有独立的包名。例如电商系统可分为:
- com.example.mall.product
- com.example.mall.order
- com.example.mall.user
这种结构在后期微服务拆分时迁移成本更低。
7. 进阶整合方案
7.1 整合Redis缓存
添加Spring Data Redis支持:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
配置缓存管理器:
java复制@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory).cacheDefaults(config).build();
}
7.2 接口文档整合
使用Swagger生成API文档:
java复制@Configuration
@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();
}
}
8. 测试策略与持续集成
8.1 分层测试方案
- DAO层测试:
java复制@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class UserDaoTest {
@Autowired
private UserDao userDao;
@Test
public void testSelectById() {
User user = userDao.selectById(1L);
assertNotNull(user);
}
}
- Service层测试(Mock方案):
java复制@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
@Mock
private UserDao userDao;
@InjectMocks
private UserServiceImpl userService;
@Test
public void testLoginSuccess() {
when(userDao.findByUsername(anyString())).thenReturn(new User());
boolean result = userService.login("admin", "123456");
assertTrue(result);
}
}
9. 安全防护方案
9.1 基础安全配置
- XSS防护过滤器:
java复制public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);
}
}
- CSRF防护(Spring Security方案):
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}
10. 部署与监控
10.1 生产环境配置建议
- Tomcat优化参数:
properties复制# 最大线程数
server.tomcat.max-threads=200
# 连接超时(ms)
server.connection-timeout=30000
- JVM参数推荐:
bash复制-Xms1024m -Xmx2048m -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError
10.2 监控方案集成
- Spring Boot Actuator:
xml复制<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
- Prometheus监控配置:
java复制@Bean
public MeterRegistryCustomizer<PrometheusMeterRegistry> metricsCommonTags() {
return registry -> registry.config().commonTags("application", "ssm-demo");
}
在项目演进过程中,我发现合理的日志规范能极大提升排查效率。建议采用SLF4J+Logback组合,按功能模块划分日志文件,关键业务操作记录审计日志。例如用户模块可以配置独立的日志文件:
xml复制<appender name="USER_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/user.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/user.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
</appender>
