答题情况和每题得分

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.接口设计

CleanShot 2024-07-08 at 15.57.58@2x

2.db
1.更新提交时间和用时 practice_info

CleanShot 2024-07-08 at 15.59.47@2x

2.练习细节如果有的话就更新记录 practice_detail

CleanShot 2024-07-08 at 16.01.05@2x

3.测试遇到一个bug,即使题目正确也会插入答案状态为0,状态设置的时候有问题

CleanShot 2024-07-08 at 16.02.44@2x

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>
7.测试

CleanShot 2024-07-09 at 12.37.41@2x

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

S-X-S

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值