/***********************************************************
 * @Description : 考试服务
 * @author      : 梁山广(Laing Shan Guang)
 * @date        : 2019-05-28 08:04
 * @email       : liangshanguang2@gmail.com
 ***********************************************************/
package lsgwr.exam.controller;
// 导入考试相关的实体类，用于在控制器中处理和传递对应的业务数据，比如考试信息、考试记录信息等
import lsgwr.exam.entity.Exam;
import lsgwr.exam.entity.ExamRecord;
// 导入考试业务逻辑层的服务类，通过它可以调用具体的业务方法来实现诸如获取考试数据、更新考试等操作
import lsgwr.exam.service.ExamService;
// 导入Swagger相关注解，用于生成API文档，Api注解用于给一组API接口定义一个标签，方便文档中分类展示
import io.swagger.annotations.Api;
// ApiOperation注解用于描述单个API接口的具体功能，在API文档中展示接口的详细说明
import io.swagger.annotations.ApiOperation;
// 导入所有视图对象（VO），视图对象通常是用于在不同层之间传递数据的载体，会根据前端展示需求对实体数据进行适当封装和整理
import lsgwr.exam.vo.*;
// 导入Spring框架提供的Bean属性拷贝工具类，方便在不同的Java对象之间进行属性值的复制操作
import org.springframework.beans.BeanUtils;
// 导入Spring框架的依赖注入注解，用于自动装配相关的Bean实例到类的成员变量中
import org.springframework.beans.factory.annotation.Autowired;
// 导入Spring Web中用于处理HTTP请求的各种注解，例如定义请求方法、请求路径、路径变量、请求体等相关的注解
import org.springframework.web.bind.annotation.*;
// 导入Java中处理HTTP请求的类，在这个控制器中可以通过它获取请求相关的信息，比如请求头中的用户标识等信息
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
// @RestController注解表明这个类是一个Spring RESTful风格的Web控制器，它结合了@Controller和@ResponseBody注解的功能，意味着该类中处理请求的方法默认会将返回值直接转换为JSON等格式响应给客户端
@RestController
// @Api注解为Swagger文档定义标签，这里将这个控制器下的所有API接口归为"Exam APIs"这一组，便于在Swagger生成的API文档里进行分类查看和管理
@Api(tags = "Exam APIs")
// @RequestMapping注解用于定义该控制器中所有接口的基础请求路径，即这个控制器下所有接口的请求URL都将以 "/api/exam" 开头
@RequestMapping("/api/exam")
public class ExamController {
    // 使用@Autowired注解进行依赖注入，让Spring容器自动将ExamService的实例注入到这个成员变量中，方便后续在控制器的方法里调用其业务方法
    @Autowired
    private ExamService examService;// 自动注入 ExamService 服务
    /**
     * 此方法用于获取所有问题的列表。
     * 它通过HTTP的GET请求方式被访问，对应的请求路径是 "/api/exam/question/all"，会调用服务层方法获取数据并根据执行情况返回相应结果给客户端。
     */
    @GetMapping("/question/all")
    @ApiOperation("获取所有问题的列表")
    ResultVO<List<QuestionVo>> getQuestionAll() {
        // 定义一个ResultVO类型的变量，用于存放最终要返回给客户端的结果对象，其泛型参数指定为List<QuestionVo>，表示包含问题列表数据的结果封装
        ResultVO<List<QuestionVo>> resultVO;
        try {
            // 调用ExamService的getQuestionAll方法，该方法应该在服务层实现从数据库或者其他数据源获取所有问题数据的逻辑，返回一个QuestionVo类型的列表，代表所有问题信息
            List<QuestionVo> questionAll = examService.getQuestionAll();
            // 如果获取数据成功，创建一个表示成功的ResultVO对象，其中状态码设置为0，表示操作成功，消息设置为"获取全部问题列表成功"，并将获取到的问题列表数据放入ResultVO对象中
            resultVO = new ResultVO<>(0, "获取全部问题列表成功", questionAll);
        } catch (Exception e) {
            // 如果在获取数据过程中出现异常，打印异常堆栈信息，方便后续排查问题，通常在开发和调试阶段查看具体出错原因
            e.printStackTrace();
            // 创建一个表示失败的ResultVO对象，状态码设置为 -1，表示操作失败，消息设置为"获取全部问题列表失败"，数据部分设置为null，因为没有成功获取到问题列表数据
            resultVO = new ResultVO<>(-1, "获取全部问题列表失败", null);// 返回失败结果
        }
        return resultVO;
    }
    /**
     * 这个方法用于更新指定的问题。
     * 它接收一个HTTP的POST请求，请求路径为 "/api/exam/question/update"，客户端需要在请求体中传递要更新的问题信息（QuestionVo对象），然后调用服务层方法来更新问题，并根据执行结果返回相应信息给客户端。
     */
    @PostMapping("/question/update")
    @ApiOperation("更新问题")
    ResultVO<QuestionVo> questionUpdate(@RequestBody QuestionVo questionVo) {
        // 打印接收到的要更新的问题对象信息，在开发调试阶段可以通过查看控制台输出来确认前端传递过来的数据是否符合预期，方便排查问题
        System.out.println(questionVo);// 打印接收到的问题信息以供调试
        try {
            // 调用ExamService的updateQuestion方法，将接收到的要更新的问题对象（questionVo）传递进去，由服务层实现具体的更新逻辑，比如更新数据库中对应的问题记录等操作，返回更新后的问题对象
            QuestionVo questionVoResult = examService.updateQuestion(questionVo);
            // 如果更新成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示更新操作成功，消息设置为"更新问题成功"，并将更新后的问题对象放入ResultVO对象中返回给客户端
            return new ResultVO<>(0, "更新问题成功", questionVoResult);
        } catch (Exception e) {
            // 如果在更新过程中出现异常，打印异常堆栈信息，便于查找问题所在
            e.printStackTrace();
            // 创建一个表示更新失败的ResultVO对象，状态码设置为 -1，表示更新操作失败，消息设置为"更新问题失败"，数据部分设置为null，因为没有成功完成更新操作
            return new ResultVO<>(-1, "更新问题失败", null);
        }
    }
    /**
     * 该方法用于创建新问题。
     * 接收一个HTTP的POST请求，请求路径为 "/api/exam/question/create"，客户端需要在请求体中传递简化的创建问题信息（QuestionCreateSimplifyVo对象）以及通过HttpServletRequest获取相关的请求上下文信息，然后完成新问题的创建并返回相应结果给客户端。
     */
    @PostMapping("/question/create")
    @ApiOperation("创建问题")
    ResultVO<String> questionCreate(@RequestBody QuestionCreateSimplifyVo questionCreateSimplifyVo, HttpServletRequest request) {
        // 创建一个QuestionCreateVo对象，用于组装完整的创建问题所需的数据，可能QuestionCreateSimplifyVo只是包含了部分必要信息，需要进一步完善才能用于创建操作
        QuestionCreateVo questionCreateVo = new QuestionCreateVo();
        // 使用Spring的BeanUtils工具类，将questionCreateSimplifyVo对象中的属性值拷贝到questionCreateVo对象中，这样可以方便地复用已有的部分数据，避免重复设置属性
        BeanUtils.copyProperties(questionCreateSimplifyVo, questionCreateVo);// 拷贝属性到新的对象
        // 从HttpServletRequest对象中获取用户ID信息，通常这个用户ID是在请求处理的前置环节（比如拦截器中）设置到请求属性中的，用于标识创建这个问题的用户是谁
        String userId = (String) request.getAttribute("user_id");// 从请求中获取用户ID
        // 将获取到的用户ID设置到questionCreateVo对象中，作为问题创建者的标识，以便在后续保存问题数据到数据库等操作中记录创建者信息
        questionCreateVo.setQuestionCreatorId(userId);
        System.out.println(questionCreateVo);
        try {
            // 调用ExamService的questionCreate方法，将组装好的questionCreateVo对象传递进去，由服务层实现将新问题数据保存到数据库等具体的创建逻辑操作
            examService.questionCreate(questionCreateVo);
            // 如果创建成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示创建操作成功，消息设置为"问题创建成功"，这里数据部分设置为null，具体根据业务需求而定，可能创建成功不需要返回具体的数据内容
            return new ResultVO<>(0, "问题创建成功", null);// 返回成功结果
        } catch (Exception e) {
            // 如果在创建过程中出现异常，打印异常堆栈信息，方便排查问题原因
            e.printStackTrace();
            // 创建一个表示创建失败的ResultVO对象，状态码设置为 -1，表示创建操作失败，消息设置为"创建问题失败"，数据部分设置为null
            return new ResultVO<>(-1, "创建问题失败", null);
        }
    }
    /**
     * 此方法用于获取问题分类的相关选项。
     * 通过HTTP的GET请求方式访问，请求路径为 "/api/exam/question/selection"，会调用服务层方法获取选项信息，并根据获取结果返回相应信息给客户端，若获取到数据则表示成功，否则表示失败。
     */
    @GetMapping("/question/selection")
    @ApiOperation("获取问题分类的相关选项")
    ResultVO<QuestionSelectionVo> getSelections() {
        // 调用ExamService的getSelections方法，该方法在服务层应该实现从数据库或者其他数据源获取问题分类相关选项数据的逻辑，返回一个QuestionSelectionVo对象代表分类选项信息
        QuestionSelectionVo questionSelectionVo = examService.getSelections();
        if (questionSelectionVo != null) {
            // 如果获取到的问题分类选项对象不为空，说明获取操作成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取成功，消息设置为"获取问题分类选项成功"，并将获取到的分类选项对象放入ResultVO对象中返回给客户端
            return new ResultVO<>(0, "获取问题分类选项成功", questionSelectionVo);
        } else {
            // 如果获取到的问题分类选项对象为空，说明获取操作失败，创建一个表示失败的ResultVO对象，状态码设置为 -1，表示获取失败，消息设置为"获取问题分类选项失败"，数据部分设置为null
            return new ResultVO<>(-1, "获取问题分类选项失败", null);// 分类选项为空时返回失败信息
        }
    }
    /**
     * 这个方法根据问题的ID获取具体题目详情。
     * 接收一个HTTP的GET请求，请求路径中包含问题的ID（格式如 "/api/exam/question/detail/{id}"，{id}是路径变量），通过传入的问题ID调用服务层方法获取题目详细信息，并返回相应结果给客户端。
     */
    @GetMapping("/question/detail/{id}")
    @ApiOperation("根据问题的id获取问题的详细信息")
    ResultVO<QuestionDetailVo> getQuestionDetail(@PathVariable String id) {
        // 打印出请求的问题ID信息，在开发调试阶段可以通过查看控制台输出来确认请求的参数是否正确传递过来，方便排查问题以及记录请求日志
        System.out.println(id);
        ResultVO<QuestionDetailVo> resultVO;
        try {
            // 调用ExamService的getQuestionDetail方法，将接收到的问题ID传递进去，由服务层实现从数据库或者其他数据源根据ID查询对应问题详细信息的逻辑，返回一个QuestionDetailVo对象代表问题详细信息
            QuestionDetailVo questionDetailVo = examService.getQuestionDetail(id);
            // 如果获取详细信息成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取操作成功，消息设置为"获取问题详情成功"，并将获取到的问题详细信息对象放入ResultVO对象中
            resultVO = new ResultVO<>(0, "获取问题详情成功", questionDetailVo);
        } catch (Exception e) {
            // 如果在获取详细信息过程中出现异常，打印异常堆栈信息，便于查找问题原因
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取操作失败，消息设置为"获取问题详情失败"，数据部分设置为null
            resultVO = new ResultVO<>(-1, "获取问题详情失败", null);
        }
        return resultVO;// 返回结果对象
    }
    /**
     * 此方法用于获取所有考试的信息。
     * 通过HTTP的GET请求方式访问，请求路径为 "/api/exam/all"，会调用服务层方法获取所有考试信息，并根据执行情况返回相应结果给客户端。
     */
    @GetMapping("/all")
    @ApiOperation("获取全部考试的列表")
    ResultVO<List<ExamVo>> getExamAll() {
        // 定义一个ResultVO类型的变量，用于存放最终要返回给客户端的结果对象，其泛型参数指定为List<ExamVo>，表示包含考试列表数据的结果封装
        ResultVO<List<ExamVo>> resultVO;
        try {
            // 调用ExamService的getExamAll方法，该方法应该在服务层实现从数据库或者其他数据源获取所有考试数据的逻辑，返回一个ExamVo类型的列表，代表所有考试信息
            List<ExamVo> examVos = examService.getExamAll();
            // 如果获取数据成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示操作成功，消息设置为"获取全部考试的列表成功"，并将获取到的考试列表数据放入ResultVO对象中
            resultVO = new ResultVO<>(0, "获取全部考试的列表成功", examVos);
        } catch (Exception e) {
            // 如果在获取数据过程中出现异常，打印异常堆栈信息，方便后续排查问题
            e.printStackTrace();
            // 创建一个表示失败的ResultVO对象，状态码设置为 -1，表示操作失败，消息设置为"获取全部考试的列表失败"，数据部分设置为null，因为没有成功获取到考试列表数据
            resultVO = new ResultVO<>(-1, "获取全部考试的列表失败", null);
        }
        return resultVO;// 返回结果对象
    }
    /**
     * 该方法用于获取问题列表，并按照单选、多选和判断题分类返回。
     * 通过HTTP的GET请求方式访问，请求路径为 "/api/exam/question/type/list"，会调用服务层方法获取分类后的问题列表数据，并根据执行情况返回相应结果给客户端。
     */
    @GetMapping("/question/type/list")
    @ApiOperation("获取问题列表，按照单选、多选和判断题分类返回")
    ResultVO<ExamQuestionTypeVo> getExamQuestionTypeList() {
        // 定义一个ResultVO类型的变量，用于存放最终要返回给客户端的结果对象，其泛型参数指定为ExamQuestionTypeVo，用于封装按照特定分类方式整理后的问题列表相关信息
        ResultVO<ExamQuestionTypeVo> resultVO;
        try {
            // 调用ExamService的getExamQuestionType方法，该方法在服务层应该实现从数据库或者其他数据源获取并整理按照单选、多选和判断题分类后的问题列表数据的逻辑，返回一个ExamQuestionTypeVo对象
            ExamQuestionTypeVo examQuestionTypeVo = examService.getExamQuestionType();
            resultVO = new ResultVO<>(0, "获取问题列表成功", examQuestionTypeVo);
        } catch (Exception e) {
            e.printStackTrace();
            resultVO = new ResultVO<>(-1, "获取问题列表失败", null);
        }
        return resultVO;
    }
    /**
     * 这个方法用于创建新的考试记录。
     * 接收一个HTTP的POST请求，请求路径为 "/api/exam/create"，客户端需要在请求体中传递包含创建新考试所需数据的视图对象（ExamCreateVo），同时通过HttpServletRequest获取相关的请求上下文信息（比如用户ID），然后调用服务层方法创建新考试记录，并返回相应结果给客户端。
     */
    @PostMapping("/create")
    @ApiOperation("创建考试")
    ResultVO<Exam> createExam(@RequestBody ExamCreateVo examCreateVo, HttpServletRequest request) {
        // 定义一个ResultVO类型的变量，用于存放最终要返回给客户端的结果对象，其泛型参数指定为Exam，表示包含新创建考试相关信息的结果封装
        ResultVO<Exam> resultVO;
        // 从HttpServletRequest对象中获取用户ID信息，通常这个用户ID是在请求处理的前置环节（比如拦截器中）设置到请求属性中的，用于标识创建这个考试的用户是谁
        String userId = (String) request.getAttribute("user_id");
        try {
            // 调用ExamService的create方法，将创建考试的视图对象（examCreateVo）和获取到的用户ID传递进去，由服务层实现将考试记录数据保存到数据库等具体的创建逻辑操作，返回创建好的Exam对象代表新创建的考试信息
            Exam exam = examService.create(examCreateVo, userId);
            // 如果创建成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示创建操作成功，消息设置为"创建考试成功"，并将创建好的考试对象放入ResultVO对象中返回给客户端
            resultVO = new ResultVO<>(0, "创建考试成功", exam);
        } catch (Exception e) {
            e.printStackTrace();
            // 如果在创建过程中出现异常，创建一个表示创建失败的ResultVO对象，状态码设置为 -1，表示创建操作失败，消息设置为"创建考试失败"，数据部分设置为null
            resultVO = new ResultVO<>(-1, "创建考试失败", null);
        }
        return resultVO;
    }
    /**
     * 更新已有考试的信息。
     * 此方法用于处理更新考试信息的业务逻辑，接收前端传来包含更新后考试数据的视图对象以及HTTP请求对象，
     * 通过调用服务层方法完成考试信息更新，并根据执行情况返回包含更新结果（成功时为最新考试信息，失败则为错误消息）的ResultVO对象。
     *
     * @param examVo 包含更新后数据的新视图对象，该对象封装了前端传来的需要更新到数据库中考试记录的各项数据，例如考试名称、考试时间等可能变动的信息。
     * @param request HTTP请求，用于提取用户ID，通常在请求处理链路的前期（如拦截器中）会将用户相关标识信息设置到请求属性里，这里用于获取操作考试信息的用户标识，以记录是谁进行的更新操作等业务逻辑判断。
     * @return 返回更新后的结果，以ResultVO<Exam>类型返回，若更新成功，ResultVO中会包含更新后的考试信息（通过Exam对象体现），若失败则包含相应的错误消息以及状态码等信息用于前端知晓操作情况。
     */
    @PostMapping("/update")
    @ApiOperation("更新考试")
    ResultVO<Exam> updateExam(@RequestBody ExamVo examVo, HttpServletRequest request) {
        // 从前端传参数过来，在这里完成考试的入库，此处先定义一个用于存放最终要返回给客户端的ResultVO<Exam>类型的结果对象，后续根据操作成功与否进行赋值。
        ResultVO<Exam> resultVO;
        // 从HttpServletRequest对象中获取用户ID属性值，该用户ID用于标识当前执行更新考试操作的用户，是后续业务逻辑判断（如权限校验、操作记录等）的重要依据。
        String userId = (String) request.getAttribute("user_id");
        try {
            // 调用ExamService的update方法，传入包含更新数据的examVo视图对象以及获取到的用户ID，由服务层去实现具体更新数据库中对应考试记录的逻辑，比如根据传入数据修改相应字段等操作，并返回更新后的Exam对象（包含最新的考试信息）。
            Exam exam = examService.update(examVo, userId);
            // 如果更新操作成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示更新考试成功，消息设置为"更新考试成功"，并将更新后的考试对象放入ResultVO对象中，用于返回给客户端展示最新的考试信息。
            resultVO = new ResultVO<>(0, "更新考试成功", exam);
        } catch (Exception e) {
            // 如果在更新考试信息的过程中出现异常，打印异常堆栈信息，方便开发人员后续排查问题，定位是哪里出现的错误导致更新失败。
            e.printStackTrace();
            // 创建一个表示更新失败的ResultVO对象，状态码设置为 -1，表示更新考试失败，消息可根据业务实际情况默认为"更新考试失败"之类的提示信息，数据部分设置为null，因为没有成功获取到更新后的有效考试信息。
            resultVO = new ResultVO<>(-1, "更新考试失败", null);
        }
        return resultVO;
    }
    /**
     * 获取适配前端卡片展示形式的考试列表。
     * 该方法通过HTTP的GET请求获取考试列表信息，此列表数据是经过处理适配前端以卡片形式展示的，最终返回一个ResultVO<List<ExamCardVo>>对象，
     * 其中若获取成功则ResultVO中包含实际的考试卡片列表数据，若失败则包含相应错误提示等信息。
     *
     * @return返回包含卡片形式的考试列表的ResultVO对象，ResultVO用于统一封装操作结果（成功与否、对应的数据以及提示消息等），List<ExamCardVo>表示具体的考试卡片列表数据结构，每个ExamCardVo对象可包含如考试标题、缩略图、关键信息等适合在前端卡片中展示的内容。
     */
    @GetMapping("/card/list")
    @ApiOperation("获取考试列表，适配前端卡片列表")
    ResultVO<List<ExamCardVo>> getExamCardList() {
        // 获取考试列表卡片，先定义一个用于存放最终要返回给客户端的ResultVO<List<ExamCardVo>>类型的结果对象，后续根据获取数据的情况进行赋值操作。
        ResultVO<List<ExamCardVo>> resultVO;
        try {
            // 调用ExamService的getExamCardList方法，由服务层实现从数据库或者其他数据源获取并整理适合前端以卡片形式展示的考试列表数据的逻辑，返回一个List<ExamCardVo>类型的列表，代表所有考试的卡片信息。
            List<ExamCardVo> examCardVoList = examService.getExamCardList();
            // 如果获取数据成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取考试列表卡片成功，消息设置为"获取考试列表卡片成功"，并将获取到的考试卡片列表数据放入ResultVO对象中，以便返回给客户端进行展示。
            resultVO = new ResultVO<>(0, "获取考试列表卡片成功", examCardVoList);
        } catch (Exception e) {
            // 如果在获取考试卡片列表数据的过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是数据源连接问题还是数据查询等环节出现的错误导致获取失败。
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试列表卡片失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的考试卡片列表数据。
            resultVO = new ResultVO<>(-1, "获取考试列表卡片失败", null);
        }
        return resultVO;
    }
    /**
     * 根据给定ID检索特定考卷的信息。
     * 此方法接收考卷的唯一标识符作为参数，通过HTTP的GET请求获取对应考卷的详细信息，最终返回一个ResultVO<ExamDetailVo>对象，
     * 若获取成功则ResultVO中包含实际的考卷详情信息，若失败则包含相应错误提示等信息。
     *
     * @param id 考卷唯一标识符，用于准确指定要查询详细信息的考卷，通常是在数据库中该考卷记录的主键或者唯一标识字段对应的值，由前端传入或者其他业务环节传递过来。
     * @return 包含考卷详情信息的ResultVO对象，ResultVO用于统一封装操作结果（成功与否、对应的数据以及提示消息等），ExamDetailVo对象包含了考卷的详细内容，比如考题详情、考试时间、考试分值等各种具体信息。
     */
    @GetMapping("/detail/{id}")
    @ApiOperation("根据考试的id，获取考试详情")
    ResultVO<ExamDetailVo> getExamDetail(@PathVariable String id) {
        // 根据id获取考试详情，先定义一个用于存放最终要返回给客户端的ResultVO<ExamDetailVo>类型的结果对象，后续根据查询数据的情况进行赋值操作。
        ResultVO<ExamDetailVo> resultVO;
        try {
            // 调用ExamService的getExamDetail方法，将接收到的考卷唯一标识符（id）传递进去，由服务层实现从数据库或者其他数据源根据该ID查询对应考卷详细信息的逻辑，返回一个ExamDetailVo对象代表该考卷的所有详细信息。
            ExamDetailVo examDetail = examService.getExamDetail(id);
            // 如果获取详细信息成功，创建一个表示成功的ResultVO对象，状态码设置为0，表示获取考试详情成功，消息设置为"获取考试详情成功"，并将获取到的考卷详细信息对象放入ResultVO对象中，以便返回给客户端进行展示。
            resultVO = new ResultVO<>(0, "获取考试详情成功", examDetail);
        } catch (Exception e) {
            // 如果在获取考卷详细信息的过程中出现异常，创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试详情失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的考卷详细信息。
            resultVO = new ResultVO<>(-1, "获取考试详情失败", null);
        }
        return resultVO;
    }
    /**
     * 提交用户答案，并进行评分处理。此过程将返回得分情况。
     * 该方法接收考试的唯一标识符、用户提交的答案集合以及HTTP请求对象，通过调用服务层的评判方法，根据用户答案对指定考试进行判分，
     * 最终返回一个ResultVO<ExamRecord>对象，若评分成功则ResultVO中包含评分后的成绩记录（如分数等信息），若失败则包含相应错误提示等信息。
     *
     * @param examId 要评分的考试唯一标识符，用于明确是对哪一场考试进行评分操作，该标识符对应数据库中考试记录的唯一标识字段，由前端传入或者其他业务环节传递过来。
     * @param answersMap 用户提交答案集合（可能包括多个答案），以HashMap<String, List<String>>类型接收，其中键可能表示题目编号或者标识，值为对应题目的答案列表（比如选择题可能有多个选项答案等情况），用于传递用户针对各题所做的回答内容。
     * @param request 用于提取当前用户ID的HTTP请求，在请求处理链路的前期（如拦截器中）会将用户相关标识信息设置到请求属性里，这里用于获取提交答案的当前用户标识，以便在服务层进行评分等业务逻辑处理时关联用户与答题记录、判断权限等操作。
     * @return 一个结果封装了评分后的成绩记录（包括分数等）与相应消息，以ResultVO<ExamRecord>类型返回，ExamRecord对象可包含如用户得分、答题情况分析、考试相关信息等内容，用于告知前端用户此次考试的评分结果以及详细情况。
     */
    @PostMapping("/finish/{examId}")
    @ApiOperation("根据用户提交的答案对指定id的考试判分")
    ResultVO<ExamRecord> finishExam(@PathVariable String examId, @RequestBody HashMap<String, List<String>> answersMap, HttpServletRequest request) {
        // 定义一个用于存放结果的ResultVO<ExamRecord>类型的数据结构，后续根据评分操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示评分结果。
        ResultVO<ExamRecord> resultVO;
        try {
            // 拦截器里设置上的用户id，从HttpServletRequest对象中获取用户ID属性值，该用户ID用于标识当前提交答案并进行评分的用户，是后续业务逻辑处理（如记录答题记录归属、判断是否有权限答题等）的重要依据。
            String userId = (String) request.getAttribute("user_id");
            // 下面根据用户提交的信息进行判分，返回用户的得分情况，调用ExamService的judge方法，传入获取到的用户ID、考试唯一标识符（examId）以及用户提交的答案集合（answersMap），由服务层实现具体的评分逻辑，比如对比答案、计算得分等操作，并返回一个ExamRecord对象，包含了评分后的成绩记录等详细信息。
            ExamRecord examRecord = examService.judge(userId, examId, answersMap);
            // 封装成绩记录到最终结果中，创建一个表示评分成功的ResultVO对象，状态码设置为0，表示考卷提交（评分）成功，消息设置为"考卷提交成功"，并将包含成绩记录的ExamRecord对象放入ResultVO对象中，以便返回给客户端展示评分结果。
            resultVO = new ResultVO<>(0, "考卷提交成功", examRecord);// 封装成绩记录到最终结果中
        } catch (Exception e) {
            // 如果在评分过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是答案解析出错还是其他业务逻辑环节出现的错误导致评分失败。
            e.printStackTrace();
            // 创建一个表示评分失败的ResultVO对象，状态码设置为 -1，表示考卷提交（评分）失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的评分成绩记录。
            resultVO = new ResultVO<>(-1, "考卷提交失败", null);
        }
        return resultVO;
    }
    /**
     * 获取当前用户已参加过所有测验记录。
     * 此方法通过HTTP的GET请求获取当前用户曾经参与过的所有考试记录信息，最终返回一个ResultVO<List<ExamRecordVo>>对象，
     * 若获取成功则ResultVO中包含实际的用户考试历史记录列表数据（如考试时间、得分等信息），若失败则包含相应错误提示等信息。
     *
     * @param request 用于提取当前用户ID，在请求处理链路的前期（如拦截器中）会将用户相关标识信息设置到请求属性里，这里用于获取要查询考试记录的目标用户标识，以便在服务层准确获取该用户对应的历史考试记录数据。
     * @return 包含该用户所有测验历史记录（如时间、得分等）的ResultVO对象，ResultVO用于统一封装操作结果（成功与否、对应的数据以及提示消息等），List<ExamRecordVo>表示具体的用户考试历史记录列表数据结构，每个ExamRecordVo对象可包含如考试时间、考试得分、考试名称等各种历史考试相关的详细信息。
     */
    @GetMapping("/record/list")
    @ApiOperation("获取当前用户的考试记录")
    ResultVO<List<ExamRecordVo>> getExamRecordList(HttpServletRequest request) {
        // 定义一个用于存放结果的ResultVO<List<ExamRecordVo>>类型的数据结构，后续根据查询用户考试记录操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示查询结果。
        ResultVO<List<ExamRecordVo>> resultVO;
        try {
            // 拦截器里设置上的用户id，从HttpServletRequest对象中获取用户ID属性值，该用户ID用于明确要查询其考试记录的目标用户，是服务层准确获取对应数据的关键依据。
            String userId = (String) request.getAttribute("user_id");
            // 下面根据用户账号拿到他（她）所有的考试信息，注意要用VO封装下，调用ExamService的getExamRecordList方法，传入获取到的用户ID，由服务层实现从数据库或者其他数据源获取该用户所有历史考试记录数据的逻辑，并将其整理封装成List<ExamRecordVo>类型的列表返回，每个ExamRecordVo对象包含了如时间、得分等详细信息。
            List<ExamRecordVo> examRecordVoList = examService.getExamRecordList(userId);
            // 封装查询得到的信息到最终结果中，创建一个表示获取成功的ResultVO对象，状态码设置为0，表示获取考试记录成功，消息设置为"获取考试记录成功"，并将获取到的用户考试记录列表数据放入ResultVO对象中，以便返回给客户端展示历史考试记录情况。
            resultVO = new ResultVO<>(0, "获取考试记录成功", examRecordVoList);//封装查询得到的信息到最终结果中；
        } catch (Exception e) {
            // 如果在获取用户考试记录数据的过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是数据源查询出错还是数据封装等环节出现的错误导致获取失败。
            e.printStackTrace();
            // 创建一个表示获取失败的ResultVO对象，状态码设置为 -1，表示获取考试记录失败，消息可根据业务实际情况设置为相应的提示语，数据部分设置为null，因为没有成功获取到有效的用户考试记录数据。
            resultVO = new ResultVO<>(-1, "获取考试记录失败", null);
        }
        return resultVO;//返回封装好的 数据结构
    }
    /**
     * 根据指定recordId查询某次测验详细情况。
     * 此方法接收要查询测验具体内容对应的唯一标识符作为参数，通过HTTP的GET请求获取该次测验的详细信息，最终返回一个ResultVO<RecordDetailVo>对象，
     * 若获取成功则ResultVO中包含实际的测验详情数据与反馈消息内容，若失败则包含相应错误提示等信息。
     *
     * @param recordId 要查询测验具体内容对应唯一标识符，用于准确指定要查询详细信息的那次测验记录，通常是在数据库中该测验记录的主键或者唯一标识字段对应的值，由前端传入或者其他业务环节传递过来。
     * @return 封装了该条目详尽数据与反馈消息内容的ResultVO对象，ResultVO用于统一封装操作结果（成功与否、对应的数据以及提示消息等），RecordDetailVo对象包含了该次测验的详细情况，比如考试题目详情、答题情况、得分情况等各种具体信息以及相关反馈消息。
     */
    @GetMapping("/record/detail/{recordId}")
    @ApiOperation("根据考试记录id获取考试记录详情")
    ResultVO<RecordDetailVo> getExamRecordDetail(@PathVariable String recordId) {
        // 定义一个用于存放结果的ResultVO<RecordDetailVo>类型的数据结构，后续根据查询测验详细情况操作的成功与否以及获取到的相关数据进行赋值，用于最终返回给客户端展示查询结果。
        ResultVO<RecordDetailVo> resultVO;
        try {
            // 调用ExamService的getRecordDetail方法，将接收到的测验记录唯一标识符（recordId）传递进去，由服务层实现从数据库或者其他数据源根据该ID查询对应测验详细信息的逻辑，返回一个RecordDetailVo对象代表该次测验的所有详细信息。
            RecordDetailVo recordDetailVo = examService.getRecordDetail(recordId);
            // 封装查询得到的信息到最终结果中，创建一个表示获取成功的ResultVO对象，状态码设置为0，表示获取考试记录详情成功，消息设置为"获取考试记录详情成功"，并将获取到的测验详细信息对象放入ResultVO对象中，以便返回给客户端展示该次测验的详细情况。
            resultVO = new ResultVO<>(0, "获取考试记录详情成功", recordDetailVo);//封装查询得到的信息到最终结果中；
        } catch (Exception e) {
            // 如果在获取测验详细信息的过程中出现异常，打印异常堆栈信息，方便开发人员排查问题，查看是数据源查询出错还是数据解析等环节出现的错误导致获取失败。
            e.printStackTrace();
            // 创建一个ResultVO对象，表示操作失败
            // 状态码设置为-1，表示获取考试记录详情失败
            // 消息设置为"获取考试记录详情失败"
            // 由于查询失败，详细信息对象设置为null
            resultVO = new ResultVO<>(-1, "获取考试记录详情失败", null);
        }
        // 返回封装好的ResultVO对象给客户端
        // 客户端可以根据状态码和消息判断操作是否成功，并根据详细信息对象获取测验的详细记录信息
        return resultVO;
    }
}
