答题状况及每题得分详解

文章目录

  • 1.提交答题情况
  • 1.PracticeDetailController.java
  • 2.PracticeDetailService.java
  • 3.PracticeDetailServiceImpl.java
  • 4.PracticeDetailDao.java
  • 5.PracticeDetailDao.xml
  • 6.req
  • SubmitSubjectDetailReq.java
  • 7.dto
  • 1.SubjectDetailDTO.java
  • 2.SubjectDTO.java
  • 3.SubjectOptionDTO.java
  • 8.测试
  • 1.接口设计
  • 2.db
  • 1.更新提交时间和用时 practice_info
  • 2.练习细节如果有的话就更新记录 practice_detail
  • 3.测试遇到一个bug,即使题目正确也会插入答案状态为0,状态设置的时候有问题
  • 2.答案解析-每题得分
  • 1.GetScoreDetailReq.java
  • 2.ScoreDetailVO.java
  • 3.PracticeDetailController.java
  • 4.PracticeDetailService.java
  • 5.PracticeDetailServiceImpl.java
  • 6.PracticeDetailDao.xml
  • 7.测试
  • 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

    作者:S-X-S

    物联沃分享整理
    物联沃-IOTWORD物联网 » 答题状况及每题得分详解

    发表回复