高校体育场管理系统是一款基于Java后端和微信小程序前端开发的校园信息化解决方案。作为一名长期从事校园信息化建设的开发者,我发现传统体育场管理普遍存在预约效率低、信息不透明、管理成本高等痛点。这个系统正是为了解决这些问题而设计的。
系统采用B/S架构,后端使用Spring Boot框架,前端采用微信小程序技术栈。主要功能包括体育场预约、订单管理、用户评价和论坛交流等模块。系统设计了三种用户角色:管理员负责基础数据维护,学生和普通用户可以通过小程序便捷预约场地。
提示:系统设计时特别考虑了高校场景的特殊性,比如学生群体的使用习惯、体育场资源的稀缺性等因素。
后端选择Java+Spring Boot组合主要基于以下考虑:
前端采用微信小程序是因为:
数据库选用MySQL 8.0,主要看中其:
系统主要分为以下几个功能模块:
| 模块名称 | 功能说明 | 技术实现 |
|---|---|---|
| 用户管理 | 处理用户注册、登录、信息维护 | Spring Security + JWT |
| 场地管理 | 体育场信息CRUD操作 | MyBatis + MySQL |
| 预约系统 | 处理预约请求和冲突检测 | Redis + 自定义算法 |
| 支付模块 | 处理订单支付 | 微信支付API |
| 评价系统 | 用户反馈收集和展示 | MySQL全文索引 |
| 论坛模块 | 用户交流互动 | WebSocket |
体育场预约的核心难点是时间冲突检测。我们设计了基于时间片的检测机制:
java复制public boolean checkTimeConflict(Reservation newRes) {
// 获取该场地所有已预约记录
List<Reservation> existing = reservationMapper.findByFieldId(newRes.getFieldId());
// 将时间转换为分钟数便于比较
int newStart = newRes.getStartTime().getHour() * 60 + newRes.getStartTime().getMinute();
int newEnd = newStart + newRes.getDuration();
for (Reservation exist : existing) {
int existStart = exist.getStartTime().getHour() * 60 + exist.getStartTime().getMinute();
int existEnd = existStart + exist.getDuration();
// 检测时间重叠
if (!(newEnd <= existStart || newStart >= existEnd)) {
return true; // 存在冲突
}
}
return false; // 无冲突
}
注意:实际项目中我们还考虑了日期过滤、取消预约等边界情况,这里做了简化展示。
支付模块采用微信小程序原生支付方案:
java复制public Map<String, String> createPrepayOrder(Order order) throws Exception {
WXPay wxpay = new WXPay(config);
Map<String, String> data = new HashMap<>();
data.put("body", "体育场预约-" + order.getFieldName());
data.put("out_trade_no", order.getOrderNo());
data.put("total_fee", String.valueOf(order.getFee()));
data.put("spbill_create_ip", "123.12.12.123");
data.put("notify_url", "https://yourdomain.com/api/pay/notify");
data.put("trade_type", "JSAPI");
data.put("openid", order.getOpenId());
Map<String, String> resp = wxpay.unifiedOrder(data);
if ("SUCCESS".equals(resp.get("return_code"))) {
return buildPayParams(resp);
}
throw new RuntimeException("支付创建失败");
}
javascript复制wx.requestPayment({
timeStamp: res.timeStamp,
nonceStr: res.nonceStr,
package: res.packageValue,
signType: 'MD5',
paySign: res.paySign,
success(res) {
console.log('支付成功', res)
},
fail(err) {
console.error('支付失败', err)
}
})
体育场表(field_info)
sql复制CREATE TABLE `field_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`field_no` varchar(20) NOT NULL COMMENT '场地编号',
`name` varchar(50) NOT NULL COMMENT '场地名称',
`area` decimal(10,2) DEFAULT NULL COMMENT '面积(m²)',
`capacity` int(11) DEFAULT NULL COMMENT '容纳人数',
`fee` decimal(10,2) DEFAULT NULL COMMENT '费用/小时',
`status` tinyint(4) DEFAULT '1' COMMENT '1-可用 0-维护中',
`cover_img` varchar(255) DEFAULT NULL COMMENT '封面图URL',
`description` text COMMENT '场地描述',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_field_no` (`field_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
预约订单表(reservation_order)
sql复制CREATE TABLE `reservation_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`order_no` varchar(32) NOT NULL COMMENT '订单编号',
`field_id` int(11) NOT NULL COMMENT '场地ID',
`field_no` varchar(20) NOT NULL COMMENT '场地编号',
`field_name` varchar(50) NOT NULL COMMENT '场地名称',
`user_type` tinyint(4) NOT NULL COMMENT '1-学生 2-教职工',
`user_id` int(11) NOT NULL COMMENT '用户ID',
`user_name` varchar(50) NOT NULL COMMENT '用户姓名',
`contact_phone` varchar(20) NOT NULL COMMENT '联系电话',
`reserve_date` date NOT NULL COMMENT '预约日期',
`start_time` time NOT NULL COMMENT '开始时间',
`duration` int(11) NOT NULL COMMENT '持续时间(分钟)',
`total_fee` decimal(10,2) NOT NULL COMMENT '总费用',
`pay_status` tinyint(4) DEFAULT '0' COMMENT '0-未支付 1-已支付 2-已退款',
`status` tinyint(4) DEFAULT '1' COMMENT '1-有效 0-已取消',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_order_no` (`order_no`),
KEY `idx_field_date` (`field_id`,`reserve_date`),
KEY `idx_user` (`user_id`,`user_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
建议的最低配置:
推荐使用Docker Compose部署,下面是docker-compose.yml示例:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourstrongpassword
MYSQL_DATABASE: sports_db
volumes:
- ./mysql_data:/var/lib/mysql
ports:
- "3306:3306"
restart: always
redis:
image: redis:6
ports:
- "6379:6379"
restart: always
app:
build: .
depends_on:
- mysql
- redis
ports:
- "8080:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/sports_db
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: yourstrongpassword
SPRING_REDIS_HOST: redis
restart: always
缓存策略:
数据库优化:
ANALYZE TABLE更新统计信息前端优化:
问题现象:多个用户同时预约同一时间段时出现超订。
解决方案:
java复制@Transactional
public boolean makeReservation(ReservationDTO dto) {
// 检查场地版本号
Field field = fieldMapper.selectForUpdate(dto.getFieldId());
if (field.getVersion() != dto.getFieldVersion()) {
throw new OptimisticLockException("场地信息已变更");
}
// 执行预约逻辑
// ...
// 更新版本号
fieldMapper.updateVersion(dto.getFieldId(), field.getVersion());
}
java复制public boolean tryReserveWithLock(ReservationDTO dto) {
String lockKey = "reserve_lock:" + dto.getFieldId();
String requestId = UUID.randomUUID().toString();
try {
// 尝试获取锁
boolean locked = redisTemplate.opsForValue().setIfAbsent(
lockKey, requestId, 30, TimeUnit.SECONDS);
if (!locked) {
return false;
}
// 执行业务逻辑
return doReserve(dto);
} finally {
// 释放锁
if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
典型错误:获取openid失败或session_key无效。
排查步骤:
代码示例(处理微信登录):
java复制public WxSession getWxSession(String code) throws WxErrorException {
WxMaService wxService = WxMaConfiguration.getWxMaService();
// 获取session信息
WxMaJscode2SessionResult session = wxService.getUserService()
.getSessionInfo(code);
// 验证获取结果
if (session == null || StringUtils.isBlank(session.getOpenid())) {
throw new WxErrorException(WxError.builder().errorMsg("微信登录失败").build());
}
return new WxSession(
session.getOpenid(),
session.getSessionKey(),
session.getUnionid()
);
}
在实际部署使用过程中,可以考虑以下几个扩展方向:
智能推荐系统:
物联网集成:
数据分析平台:
移动端管理:
我在实际开发中发现,系统的可扩展性设计非常重要。特别是在高校环境中,经常需要根据实际使用情况调整功能模块。建议在架构设计时预留好接口,采用微服务架构可以更好地应对未来的需求变化。