1. 项目概述
作为一名在高校信息化建设领域深耕多年的开发者,我最近完成了一个基于SpringBoot的高校游泳馆管理系统项目。这个系统旨在解决传统高校游泳馆管理中的诸多痛点:预约流程繁琐、资源分配不均、数据统计困难等问题。
在实际开发过程中,我发现高校游泳馆管理存在几个典型问题:
- 高峰期场地预约困难,学生需要排队或提前多日预约
- 教练课程安排和学员管理效率低下
- 设备借用归还流程混乱
- 财务统计和报表生成工作量大
针对这些问题,我设计开发了这套管理系统,主要面向三类用户:
- 学生用户:可在线预约场地、课程、设备
- 教练用户:管理课程安排和学员信息
- 管理员:全面管理游泳馆运营数据
2. 技术选型与架构设计
2.1 技术栈选择
在技术选型上,我基于以下考虑选择了当前技术组合:
后端技术栈:
- SpringBoot 2.7.3:简化配置,快速开发
- MyBatis-Plus 3.5.1:增强的ORM框架
- Spring Security:安全认证
- Redis 6.2:缓存和会话管理
前端技术栈:
- Vue 3.2 + Element Plus:现代化UI
- Axios:HTTP请求处理
- ECharts:数据可视化
数据库:
- MySQL 8.0:关系型数据库
- 采用InnoDB引擎,支持事务
服务器环境:
- Tomcat 9.0
- JDK 11
- Windows Server 2019
选择这些技术的主要原因是:
- SpringBoot的自动配置和起步依赖可以大幅减少配置时间
- Vue+Element Plus组合能快速构建美观的管理界面
- MySQL在高校信息化系统中应用广泛,运维经验丰富
2.2 系统架构设计
系统采用经典的三层架构:
code复制表现层(UI)
↑↓
业务逻辑层(Service)
↑↓
数据访问层(DAO)
表现层:
- 基于Vue的单页面应用
- 采用RESTful API与后端交互
- 实现响应式布局,适配PC和移动端
业务逻辑层:
- 采用领域驱动设计(DDD)
- 核心业务逻辑封装在Service
- 事务管理在Service层实现
数据访问层:
- MyBatis-Plus实现CRUD
- 动态SQL处理复杂查询
- 二级缓存提升性能
3. 核心功能实现
3.1 预约管理模块
这是系统的核心功能,我设计了以下关键表结构:
sql复制CREATE TABLE `reservation` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`resource_type` tinyint NOT NULL COMMENT '1-场地 2-课程 3-设备',
`resource_id` bigint NOT NULL,
`start_time` datetime NOT NULL,
`end_time` datetime NOT NULL,
`status` tinyint DEFAULT '0' COMMENT '0-待确认 1-已确认 2-已取消',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user` (`user_id`),
KEY `idx_resource` (`resource_type`,`resource_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
关键业务逻辑:
- 并发控制:
java复制@Transactional
public boolean makeReservation(ReservationDTO dto) {
// 检查资源是否可用
if(!resourceService.isAvailable(dto.getResourceType(), dto.getResourceId(),
dto.getStartTime(), dto.getEndTime())) {
throw new BusinessException("该时段已被预约");
}
// 创建预约记录
Reservation reservation = convertToEntity(dto);
reservationMapper.insert(reservation);
// 更新资源状态
resourceService.lock(dto.getResourceType(), dto.getResourceId(),
dto.getStartTime(), dto.getEndTime());
return true;
}
- 预约冲突检测算法:
- 使用时间区间重叠检测
- SQL实现:
sql复制SELECT COUNT(*) FROM reservation
WHERE resource_type = #{type}
AND resource_id = #{id}
AND NOT (end_time <= #{start} OR start_time >= #{end})
3.2 支付模块集成
考虑到高校场景的特殊性,我实现了两种支付方式:
- 校园卡支付(对接学校一卡通系统)
- 第三方支付(微信/支付宝)
支付状态机设计:
code复制待支付 → 支付中 → 已支付
↓
支付失败
关键代码:
java复制public PaymentResult processPayment(PaymentRequest request) {
Payment payment = createPaymentRecord(request);
try {
if(request.getType() == PaymentType.CAMPUS_CARD) {
campusCardService.deduct(request.getStudentId(), request.getAmount());
} else {
thirdPartyPayService.pay(request);
}
payment.setStatus(PaymentStatus.SUCCESS);
} catch (Exception e) {
payment.setStatus(PaymentStatus.FAILED);
throw new PaymentException("支付失败", e);
} finally {
paymentMapper.updateById(payment);
}
return convertToResult(payment);
}
4. 数据库设计与优化
4.1 主要表结构
除了前面提到的预约表,系统核心表还包括:
用户表:
sql复制CREATE TABLE `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
`real_name` varchar(50) DEFAULT NULL,
`student_id` varchar(20) DEFAULT NULL,
`phone` varchar(20) DEFAULT NULL,
`email` varchar(50) DEFAULT NULL,
`avatar` varchar(255) DEFAULT NULL,
`type` tinyint DEFAULT '0' COMMENT '0-学生 1-教练 2-管理员',
`status` tinyint DEFAULT '1' COMMENT '0-禁用 1-正常',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_username` (`username`),
KEY `idx_student_id` (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
场地表:
sql复制CREATE TABLE `venue` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`type` tinyint DEFAULT '0' COMMENT '0-训练池 1-比赛池',
`capacity` int DEFAULT '0',
`status` tinyint DEFAULT '1' COMMENT '0-维护中 1-可用',
`description` text,
`price_per_hour` decimal(10,2) DEFAULT '0.00',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
4.2 索引优化实践
在高并发预约场景下,我特别优化了索引:
- 复合索引:
sql复制ALTER TABLE reservation ADD INDEX idx_resource_time (resource_type, resource_id, start_time, end_time);
- 覆盖索引:
sql复制ALTER TABLE user ADD INDEX idx_student_phone (student_id, phone);
- 执行计划分析:
sql复制EXPLAIN SELECT * FROM reservation
WHERE resource_type = 1
AND resource_id = 100
AND start_time >= '2023-06-01 00:00:00'
5. 安全设计与实现
5.1 认证与授权
采用JWT + Spring Security实现安全控制:
java复制@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/student/**").hasRole("STUDENT")
.antMatchers("/api/coach/**").hasRole("COACH")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager()));
}
}
5.2 数据安全
- 敏感数据加密:
java复制public class PasswordEncoder implements org.springframework.security.crypto.password.PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return BCrypt.hashpw(rawPassword.toString(), BCrypt.gensalt());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
}
- SQL注入防护:
- 全部使用MyBatis参数绑定
- 禁止拼接SQL语句
6. 性能优化实践
6.1 缓存策略
采用多级缓存架构:
- 本地缓存(Caffeine):高频访问的配置数据
- Redis缓存:
- 热点数据
- 分布式锁
- 会话管理
缓存配置示例:
java复制@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return cacheManager;
}
@Bean
public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours(1))
.disableCachingNullValues();
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
6.2 数据库连接池优化
使用HikariCP配置:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5
idle-timeout: 30000
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
7. 系统测试与部署
7.1 测试策略
采用分层测试策略:
- 单元测试:JUnit 5 + Mockito
- 集成测试:TestContainers + MySQL容器
- API测试:Postman + Newman
- 压力测试:JMeter
7.2 部署方案
采用Docker容器化部署:
dockerfile复制FROM openjdk:11-jre
WORKDIR /app
COPY target/swimming-pool-management.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]
部署架构:
code复制Nginx (负载均衡)
↑
Docker Swarm集群
↑
MySQL主从集群
↑
Redis哨兵集群
8. 项目总结与反思
在开发这个系统的过程中,我积累了一些宝贵的经验:
-
并发控制:初期没有处理好高并发预约场景,导致出现超卖问题。后来通过乐观锁+Redis分布式锁解决了这个问题。
-
事务管理:复杂的业务逻辑需要仔细设计事务边界,避免长事务导致的性能问题。
-
缓存一致性:缓存与数据库的一致性是个挑战,最终采用"先更新数据库,再删除缓存"的策略。
-
接口设计:RESTful API设计要考虑到前端的使用便利性,不是机械地遵循规范。
这个系统目前已在某高校稳定运行半年,日均处理预约请求3000+,高峰时段QPS达到50。后续计划增加智能排课、人脸识别入场等高级功能。