6.2 KiB
6.2 KiB
赛程编排API冲突修复说明
问题描述
在实现赛程编排后端API时,发现项目中已经存在 MartialScheduleArrangeController 控制器,该控制器已经定义了相同的路径:
GET /martial/schedule/resultPOST /martial/schedule/save-and-lock
这导致Spring Boot启动时报错:
Ambiguous mapping. Cannot map 'martialScheduleController' method to {POST [/martial/schedule/save-and-lock]}:
There is already 'martialScheduleArrangeController' bean method mapped.
解决方案
1. 删除重复的控制器端点
从新创建的 MartialScheduleController 中删除了冲突的3个端点:
/result/save-draft/save-and-lock
保留原有的基础CRUD端点(detail, list, submit, remove)。
2. 更新现有控制器
修改 MartialScheduleArrangeController,使其使用新创建的Service和DTO:
文件: MartialScheduleArrangeController.java
2.1 添加依赖注入
private final IMartialScheduleArrangeService scheduleArrangeService;
private final IMartialScheduleService scheduleService; // 新增
2.2 更新 GET /result 端点
修改前:
public R<Map<String, Object>> getScheduleResult(@RequestParam Long competitionId) {
Map<String, Object> result = scheduleArrangeService.getScheduleResult(competitionId);
return R.data(result);
}
修改后:
public R<ScheduleResultDTO> getScheduleResult(@RequestParam Long competitionId) {
ScheduleResultDTO result = scheduleService.getScheduleResult(competitionId);
return R.data(result);
}
改进:
- 使用结构化的DTO替代Map
- 返回类型更加明确
- 符合前端API规范
2.3 新增 POST /save-draft 端点
@PostMapping("/save-draft")
@Operation(summary = "保存编排草稿", description = "传入编排草稿数据")
public R saveDraftSchedule(@RequestBody SaveScheduleDraftDTO dto) {
try {
boolean success = scheduleService.saveDraftSchedule(dto);
return success ? R.success("草稿保存成功") : R.fail("草稿保存失败");
} catch (Exception e) {
log.error("保存编排草稿失败", e);
return R.fail("保存编排草稿失败: " + e.getMessage());
}
}
2.4 更新 POST /save-and-lock 端点
修改前:
public R saveAndLock(@RequestBody Map<String, Object> params) {
Long competitionId = Long.valueOf(String.valueOf(params.get("competitionId")));
scheduleArrangeService.saveAndLock(competitionId, userId);
return R.success("编排已保存并锁定");
}
修改后:
public R saveAndLock(@RequestBody SaveScheduleDraftDTO dto) {
BladeUser user = AuthUtil.getUser();
String userId = user != null ? user.getUserName() : "system";
boolean success = scheduleService.saveAndLockSchedule(dto.getCompetitionId());
if (success) {
// 调用原有的锁定逻辑
scheduleArrangeService.saveAndLock(dto.getCompetitionId(), userId);
return R.success("编排已完成并锁定");
} else {
return R.fail("编排锁定失败");
}
}
改进:
- 使用DTO替代Map,类型安全
- 结合新旧两个Service的功能
- 先更新参赛者状态,再执行原有的锁定逻辑
最终API结构
MartialScheduleArrangeController
基础路径: /martial/schedule
| 方法 | 路径 | 功能 | 请求类型 | 响应类型 |
|---|---|---|---|---|
| GET | /result |
获取编排结果 | competitionId | ScheduleResultDTO |
| POST | /save-draft |
保存编排草稿 | SaveScheduleDraftDTO | R |
| POST | /save-and-lock |
完成编排并锁定 | SaveScheduleDraftDTO | R |
| POST | /auto-arrange |
手动触发自动编排 | Map | R |
MartialScheduleController
基础路径: /martial/schedule
| 方法 | 路径 | 功能 | 请求类型 | 响应类型 |
|---|---|---|---|---|
| GET | /detail |
获取详情 | id | MartialSchedule |
| GET | /list |
分页列表 | MartialSchedule, Query | IPage |
| POST | /submit |
新增或修改 | MartialSchedule | R |
| POST | /remove |
删除 | ids | R |
字段冲突修复
问题
实体类 MartialScheduleParticipant 的 status 字段与基础类 TenantEntity 冲突。
解决方案
将 status 字段重命名为 checkInStatus(签到状态):
文件: MartialScheduleParticipant.java:86-90
/**
* 签到状态:未签到/已签到/异常
*/
@Schema(description = "签到状态:未签到/已签到/异常")
private String checkInStatus;
相应更新
Service层 (MartialScheduleServiceImpl.java):
- 读取时:
dto.setStatus(p.getCheckInStatus() != null ? p.getCheckInStatus() : "未签到");
- 保存时:
participant.setCheckInStatus(participantDTO.getStatus());
前端仍然使用 status 字段,在Service层进行映射转换。
数据库字段名建议
ALTER TABLE martial_schedule_participant
ADD COLUMN check_in_status VARCHAR(20) DEFAULT '未签到' COMMENT '签到状态:未签到/已签到/异常',
ADD COLUMN schedule_status VARCHAR(20) DEFAULT 'draft' COMMENT '编排状态:draft/completed';
前后端对接
前端API配置无需修改,仍然使用原有路径:
// 获取赛程编排结果
GET /api/martial/schedule/result
// 保存编排草稿
POST /api/martial/schedule/save-draft
// 完成编排并锁定
POST /api/martial/schedule/save-and-lock
所有端点都通过 MartialScheduleArrangeController 处理。
总结
通过以下措施解决了API冲突问题:
- ✅ 删除重复的控制器端点
- ✅ 更新现有控制器使用新的DTO和Service
- ✅ 修复字段名冲突
- ✅ 保持前端API路径不变
- ✅ 结合新旧Service功能,确保业务逻辑完整
现在系统可以正常启动,API端点清晰明确,没有冲突。