作为一名有五年Java全栈开发经验的工程师,最近完成了一个基于SSM框架的个人时间管理系统开发项目。这个系统从开题到最终上线历时六个月,期间经历了需求变更、技术选型论证和三次架构调整。本文将完整还原这个企业级应用的开发过程,包括技术决策背后的思考、实际开发中遇到的典型问题以及解决方案。
在项目启动阶段,我们对比了多种Java技术栈,最终确定Spring+SpringMVC+MyBatis的组合主要基于以下考量:
Spring框架优势:
MyBatis的取舍:
实际开发中发现:MyBatis的XML配置方式虽然灵活,但在大型项目中容易造成XML文件膨胀。我们通过自定义SQL Builder类解决了这个问题。
最初考虑过React和Angular,最终选择Vue.js主要因为:
sql复制CREATE TABLE `time_block` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
`description` text,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`category_id` int(11) DEFAULT NULL,
`priority` tinyint(4) DEFAULT '2' COMMENT '1-高 2-中 3-低',
`status` tinyint(4) DEFAULT '0' COMMENT '0-未开始 1-进行中 2-已完成',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_time` (`user_id`,`start_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
索引策略:
缓存方案:
java复制@Service
public class TimeBlockServiceImpl implements TimeBlockService {
@Override
public List<TimeBlock> classifyByQuadrant(Integer userId) {
// 获取用户所有未完成的时间块
List<TimeBlock> blocks = timeBlockMapper.selectUnfinished(userId);
return blocks.stream()
.map(block -> {
// 根据紧急重要程度计算象限值
int quadrant = calculateQuadrant(
block.getUrgency(),
block.getImportance());
block.setQuadrant(quadrant);
return block;
})
.sorted(Comparator.comparingInt(TimeBlock::getQuadrant))
.collect(Collectors.toList());
}
private int calculateQuadrant(int urgency, int importance) {
if(urgency > 3 && importance > 3) return 1; // 重要紧急
if(urgency <=3 && importance >3) return 2; // 重要不紧急
if(urgency >3 && importance <=3) return 3; // 紧急不重要
return 4; // 不紧急不重要
}
}
xml复制<!-- pom.xml关键依赖 -->
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.18</version>
</dependency>
<!-- MyBatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- Vue.js前端集成 -->
<dependency>
<groupId>org.webjars.npm</groupId>
<artifactId>vue</artifactId>
<version>2.6.14</version>
</dependency>
</dependencies>
跨域问题:
java复制@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowCredentials(true)
.maxAge(3600);
}
}
时区问题:
properties复制# application.properties
spring.jackson.time-zone=GMT+8
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
我们采用Docker容器化部署,主要优势:
dockerfile复制# Dockerfile示例
FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY target/time-management-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
监控指标:
日志收集:
现象:当月数据超过500条时,日历视图加载超过3秒
排查过程:
解决方案:
现象:多人同时修改同一时间块导致状态不一致
解决方案:
java复制@Transactional
public boolean updateTimeBlockStatus(Integer id, Integer status) {
// 使用乐观锁控制并发
TimeBlock block = timeBlockMapper.selectForUpdate(id);
if(block.getVersion() != version) {
throw new OptimisticLockException("数据已被修改");
}
return timeBlockMapper.updateStatus(id, status, version+1) > 0;
}
这个项目让我对SSM框架有了更深入的理解,特别是在复杂业务场景下的应用。有几点特别值得分享的经验:
如果重新设计这个系统,我会考虑: