飞算 JavaAI:需求转在线考试系统全流程体验-代码驱动的智能开发革命
每日一句
愿你是一只燕子,
衔着春光飞来;
愿你是一只雄鹰,
箭一般射向蓝天。
目录
每日一句
一.引言:当代码自动生成成为现实
二.数据库设计:自动生成的表结构与关系映射
三.实体类设计:注解驱动的对象映射
四.DAO 层设计:MyBatis-Plus 的智能封装
五.Service 层设计:事务管理与业务逻辑
六.Controller 层设计:RESTful 接口与统一响应
七.前端代码:Vue 组件与实时交互
八.开发效率对比:AI 生成代码带来的质变
九.总结:AI 驱动的开发新范式
一.引言:当代码自动生成成为现实
作为计算机专业学生,我曾以为 \"一天开发一个系统\" 只是天方夜谭。直到使用飞算 JavaAI 开发在线考试系统时,这个想法被彻底颠覆 —— 系统不仅自动生成了规范代码,还处理了事务管理、异常处理等高级逻辑。本文将深入剖析 AI 生成的核心代码,展示从需求到可运行系统的完整技术路径。
二.数据库设计:自动生成的表结构与关系映射
飞算 JavaAI 根据需求自动生成了 8 张核心表,每张表都包含完整的字段约束和索引设计。以下是关键表的 SQL 代码:
-- 用户表设计CREATE TABLE `t_user` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT \'用户ID\', `username` varchar(50) NOT NULL COMMENT \'用户名\', `password` varchar(100) NOT NULL COMMENT \'密码(MD5加密)\', `real_name` varchar(50) NOT NULL COMMENT \'真实姓名\', `id_card` varchar(20) DEFAULT NULL COMMENT \'身份证号\', `phone` varchar(20) DEFAULT NULL COMMENT \'手机号\', `role_id` bigint NOT NULL COMMENT \'角色ID(1:管理员,2:教师,3:学生)\', `status` tinyint NOT NULL DEFAULT \'1\' COMMENT \'状态(0:禁用,1:正常)\', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`), KEY `idx_role_id` (`role_id`), KEY `idx_status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=\'用户信息表\';-- 题库表设计(核心业务表)CREATE TABLE `t_question` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT \'题目ID\', `question_type_id` bigint NOT NULL COMMENT \'题目类型ID(1:单选,2:多选,3:判断)\', `subject_id` bigint NOT NULL COMMENT \'科目ID\', `content` text NOT NULL COMMENT \'题目内容\', `option_a` varchar(500) DEFAULT NULL COMMENT \'选项A\', `option_b` varchar(500) DEFAULT NULL COMMENT \'选项B\', `option_c` varchar(500) DEFAULT NULL COMMENT \'选项C\', `option_d` varchar(500) DEFAULT NULL COMMENT \'选项D\', `answer` varchar(100) NOT NULL COMMENT \'正确答案\', `score` int NOT NULL COMMENT \'分值\', `difficulty` tinyint NOT NULL COMMENT \'难度(1:易,2:中,3:难)\', `analysis` text COMMENT \'答案解析\', `create_by` bigint NOT NULL COMMENT \'创建人\', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_question_type` (`question_type_id`), KEY `idx_subject` (`subject_id`), KEY `idx_difficulty` (`difficulty`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=\'题库表\';-- 考试记录表(带事务特性)CREATE TABLE `t_exam_record` ( `id` bigint NOT NULL AUTO_INCREMENT COMMENT \'考试记录ID\', `paper_id` bigint NOT NULL COMMENT \'试卷ID\', `user_id` bigint NOT NULL COMMENT \'考生ID\', `start_time` datetime NOT NULL COMMENT \'开始时间\', `end_time` datetime DEFAULT NULL COMMENT \'结束时间\', `status` tinyint NOT NULL COMMENT \'状态(1:进行中,2:已完成,3:超时)\', `score` decimal(5,1) DEFAULT NULL COMMENT \'总分\', `cheat_count` int NOT NULL DEFAULT \'0\' COMMENT \'作弊次数\', `ip_address` varchar(50) DEFAULT NULL COMMENT \'登录IP\', PRIMARY KEY (`id`), UNIQUE KEY `idx_user_paper` (`user_id`,`paper_id`,`status`) COMMENT \'防止重复考试\', KEY `idx_status` (`status`), KEY `idx_end_time` (`end_time`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT=\'考试记录表\';
代码解析:AI 生成的 SQL 具有以下特点:
1.完整的字段注释和表注释,符合企业开发规范
2.合理的索引设计,尤其是idx_user_paper
唯一索引有效防止重复考试
3.包含时间戳字段create_time
和update_time
,便于数据追踪
4.状态字段使用 tinyint 类型,节省存储空间
5.针对考试业务特点设计了cheat_count
等特色字段
三.实体类设计:注解驱动的对象映射
基于数据库表结构,飞算 JavaAI 自动生成了对应的实体类,采用 Lombok 简化代码:
@Data@TableName(\"t_question\")public class Question implements Serializable { private static final long serialVersionUID = 1L; /** * 题目ID */ @TableId(type = IdType.AUTO) private Long id; /** * 题目类型ID(1:单选,2:多选,3:判断) */ @TableField(\"question_type_id\") @NotNull(message = \"题目类型不能为空\") private Long questionTypeId; /** * 科目ID */ @TableField(\"subject_id\") @NotNull(message = \"科目不能为空\") private Long subjectId; /** * 题目内容 */ @TableField(\"content\") @NotBlank(message = \"题目内容不能为空\") private String content; /** * 选项A */ @TableField(\"option_a\") private String optionA; /** * 选项B */ @TableField(\"option_b\") private String optionB; /** * 选项C */ @TableField(\"option_c\") private String optionC; /** * 选项D */ @TableField(\"option_d\") private String optionD; /** * 正确答案 */ @TableField(\"answer\") @NotBlank(message = \"正确答案不能为空\") private String answer; /** * 分值 */ @TableField(\"score\") @Min(value = 1, message = \"分值不能小于1\") private Integer score; /** * 难度(1:易,2:中,3:难) */ @TableField(\"difficulty\") @NotNull(message = \"难度等级不能为空\") @Range(min = 1, max = 3, message = \"难度等级必须在1-3之间\") private Integer difficulty; /** * 答案解析 */ @TableField(\"analysis\") private String analysis; /** * 创建人 */ @TableField(\"create_by\") private Long createBy; /** * 创建时间 */ @TableField(value = \"create_time\", fill = FieldFill.INSERT) private LocalDateTime createTime; /** * 更新时间 */ @TableField(value = \"update_time\", fill = FieldFill.INSERT_UPDATE) private LocalDateTime updateTime; // 扩展字段(非数据库字段) @TableField(exist = false) private String questionTypeName; // 题目类型名称 @TableField(exist = false) private String subjectName; // 科目名称}
代码解析:实体类体现了 AI 的细致处理:
1.使用@Data
注解简化 getter/setter 等模板代码
2.通过@TableName
和@TableField
实现与数据库表的映射
3.集成javax.validation
注解实现参数校验
4.合理使用@TableField(exist = false)
定义 DTO 扩展字段
5.使用LocalDateTime
处理时间,符合 Java 8 + 规范
6.添加序列化接口,支持分布式场景
四.DAO 层设计:MyBatis-Plus 的智能封装
数据访问层采用 MyBatis-Plus 框架,AI 生成的代码不仅包含基础 CRUD,还实现了复杂查询:
public interface QuestionMapper extends BaseMapper { /** * 按条件分页查询题目 * 支持多条件组合查询,包含题目类型、科目、难度、关键词 */ @Select(\"\" + \"SELECT q.*,qt.name as question_type_name,s.name as subject_name \" + \"FROM t_question q \" + \"LEFT JOIN t_question_type qt ON q.question_type_id = qt.id \" + \"LEFT JOIN t_subject s ON q.subject_id = s.id \" + \"\" + \"AND q.question_type_id = #{questionTypeId}\" + \"AND q.subject_id = #{subjectId}\" + \"AND q.difficulty = #{difficulty}\" + \"AND q.content LIKE CONCAT(\'%\',#{keyword},\'%\')\" + \"\" + \"ORDER BY q.create_time DESC\" + \"\") IPage selectPage( @Param(\"page\") Page page, @Param(\"questionTypeId\") Long questionTypeId, @Param(\"subjectId\") Long subjectId, @Param(\"difficulty\") Integer difficulty, @Param(\"keyword\") String keyword); /** * 随机抽取题目(组卷核心方法) * 根据科目、题型、难度、数量进行随机抽题 */ @Select(\"\" + \"SELECT * FROM t_question \" + \"\" + \"subject_id = #{subjectId} \" + \"AND question_type_id = #{questionTypeId} \" + \"AND difficulty = #{difficulty} \" + \"\" + \"ORDER BY RAND() LIMIT #{count}\" + \"\") List selectRandomQuestions( @Param(\"subjectId\") Long subjectId, @Param(\"questionTypeId\") Long questionTypeId, @Param(\"difficulty\") Integer difficulty, @Param(\"count\") Integer count);}
代码解析:DAO 层代码展现了高级查询能力:
1.继承BaseMapper
获得基础 CRUD 操作,减少重复代码
2.使用 MyBatis 动态 SQL 实现多条件查询
3.专门设计selectRandomQuestions
方法支持智能组卷
4.分页查询包含关联表信息,减少 N+1 查询问题
5.参数命名规范,与业务逻辑保持一致
五.Service 层设计:事务管理与业务逻辑
Service 层是业务逻辑核心,AI 生成的代码包含完整的事务控制和业务规则:
@Service@Slf4jpublic class ExamServiceImpl implements ExamService { @Autowired private ExamRecordMapper examRecordMapper; @Autowired private PaperMapper paperMapper; @Autowired private QuestionMapper questionMapper; @Autowired private AnswerMapper answerMapper; @Autowired private RedisTemplate redisTemplate; /** * 开始考试(带事务控制) */ @Override @Transactional(rollbackFor = Exception.class) public ExamStartVO startExam(Long paperId, Long userId) { // 1. 验证试卷状态 Paper paper = paperMapper.selectById(paperId); if (paper == null) { throw new BusinessException(\"试卷不存在\"); } if (paper.getStatus() != 1) { throw new BusinessException(\"试卷未发布或已过期\"); } // 2. 检查是否已参加过考试 QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq(\"user_id\", userId) .eq(\"paper_id\", paperId) .in(\"status\", 1, 2); // 进行中或已完成 ExamRecord existRecord = examRecordMapper.selectOne(queryWrapper); if (existRecord != null) { if (existRecord.getStatus() == 1) { throw new BusinessException(\"您有未完成的考试,请继续作答\"); } else { throw new BusinessException(\"您已参加过该考试,不能重复考试\"); } } // 3. 创建考试记录 ExamRecord examRecord = new ExamRecord(); examRecord.setPaperId(paperId); examRecord.setUserId(userId); examRecord.setStartTime(LocalDateTime.now()); examRecord.setStatus(1); // 进行中 examRecord.setIpAddress(IpUtils.getIpAddr()); examRecordMapper.insert(examRecord); // 4. 获取试卷题目 List questions = questionMapper.selectByPaperId(paperId); if (CollectionUtils.isEmpty(questions)) { throw new BusinessException(\"试卷未配置题目,请联系管理员\"); } // 5. 缓存考试信息到Redis,设置过期时间(考试时长+5分钟缓冲) String examKey = \"exam:record:\" + examRecord.getId(); redisTemplate.opsForValue().set(examKey, examRecord, paper.getDuration() + 5, TimeUnit.MINUTES); // 6. 构建返回结果 ExamStartVO result = new ExamStartVO(); result.setExamId(examRecord.getId()); result.setPaperId(paperId); result.setPaperName(paper.getName()); result.setDuration(paper.getDuration()); result.setStartTime(examRecord.getStartTime()); result.setQuestions(questions); log.info(\"用户[{}]开始考试[{}],试卷[{}]\", userId, examRecord.getId(), paperId); return result; } /** * 提交答案并自动判分(核心业务逻辑) */ @Override @Transactional(rollbackFor = Exception.class) public ExamResultVO submitAnswer(Long examId, Long userId, List answerList) { // 1. 验证考试状态 ExamRecord examRecord = examRecordMapper.selectById(examId); if (examRecord == null) { throw new BusinessException(\"考试记录不存在\"); } if (!examRecord.getUserId().equals(userId)) { throw new BusinessException(\"无权操作他人考试记录\"); } if (examRecord.getStatus() != 1) { throw new BusinessException(\"考试已结束或已提交\"); } // 2. 获取试卷信息 Paper paper = paperMapper.selectById(examRecord.getPaperId()); if (paper == null) { throw new BusinessException(\"试卷信息不存在\"); } // 3. 保存答案并计算得分 BigDecimal totalScore = BigDecimal.ZERO; List answers = new ArrayList(); for (AnswerDTO dto : answerList) { // 查询题目信息 Question question = questionMapper.selectById(dto.getQuestionId()); if (question == null) { continue; } // 创建答案记录 Answer answer = new Answer(); answer.setExamId(examId); answer.setQuestionId(dto.getQuestionId()); answer.setUserId(userId); answer.setUserAnswer(dto.getUserAnswer()); answer.setCreateTime(LocalDateTime.now()); // 自动判分(不同题型有不同判分规则) BigDecimal score = BigDecimal.ZERO; if (question.getQuestionTypeId() == 3) { // 判断题 if (Objects.equals(dto.getUserAnswer(), question.getAnswer())) { score = BigDecimal.valueOf(question.getScore()); } } else if (question.getQuestionTypeId() == 1) { // 单选题 if (Objects.equals(dto.getUserAnswer(), question.getAnswer())) { score = BigDecimal.valueOf(question.getScore()); } } else if (question.getQuestionTypeId() == 2) { // 多选题(按正确比例得分) String[] userAnswers = dto.getUserAnswer().split(\",\"); String[] correctAnswers = question.getAnswer().split(\",\"); int correctCount = 0; for (String userAns : userAnswers) { if (Arrays.asList(correctAnswers).contains(userAns)) { correctCount++; } else { // 多选错选不得分 correctCount = 0; break; } } // 部分正确得分 if (correctCount > 0 && correctCount = 0); result.setEndTime(examRecord.getEndTime()); log.info(\"用户[{}]完成考试[{}],得分[{}]\", userId, examId, totalScore); return result; } /** * 随机组卷算法(智能组卷核心) */ @Override public Long generateRandomPaper(PaperGenerateDTO dto) { // 1. 参数校验 if (dto.getSubjectId() == null) { throw new BusinessException(\"请选择考试科目\"); } if (CollectionUtils.isEmpty(dto.getQuestionTypeList())) { throw new BusinessException(\"请选择题目类型\"); } // 2. 创建试卷基本信息 Paper paper = new Paper(); paper.setName(dto.getPaperName()); paper.setSubjectId(dto.getSubjectId()); paper.setDuration(dto.getDuration()); paper.setPassScore(dto.getPassScore()); paper.setStatus(0); // 未发布 paper.setCreateBy(dto.getCreateBy()); paperMapper.insert(paper); Long paperId = paper.getId(); // 3. 按题型和难度随机抽题 List paperQuestions = new ArrayList(); int sort = 1; for (QuestionTypeDTO type : dto.getQuestionTypeList()) { // 按难度分布抽题 for (DifficultyDTO difficulty : type.getDifficultyList()) { List questions = questionMapper.selectRandomQuestions( dto.getSubjectId(), type.getQuestionTypeId(), difficulty.getDifficulty(), difficulty.getCount() ); // 处理抽题不足的情况 if (questions.size() < difficulty.getCount()) { log.warn(\"题目不足:科目[{}],题型[{}],难度[{}],需求[{}],实际[{}]\", dto.getSubjectId(), type.getQuestionTypeId(), difficulty.getDifficulty(), difficulty.getCount(), questions.size()); } // 添加到试卷 for (Question q : questions) { PaperQuestion pq = new PaperQuestion(); pq.setPaperId(paperId); pq.setQuestionId(q.getId()); pq.setScore(q.getScore()); pq.setSort(sort++); paperQuestions.add(pq); } } } // 4. 保存试卷题目关联关系 if (!paperQuestions.isEmpty()) { paperQuestionMapper.batchInsert(paperQuestions); // 5. 计算试卷总分 BigDecimal totalScore = paperQuestions.stream() .map(PaperQuestion::getScore) .reduce(BigDecimal.ZERO, BigDecimal::add); paper.setTotalScore(totalScore); paperMapper.updateById(paper); } log.info(\"生成随机试卷[{}],题目数量[{}]\", paperId, paperQuestions.size()); return paperId; }}
代码解析:Service 层代码体现了企业级应用的核心特性:
1.使用@Transactional
注解保证事务一致性
2.完善的参数校验和异常处理(自定义BusinessException
)
3.复杂业务逻辑实现,如多选题的按比例计分规则
4.结合 Redis 实现考试状态缓存和过期控制
5.批量操作优化(batchInsert
)提升性能
6.详细的日志记录便于问题排查
7.面向接口编程,通过 VO/DTO 分离数据传输对象
六.Controller 层设计:RESTful 接口与统一响应
控制器层实现了 RESTful 风格的 API 设计,包含完整的请求处理流程:
@RestController@RequestMapping(\"/api/exam\")@Slf4jpublic class ExamController { @Autowired private ExamService examService; @Autowired private AnswerService answerService; /** * 开始考试接口 */ @PostMapping(\"/start\") public Result startExam(@Valid @RequestBody ExamStartDTO dto, HttpServletRequest request) { try { // 获取当前登录用户ID(实际项目中从Token中解析) Long userId = SecurityUtils.getCurrentUserId(); ExamStartVO result = examService.startExam(dto.getPaperId(), userId); return Result.success(result); } catch (BusinessException e) { log.warn(\"开始考试失败:{}\", e.getMessage()); return Result.fail(e.getMessage()); } catch (Exception e) { log.error(\"开始考试异常\", e); return Result.error(\"系统异常,请稍后重试\"); } } /** * 提交答案接口 */ @PostMapping(\"/submit\") public Result submitAnswer(@Valid @RequestBody ExamSubmitDTO dto) { try { Long userId = SecurityUtils.getCurrentUserId(); ExamResultVO result = examService.submitAnswer(dto.getExamId(), userId, dto.getAnswerList()); return Result.success(result); } catch (BusinessException e) { log.warn(\"提交答案失败:{}\", e.getMessage()); return Result.fail(e.getMessage()); } catch (Exception e) { log.error(\"提交答案异常\", e); return Result.error(\"系统异常,请稍后重试\"); } } /** * 获取考试详情接口 */ @GetMapping(\"/{examId}/detail\") public Result getExamDetail(@PathVariable Long examId) { try { Long userId = SecurityUtils.getCurrentUserId(); ExamDetailVO result = examService.getExamDetail(examId, userId); return Result.success(result); } catch (BusinessException e) { log.warn(\"获取考试详情失败:{}\", e.getMessage()); return Result.fail(e.getMessage()); } catch (Exception e) { log.error(\"获取考试详情异常\", e); return Result.error(\"系统异常,请稍后重试\"); } } /** * 随机组卷接口 */ @PostMapping(\"/paper/random\") public Result generateRandomPaper(@Valid @RequestBody PaperGenerateDTO dto) { try { Long userId = SecurityUtils.getCurrentUserId(); dto.setCreateBy(userId); Long paperId = examService.generateRandomPaper(dto); return Result.success(paperId); } catch (BusinessException e) { log.warn(\"随机组卷失败:{}\", e.getMessage()); return Result.fail(e.getMessage()); } catch (Exception e) { log.error(\"随机组卷异常\", e); return Result.error(\"系统异常,请稍后重试\"); } } /** * 监控考试状态(防作弊) */ @PostMapping(\"/monitor\") public Result monitorExamStatus(@RequestBody ExamMonitorDTO dto) { try { Long userId = SecurityUtils.getCurrentUserId(); examService.updateExamStatus(dto.getExamId(), userId, dto.getStatus()); return Result.success(true); } catch (Exception e) { log.error(\"监控考试状态异常\", e); return Result.success(false); } }}
代码解析:Controller 层实现了规范的 API 设计:
1.采用 RESTful 风格的 URL 设计,使用合适的 HTTP 方法
2.统一的响应格式Result
,包含状态码、消息和数据
3.使用@Valid
注解进行请求参数校验
4.完善的异常处理机制,区分业务异常和系统异常
5.日志分级记录(warn/error)便于问题定位
6.安全控制(SecurityUtils.getCurrentUserId()
)
7.清晰的接口命名和职责划分
七.前端代码:Vue 组件与实时交互
飞算 JavaAI 生成的前端代码基于 Vue 和 Element UI,实现了丰富的交互功能:
{{ paperName }}
考试时长:{{ duration }}分钟
<div class=\"timer\" :class=\"{ warning: remainingTime < 5 * 60, danger: remainingTime 剩余时间:{{ formatTime(remainingTime) }} 交卷 {{ index + 1 }} {{ getQuestionTypeName(currentQuestion.questionTypeId) }} ({{ currentQuestion.score }}分) {{ currentQuestionIndex + 1 }}. {{ currentQuestion.content }}
代码解析:前端代码实现了丰富的交互功能:
1.完整的考试流程:题目导航、答题、交卷
2.实时倒计时功能,支持自动交卷
3.防作弊机制:监控页面切换、窗口焦点变化
4.答案自动保存,避免意外丢失
5.响应式布局,适配不同屏幕尺寸
6.清晰的视觉反馈:已答题标记、当前题标记
7.不同题型的差异化展示
八.开发效率对比:AI 生成代码带来的质变
通过飞算 JavaAI 开发在线考试系统,我深刻体会到了智能开发工具的革命性影响:
代码质量对比:
- 传统开发:需要手动处理事务、异常、缓存等复杂逻辑,容易出现疏漏
- AI 生成代码:内置完整的事务管理、异常处理、缓存策略和安全控制
- 可维护性:AI 生成的代码遵循统一规范,注释完整,架构清晰
功能完整性:
AI 生成的系统不仅实现了基础功能,还包含了许多高级特性:
- 防作弊机制(页面监控、切屏检测)
- 智能组卷算法(按难度、题型自动抽题)
- 复杂计分规则(多选题部分得分逻辑)
- 分布式缓存(Redis 存储考试状态)
九.总结:AI 驱动的开发新范式
飞算 JavaAI 彻底改变了我的开发认知 —— 它不仅是一个代码生成工具,更是一个全流程的开发助手。通过分析本次生成的在线考试系统代码,可以发现几个显著特点:
1.架构完整性:严格遵循三层架构设计,各层职责清晰,依赖关系合理
2.业务深度:针对考试场景设计了完整的业务逻辑,包括复杂的计分规则和组卷算法
3.技术先进性:整合了 Spring Boot、MyBatis-Plus、Redis 等主流技术栈
4.安全性考虑:包含权限控制、防作弊机制、数据校验等安全措施
5.可扩展性:代码结构松耦合,便于后续功能扩展和维护
对于学生开发者而言,飞算 JavaAI 是一个绝佳的学习工具 —— 通过研究 AI 生成的高质量代码,我掌握了许多企业级开发的最佳实践。对于企业来说,这种智能开发工具将大幅降低开发成本,缩短项目周期。
未来的软件开发,必将是 \"人类定义需求,AI 实现细节\" 的协作模式。飞算 JavaAI 让我看到了这种未来的可能性,也让我对自己的编程之路充满了新的期待。在 AI 的助力下,我们终于可以从重复劳动中解放出来,将更多精力投入到创意和创新中去。