文章目录
1.提交答题情况
1.PracticeDetailController.java
/**
* 提交题目,每一次点下一题,都会调用这个接口
*/
@PostMapping(value = "/submitSubject")
public Result<Boolean> submitSubject(@RequestBody SubmitSubjectDetailReq req) {
try {
if (log.isInfoEnabled()) {
log.info("练习提交题目入参{}", JSON.toJSONString(req));
}
Preconditions.checkArgument(!Objects.isNull(req), "参数不能为空!");
Preconditions.checkArgument(!Objects.isNull(req.getPracticeId()), "练习id不能为空!");
Preconditions.checkArgument(!Objects.isNull(req.getSubjectId()), "题目id不能为空!");
Preconditions.checkArgument(!Objects.isNull(req.getSubjectType()), "题目类型不能为空!");
Preconditions.checkArgument(!StringUtils.isBlank(req.getTimeUse()), "用时不能为空!");
Boolean result = practiceDetailService.submitSubject(req);
log.info("练习提交题目出参{}", result);
return Result.ok(result);
} catch (IllegalArgumentException e) {
log.error("参数异常!错误原因{}", e.getMessage(), e);
return Result.fail(e.getMessage());
} catch (Exception e) {
log.error("练习提交题目异常!错误原因{}", e.getMessage(), e);
return Result.fail("练习提交题目异常!");
}
}
2.PracticeDetailService.java
package com.sunxiansheng.practice.server.service;
import com.sunxiansheng.practice.api.req.SubmitSubjectDetailReq;
/**
* Description:
* @Author sun
* @Create 2024/7/8 12:28
* @Version 1.0
*/
public interface PracticeDetailService {
/**
* 练习提交题目
*/
Boolean submitSubject(SubmitSubjectDetailReq req);
}
3.PracticeDetailServiceImpl.java
package com.sunxiansheng.practice.server.service.impl;
import com.sunxiansheng.practice.api.enums.SubjectInfoTypeEnum;
import com.sunxiansheng.practice.api.req.SubmitSubjectDetailReq;
import com.sunxiansheng.practice.server.dao.*;
import com.sunxiansheng.practice.server.entity.dto.SubjectDTO;
import com.sunxiansheng.practice.server.entity.po.PracticeDetailPO;
import com.sunxiansheng.practice.server.entity.po.PracticePO;
import com.sunxiansheng.practice.server.entity.po.SubjectMultiplePO;
import com.sunxiansheng.practice.server.entity.po.SubjectRadioPO;
import com.sunxiansheng.practice.server.service.PracticeDetailService;
import com.sunxiansheng.practice.server.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
/**
* Description:
* @Author sun
* @Create 2024/6/25 17:08
* @Version 1.0
*/
@Service
@Slf4j
public class PracticeDetailServiceImpl implements PracticeDetailService {
@Resource
private PracticeDao practiceDao;
@Resource
private SubjectDao subjectDao;
@Resource
private SubjectRadioDao subjectRadioDao;
@Resource
private SubjectMultipleDao subjectMultipleDao;
@Resource
private PracticeDetailDao practiceDetailDao;
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean submitSubject(SubmitSubjectDetailReq req) {
// 获取req的信息
Long practiceId = req.getPracticeId();
Long subjectId = req.getSubjectId();
List<Integer> answerContents = req.getAnswerContents();
Integer subjectType = req.getSubjectType();
String timeUse = req.getTimeUse();
// ============================== 处理用时 ==============================
if (timeUse.equals("0")) {
timeUse = "000000";
}
String hour = timeUse.substring(0, 2);
String minute = timeUse.substring(2, 4);
String second = timeUse.substring(4, 6);
// ============================== 处理用时 ==============================
// ============================== 根据id更新时间 ==============================
PracticePO practicePO = new PracticePO();
practicePO.setId(practiceId);
practicePO.setTimeUse(hour + ":" + minute + ":" + second);
practicePO.setSubmitTime(new Date());
practiceDao.update(practicePO);
// ============================== 根据id更新时间 ==============================
// ============================== 给练习的细节插入一条记录 ==============================
PracticeDetailPO practiceDetailPO = new PracticeDetailPO();
// 基本信息填充
practiceDetailPO.setPracticeId(practiceId);
practiceDetailPO.setSubjectId(subjectId);
practiceDetailPO.setSubjectType(subjectType);
String loginId = LoginUtil.getLoginId();
practiceDetailPO.setCreatedBy(loginId);
practiceDetailPO.setCreatedTime(new Date());
practiceDetailPO.setIsDeleted(0);
// 修改答案数组,将答案变成1,2,3...这种格式的
String answerContent = getAnswerContent(answerContents);
practiceDetailPO.setAnswerContent(answerContent);
// 从数据库中获取正确答案,并判断答案是否正确
SubjectDTO subjectDTO = new SubjectDTO();
subjectDTO.setSubjectId(req.getSubjectId());
subjectDTO.setSubjectType(req.getSubjectType());
// 根据subjectId和subjectType来获取题目答案
// 初始化为0
Integer answerStatus = 0;
StringBuffer correctAnswer = new StringBuffer();
// 获得正确答案的字符串
extracted(subjectType, subjectId, correctAnswer);
// 如果答案正确,则答案的状态就会是1,否则是0
if (Objects.equals(correctAnswer.toString(), answerContent)) {
// practiceDetailPO.setAnswerStatus(1);
answerStatus = 1;
}
practiceDetailPO.setAnswerStatus(answerStatus);
// 到此练习的细节就构建完毕了
// 查询练习细节是否已经存在了,如果存在就更新,不存在就插入
PracticeDetailPO existDetail = practiceDetailDao.selectDetail(practiceId, subjectId, loginId);
if (Objects.isNull(existDetail)) {
practiceDetailDao.insertSingle(practiceDetailPO);
} else {
practiceDetailPO.setId(existDetail.getId());
practiceDetailDao.update(practiceDetailPO);
}
// ============================== 给练习的细节插入一条记录 ==============================
return true;
}
/**
* 根据题目id和类型,得到正确答案的字符串
* @param subjectType
* @param subjectId
* @param correctAnswer
*/
private void extracted(Integer subjectType, Long subjectId, StringBuffer correctAnswer) {
// 单选
if (subjectType == SubjectInfoTypeEnum.RADIO.getCode()) {
// 查询单选题目细节
List<SubjectRadioPO> subjectRadioPOS = subjectRadioDao.selectBySubjectId(subjectId);
// 得到对的那个的选项类型
subjectRadioPOS.forEach(
radio -> {
if (Objects.equals(radio.getIsCorrect(), 1)) {
correctAnswer.append(radio.getOptionType());
}
}
);
}
// 多选
if (subjectType == SubjectInfoTypeEnum.MULTIPLE.getCode()) {
// 查询多选题目细节
List<SubjectMultiplePO> subjectMultiplePOS = subjectMultipleDao.selectBySubjectId(subjectId);
// 得到所有的对的选项类型
subjectMultiplePOS.forEach(
multiple -> {
if (Objects.equals(multiple.getIsCorrect(), 1)) {
correctAnswer.append(multiple.getOptionType()).append(",");
}
}
);
// 去掉最后一个逗号
if (correctAnswer.length() > 0) {
correctAnswer.deleteCharAt(correctAnswer.length() - 1);
}
}
// 判断
if (subjectType == SubjectInfoTypeEnum.JUDGE.getCode()) {
// 查询判断题目细节
List<SubjectMultiplePO> subjectMultiplePOS = subjectMultipleDao.selectBySubjectId(subjectId);
// 判断题只能有一条细节,所以取第一个就可以
Integer isCorrect = subjectMultiplePOS.get(0).getIsCorrect();
correctAnswer.append(isCorrect);
}
}
/**
* 修改答案数组,将答案变成1,2,3...这种格式的
* @param answerContents
* @return
*/
private static String getAnswerContent(List<Integer> answerContents) {
String answerContent = "";
// 判空
if (!CollectionUtils.isEmpty(answerContents)) {
// 排序
Collections.sort(answerContents);
// 拼接
answerContent = StringUtils.join(answerContents, ",");
}
return answerContent;
}
}
4.PracticeDetailDao.java
/**
* 更新练习详情
*/
int update(PracticeDetailPO practiceDetailPO);
5.PracticeDetailDao.xml
<update id="update">
update practice_detail
<set>
<if test="answerStatus != null">
answer_status = #{answerStatus},
</if>
<if test="answerContent != null">
answer_content = #{answerContent},
</if>
</set>
where id = #{id,jdbcType=BIGINT}
</update>
6.req
SubmitSubjectDetailReq.java
package com.sunxiansheng.practice.api.req;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class SubmitSubjectDetailReq implements Serializable {
/**
* 练习id
*/
private Long practiceId;
/**
* 题目id
*/
private Long subjectId;
/**
* 题目答案
*/
private List<Integer> answerContents;
/**
* 题目类型
*/
private Integer subjectType;
/**
* 用时
*/
private String timeUse;
}
7.dto
1.SubjectDetailDTO.java
package com.sunxiansheng.practice.server.entity.dto;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class SubjectDetailDTO implements Serializable {
/**
* 题目id
*/
private Long id;
/**
* 题目名称
*/
private String subjectName;
/**
* 判断题答案
*/
private Integer isCorrect;
/**
* 题目解析
*/
private String subjectParse;
/**
* 单选、多选、判断题目答案
*/
private List<SubjectOptionDTO> optionList;
}
2.SubjectDTO.java
package com.sunxiansheng.practice.server.entity.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class SubjectDTO implements Serializable {
/**
* 题目id
*/
private Long id;
/**
* 题目id
*/
private Long subjectId;
/**
* 题目名称
*/
private String subjectName;
/**
* 题目类型
*/
private Integer subjectType;
}
3.SubjectOptionDTO.java
package com.sunxiansheng.practice.server.entity.dto;
import lombok.Data;
import java.io.Serializable;
@Data
public class SubjectOptionDTO implements Serializable {
/**
* 答案类型
*/
private Integer optionType;
/**
* 答案内容
*/
private String optionContent;
/**
* 是否为正确答案
*/
private Integer isCorrect;
}
8.测试
1.接口设计
2.db
1.更新提交时间和用时 practice_info
2.练习细节如果有的话就更新记录 practice_detail
3.测试遇到一个bug,即使题目正确也会插入答案状态为0,状态设置的时候有问题
2.答案解析-每题得分
1.GetScoreDetailReq.java
package com.sunxiansheng.practice.api.req;
import lombok.Data;
import java.io.Serializable;
@Data
public class GetScoreDetailReq implements Serializable {
/**
* 练习id
*/
private Long practiceId;
}
2.ScoreDetailVO.java
package com.sunxiansheng.practice.api.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class ScoreDetailVO implements Serializable {
/**
* 题目id
*/
private Long subjectId;
/**
* 题目类型
*/
private Integer subjectType;
/**
* 是否正确
*/
private Integer isCorrect;
}
3.PracticeDetailController.java
/**
* 答案解析-每题得分
*/
@PostMapping(value = "/getScoreDetail")
public Result<List<ScoreDetailVO>> getScoreDetail(@RequestBody GetScoreDetailReq req) {
try {
if (log.isInfoEnabled()) {
log.info("每题得分入参{}", JSON.toJSONString(req));
}
Preconditions.checkArgument(!Objects.isNull(req), "参数不能为空!");
Preconditions.checkArgument(!Objects.isNull(req.getPracticeId()), "练习id不能为空!");
List<ScoreDetailVO> list = practiceDetailService.getScoreDetail(req);
if (log.isInfoEnabled()) {
log.info("每题得分出参{}", JSON.toJSONString(list));
}
return Result.ok(list);
} catch (IllegalArgumentException e) {
log.error("参数异常!错误原因{}", e.getMessage(), e);
return Result.fail(e.getMessage());
} catch (Exception e) {
log.error("每题得分异常!错误原因{}", e.getMessage(), e);
return Result.fail("每题得分异常!");
}
}
4.PracticeDetailService.java
/**
* 每题得分详情
*/
List<ScoreDetailVO> getScoreDetail(GetScoreDetailReq req);
5.PracticeDetailServiceImpl.java
@Override
public List<ScoreDetailVO> getScoreDetail(GetScoreDetailReq req) {
// 获取练习id
Long practiceId = req.getPracticeId();
// 根据练习id查询题目id,题目类型,题目状态
List<PracticeDetailPO> practiceDetailPOList = practiceDetailDao.selectByPracticeId(practiceId);
// 判空
if (CollectionUtils.isEmpty(practiceDetailPOList)) {
return Collections.emptyList();
}
// 将其map成要返回的结果
List<ScoreDetailVO> res = practiceDetailPOList.stream().map(
po -> {
// 将每一个practiceDetailPO都map成ScoreDetailVO
ScoreDetailVO scoreDetailVO = new ScoreDetailVO();
scoreDetailVO.setSubjectId(po.getSubjectId());
scoreDetailVO.setSubjectType(po.getSubjectType());
scoreDetailVO.setIsCorrect(po.getAnswerStatus());
return scoreDetailVO;
}
).collect(Collectors.toList());
return res;
}
6.PracticeDetailDao.xml
<select id="selectByPracticeId" resultType="com.sunxiansheng.practice.server.entity.po.PracticeDetailPO">
select subject_id as subjectId, subject_type as subjectType, answer_status as answerStatus
from practice_detail
where practice_id = #{practiceId}
and is_deleted = 0
</select>