public wxw_exam_record submitExam(Integer examineeId, Map<Integer, String> answers) { List<exam_question> allQuestions = exam_questionMapper.selectAll(); double totalScore = 0; // List<AnswerDetail> details = new ArrayList<>(); for (exam_question q : allQuestions) { String userAnswer = answers.get(q.getId()); boolean isCorrect = checkAnswer(q, userAnswer); if (isCorrect) totalScore += q.getScore(); // details.add(new AnswerDetail(null, q.getId(), userAnswer, isCorrect)); } wxw_exam_record record = new wxw_exam_record(); System.out.println(examineeId); record.setExamineeId(examineeId.toString()); record.setTotal_score(totalScore); //初始化时间 LocalDateTime now = LocalDateTime.now(); DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss"); String format = now.format(dateTimeFormatter); record.setExam_time(format); wxwExamRecordMapper.insert(record); // 插入主记录 // details.forEach(d -> d.setExamId(record.getId())); // 设置外键 // answerDetailMapper.batchInsert(details); // 批量插入答题明细 return record; } /** * 校验答题的逻辑 * @param q * @param userAnswer * @return */ private boolean checkAnswer(exam_question q, String userAnswer) { // 将正确答案拆分为集合(适用于多选题) Set<String> correct = new HashSet<>(Arrays.asList(q.getCorrect_answer().split(","))); // 处理用户答案为空的情况 Set<String> user = userAnswer == null ? new HashSet<>() : new HashSet<>(Arrays.asList(userAnswer.split(","))); return correct.equals(user); // 集合比对忽略顺序差异 }前端输入了正确的答案,还是0分,前端的参数{examineeId: 10009, answers: {1: "B", 2: "B", 3: "B"}},数据库题目{"A": "1", "B": "2", "C": "3", "D": "5"},答案{"B": "2"},为什么,你帮我重构一下业务层
时间: 2025-07-06 18:43:55 浏览: 4
<think>好的,我现在需要解决用户的问题:前端提交了正确的答案,但得分仍然是0分。用户提供的代码中,业务层的submitExam方法可能存在逻辑错误。我需要仔细分析代码,找出问题所在,并重构业务层。
首先,用户提到前端传入的参数是{examineeId: 10009, answers: {1: "B", 2: "B", 3: "B"}},而数据库中的题目答案存储为{"B": "2"}。这可能意味着题目的正确答案在数据库中以某种键值对的形式保存,但代码中的处理方式可能不正确。
查看submitExam方法,发现主要逻辑是遍历所有题目,检查用户的答案是否正确,累加分数。关键点在于checkAnswer方法是否正确处理了正确答案和用户答案的比较。
在checkAnswer方法中,代码将正确答案q.getCorrect_answer()按逗号分割成集合,用户答案同样处理。然后比较两个集合是否相等。例如,如果正确答案是"B",而用户答案也是"B",那么correct集合是["B"],user集合也是["B"],这时候应该返回true,分数累加。但实际情况中用户得分却是0,说明这里的比较可能存在问题。
接下来,需要检查数据库中的正确答案存储结构。用户提到题目中的答案字段是{"B": "2"},这可能表示正确答案的存储方式有问题。比如,可能原本应该存储"B"作为正确答案,但实际存储的是JSON对象,导致代码在分割时得到的correct集合不正确。例如,如果q.getCorrect_answer()返回的是字符串"{\"B\": \"2\"}",那么split(",")会得到["{\"B\"", "\"2\"}"],这样的集合显然无法与用户答案的["B"]匹配,导致isCorrect为false。
这说明问题可能出在正确答案的存储格式上。代码期望正确答案是用逗号分隔的选项列表,如"B,C",但实际存储的是JSON字符串,无法正确分割。因此,需要调整正确答案的存储方式,或者修改checkAnswer方法来正确解析正确答案。
假设数据库中的正确答案应该直接存储选项字母,如"B",而不是JSON对象,那么需要修正数据。或者,如果确实需要存储JSON,那么应该在checkAnswer方法中解析JSON,提取出正确的选项字母。
此外,还需要检查前端传入的answers参数是否正确。例如,题号是否与数据库中的题目ID匹配,用户答案是否正确地传递到后端。
重构业务层时,首先需要确保正确答案的存储格式正确。如果正确答案应该是选项字母,如"B",则修改数据库中的值。如果必须使用JSON格式存储,则需要在checkAnswer方法中解析JSON,提取出正确的选项。
另外,检查checkAnswer方法中的分割逻辑是否正确处理了空值和格式错误的情况。例如,当用户答案为空时,是否正确处理为空的集合,避免空指针异常。
可能还需要添加日志输出,记录正确答案和用户答案的具体内容,以便调试和验证比较过程是否正确。
总结问题原因:正确答案存储格式错误,导致分割后的集合与用户答案不匹配,从而所有题目都被判定为错误,总分为0。
重构步骤包括:
1. 修正数据库中的正确答案存储格式,确保是逗号分隔的选项字母。
2. 修改checkAnswer方法,正确处理正确答案的解析,或者调整存储方式。
3. 添加日志输出,帮助调试和验证数据。
4. 确保题号ID和答案的映射正确,避免ID不匹配导致答案未被正确获取。</think>以下是问题分析和解决方案的分步说明:
---
### 一、问题定位
1. **数据库存储格式错误**
题目正确答案字段存储为JSON格式(例:`{"B": "2"}`),但代码中按逗号分割处理,导致实际获取的正确答案集合为 `["{\"B\"", "\"2\"}"]`
2. **答案比对逻辑失效**
比较时用户答案为 `["B"]`,而正确答案集合包含非法字符,导致永远返回 `false`
---
### 二、解决方案
#### 步骤1:修正数据库存储格式
将正确答案字段改为**直接存储选项字母**(无需JSON):
```sql
-- 示例题目数据更新
UPDATE exam_question SET correct_answer = 'B' WHERE id = 1;
```
#### 步骤2:重构业务层代码
```java
public wxw_exam_record submitExam(Integer examineeId, Map<Integer, String> answers) {
List<exam_question> allQuestions = exam_questionMapper.selectAll();
double totalScore = 0;
for (exam_question q : allQuestions) {
Integer questionId = q.getId();
String userAnswer = answers.get(questionId);
boolean isCorrect = checkAnswer(q, userAnswer);
// 添加调试日志(生产环境需删除)
System.out.printf("题目ID:%d 正确答案:%s 用户答案:%s 是否正确:%s%n",
questionId, q.getCorrect_answer(), userAnswer, isCorrect);
if (isCorrect) totalScore += q.getScore();
}
// 后续记录存储逻辑保持不变...
}
private boolean checkAnswer(exam_question q, String userAnswer) {
// 处理空值
if (StringUtils.isBlank(userAnswer)) return false;
// 直接获取正确答案(不再拆分)
String correctAnswer = q.getCorrect_answer().trim();
String processedUserAnswer = userAnswer.trim();
// 大小写敏感处理(按需调整)
return correctAnswer.equalsIgnoreCase(processedUserAnswer);
}
```
---
### 三、关键改进点
1. **正确答案存储**
直接存储选项字母(如 `B`),而非JSON格式
2. **简化校验逻辑**
直接比对字符串而非集合,适用于单选场景
3. **健壮性增强**
- 增加空值处理
- 添加trim()去除空格
- 可选大小写不敏感比对
---
### 四、多选题型适配方案
若需支持多选题,调整如下:
```java
// 多选校验逻辑
private boolean checkAnswer(exam_question q, String userAnswer) {
// 处理空答案
if (userAnswer == null) userAnswer = "";
// 拆分并排序确保顺序无关
String[] correctParts = q.getCorrect_answer().split(",");
String[] userParts = userAnswer.split(",");
Arrays.sort(correctParts);
Arrays.sort(userParts);
return Arrays.equals(correctParts, userParts);
}
```
---
### 五、验证建议
1. **数据库检查**
确认 `correct_answer` 字段值为纯选项字母(如 `B` 或 `A,C`)
2. **日志验证**
通过控制台输出确认比对过程:
```
题目ID:1 正确答案:B 用户答案:B 是否正确:true
```
3. **单元测试**
编写测试用例覆盖边界情况:
```java
@Test
void testCheckAnswer() {
exam_question q = new exam_question();
q.setCorrect_answer("B");
assertTrue(checkAnswer(q, "B")); // 正确
assertFalse(checkAnswer(q, "A")); // 错误
}
```
阅读全文
相关推荐















