From c63419e0156fa4a52cd5128b33565db3cc28b1d4 Mon Sep 17 00:00:00 2001 From: zl <3216908512@qq.com> Date: Wed, 27 Nov 2024 16:53:19 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=BC=A0=E5=8A=9B=E5=88=86=E6=94=AF?= =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yf/exam/ability/Constant.java | 13 +- .../yf/exam/ability/job/enums/JobGroup.java | 14 +- .../yf/exam/ability/job/enums/JobPrefix.java | 15 +- .../exam/ability/job/service/JobService.java | 51 +-- .../job/service/impl/JobServiceImpl.java | 129 +++++-- .../ability/shiro/CNFilterFactoryBean.java | 38 ++- .../com/yf/exam/ability/shiro/ShiroRealm.java | 246 +++++++------- .../yf/exam/ability/shiro/aop/JwtFilter.java | 113 +++--- .../yf/exam/ability/shiro/jwt/JwtToken.java | 41 ++- .../yf/exam/ability/shiro/jwt/JwtUtils.java | 90 +++-- .../ability/upload/config/UploadConfig.java | 36 +- .../upload/controller/UploadController.java | 71 ++-- .../exam/ability/upload/dto/UploadReqDTO.java | 30 +- .../ability/upload/dto/UploadRespDTO.java | 35 +- .../ability/upload/service/UploadService.java | 58 +++- .../service/impl/UploadServiceImpl.java | 144 ++++---- .../exam/ability/upload/utils/FileUtils.java | 321 +++++++++--------- .../exam/ability/upload/utils/MediaUtils.java | 76 +++-- .../java/com/yf/exam/aspect/DictAspect.java | 215 +++++++----- .../exam/aspect/mybatis/QueryInterceptor.java | 177 ++++++++-- .../aspect/mybatis/UpdateInterceptor.java | 126 ++++++- .../com/yf/exam/aspect/utils/InjectUtils.java | 111 +++--- .../java/com/yf/exam/config/CorsConfig.java | 58 +++- .../com/yf/exam/config/MultipartConfig.java | 53 ++- .../com/yf/exam/config/MybatisConfig.java | 55 ++- .../com/yf/exam/config/ScheduledConfig.java | 141 +++++++- .../java/com/yf/exam/config/ShiroConfig.java | 242 ++++++------- .../com/yf/exam/config/SwaggerConfig.java | 155 +++++++-- .../exam/controller/ExamController.java | 233 ++++++------- .../com/yf/exam/modules/exam/dto/ExamDTO.java | 140 ++++---- .../exam/modules/exam/dto/ExamDepartDTO.java | 55 ++- .../yf/exam/modules/exam/dto/ExamRepoDTO.java | 93 +++-- .../modules/exam/dto/ext/ExamRepoExtDTO.java | 50 ++- .../exam/dto/request/ExamSaveReqDTO.java | 54 ++- .../exam/dto/response/ExamOnlineRespDTO.java | 35 +- .../exam/dto/response/ExamReviewRespDTO.java | 53 ++- .../com/yf/exam/modules/exam/entity/Exam.java | 155 ++++----- .../exam/modules/exam/entity/ExamDepart.java | 65 ++-- .../yf/exam/modules/exam/entity/ExamRepo.java | 105 +++--- .../modules/exam/mapper/ExamDepartMapper.java | 28 +- .../exam/modules/exam/mapper/ExamMapper.java | 61 ++-- .../modules/exam/mapper/ExamRepoMapper.java | 39 ++- .../exam/service/ExamDepartService.java | 42 +-- .../modules/exam/service/ExamRepoService.java | 49 +-- .../modules/exam/service/ExamService.java | 77 +++-- .../service/impl/ExamDepartServiceImpl.java | 88 +++-- .../service/impl/ExamRepoServiceImpl.java | 92 +++-- .../exam/service/impl/ExamServiceImpl.java | 209 +++++------- 48 files changed, 2685 insertions(+), 1892 deletions(-) diff --git a/src-源文件/main/java/com/yf/exam/ability/Constant.java b/src-源文件/main/java/com/yf/exam/ability/Constant.java index 9880ea6..50e754d 100644 --- a/src-源文件/main/java/com/yf/exam/ability/Constant.java +++ b/src-源文件/main/java/com/yf/exam/ability/Constant.java @@ -1,15 +1,18 @@ +// 定义包路径,用于存放系统基础功能相关的类 package com.yf.exam.ability; - /** - * 通用常量 + * 通用常量类 + * 用于定义系统中使用的常量值,提供全局可访问的常量。 * @author bool */ public class Constant { - /** - * 文件上传路径 + * 文件上传路径的前缀常量 + * 用于指定上传文件的基础路径,所有上传的文件URL都会以这个路径开头。 + * 例如: /upload/file/example.jpg + * 这个前缀用于构建和解析文件的URL,以便在系统中统一管理和访问上传的文件。 */ public static final String FILE_PREFIX = "/upload/file/"; -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java index 2159361..058ab16 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java @@ -1,13 +1,19 @@ +// 定义包路径,用于存放任务分组相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务分组 + * 任务分组枚举接口 + * 定义系统中不同类型任务的分组标识 + * 这个接口用于集中管理任务分组的常量值,确保代码的一致性和可维护性。 + * * @author van */ public interface JobGroup { /** - * 系统任务 + * 系统任务的分组标识 + * 用于标识系统级别的定时任务,如系统维护、数据清理等。 + * 这个标识符用于在任务调度系统中区分系统级别的任务,便于管理和执行。 */ - String SYSTEM = "system"; -} + String SYSTEM = "system"; // 系统任务组的标识符 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java index 2536f0e..dd51986 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java @@ -1,14 +1,19 @@ +// 定义包路径,用于存放任务前缀相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务前缀 + * 任务前缀枚举接口 + * 定义系统中不同任务类型的前缀标识 + * 这个接口用于集中管理任务的前缀常量值,确保代码的一致性和可维护性。 + * * @author bool */ public interface JobPrefix { /** - * 强制交卷的 + * 强制交卷任务的前缀标识 + * 用于标识与强制交卷相关的定时任务,方便在任务调度系统中识别和处理。 + * 例如:break_exam_12345 表示ID为12345的考试的强制交卷任务。 */ - String BREAK_EXAM = "break_exam_"; - -} + String BREAK_EXAM = "break_exam_"; // 强制交卷任务的前缀标识符 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java index cb465de..410c006 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java @@ -1,53 +1,66 @@ +// 定义包路径,用于存放任务服务接口 package com.yf.exam.ability.job.service; /** - * 任务业务类,用于动态处理任务信息 + * 任务业务接口类,用于定义任务相关的业务操作 + * 这个接口定义了定时任务的基本操作,包括添加、暂停、恢复和删除任务。 + * * @author bool * @date 2020/11/29 下午2:17 */ public interface JobService { - /** - * 任务数据 + * 任务数据的键名常量 + * 用于在任务的JobDataMap中存储和检索任务相关数据的键名。 */ - String TASK_DATA = "taskData"; + String TASK_DATA = "taskData"; // 用于存储任务相关数据的键名 /** * 添加定时任务 - * @param jobClass - * @param jobName - * @param cron - * @param data + * 方法用于根据给定的任务类、名称、cron表达式和任务数据,添加一个新的定时任务。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param cron cron表达式,用于指定任务的执行计划 + * @param data 任务数据,传递给任务执行时的参数 */ void addCronJob(Class jobClass, String jobName, String cron, String data); /** * 添加立即执行的任务 - * @param jobClass - * @param jobName - * @param data + * 方法用于根据给定的任务类、名称和任务数据,添加一个新的立即执行的任务。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param data 任务数据,传递给任务执行时的参数 */ void addCronJob(Class jobClass, String jobName, String data); /** * 暂停任务 - * @param jobName - * @param jobGroup + * 方法用于根据任务名称和任务组,暂停一个正在运行的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 */ void pauseJob(String jobName, String jobGroup); /** * 恢复任务 - * @param triggerName - * @param triggerGroup + * 方法用于根据触发器名称和触发器组,恢复一个已暂停的定时任务。 + * + * @param triggerName 触发器名称 + * @param triggerGroup 触发器组 */ void resumeJob(String triggerName, String triggerGroup); /** - * 删除job - * @param jobName - * @param jobGroup + * 删除任务 + * 方法用于根据任务名称和任务组,删除一个定时任务,包括任务本身和相关的触发器。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 */ void deleteJob(String jobName, String jobGroup); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java index aafdfdb..b34ea8e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java @@ -1,123 +1,186 @@ +// 定义包路径,用于存放任务服务实现类 package com.yf.exam.ability.job.service.impl; -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.yf.exam.ability.job.enums.JobGroup; -import com.yf.exam.ability.job.service.JobService; -import lombok.extern.log4j.Log4j2; -import org.quartz.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; +// 导入所需的外部依赖包 +import com.alibaba.fastjson.JSON; // 用于JSON数据处理 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 用于生成唯一ID +import com.yf.exam.ability.job.enums.JobGroup; // 任务分组枚举 +import com.yf.exam.ability.job.service.JobService; // 任务服务接口 +import lombok.extern.log4j.Log4j2; // 日志注解 +import org.quartz.*; // Quartz定时任务框架相关类 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 +import org.springframework.scheduling.quartz.SchedulerFactoryBean; // Quartz调度器工厂Bean +import org.springframework.stereotype.Service; // Spring服务注解 +import org.springframework.util.StringUtils; // Spring字符串工具类 /** + * 定时任务服务实现类 + * 用于管理系统中的定时任务,包括添加、暂停、恢复和删除任务。 * @author bool */ -@Log4j2 -@Service +@Log4j2 // 启用Log4j2日志 +@Service // 标记为Spring服务组件 public class JobServiceImpl implements JobService { /** - * Quartz定时任务核心的功能实现类 + * Quartz定时任务调度器 + * 用于管理和执行所有的定时任务 */ - private Scheduler scheduler; + private Scheduler scheduler; // 定时任务调度器实例 /** - * 注入 - * @param schedulerFactoryBean + * 构造函数,注入SchedulerFactoryBean + * 从Spring容器中注入Quartz调度器工厂Bean,并从中获取调度器实例。 + * @param schedulerFactoryBean Quartz调度器工厂Bean */ public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) { + // 从工厂Bean中获取调度器实例 scheduler = schedulerFactoryBean.getScheduler(); } - + /** + * 添加定时任务 + * 方法用于添加一个新的定时任务,包括cron表达式和立即执行两种情况。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param cron cron表达式,用于指定任务的执行计划 + * @param data 任务数据,传递给任务执行时的参数 + */ @Override public void addCronJob(Class jobClass, String jobName, String cron, String data) { - - + // 设置任务组为系统任务组 String jobGroup = JobGroup.SYSTEM; - // 自动命名 + // 如果任务名为空,则自动生成任务名 if(StringUtils.isEmpty(jobName)){ - jobName = jobClass.getSimpleName().toUpperCase() + "_"+IdWorker.getIdStr(); + // 使用类名大写+下划线+唯一ID作为任务名 + jobName = jobClass.getSimpleName().toUpperCase() + "_" + IdWorker.getIdStr(); } try { + // 创建任务键,用于唯一标识任务 JobKey jobKey = JobKey.jobKey(jobName, jobGroup); + // 获取任务详情 JobDetail jobDetail = scheduler.getJobDetail(jobKey); + + // 如果任务已存在,则删除旧任务 if (jobDetail != null) { log.info("++++++++++任务:{} 已存在", jobName); this.deleteJob(jobName, jobGroup); } + // 记录任务构建信息 log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data); - //构建job信息 + // 构建新的任务详情 jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build(); - //用JopDataMap来传递数据 + // 设置任务数据 jobDetail.getJobDataMap().put(TASK_DATA, data); - //按新的cronExpression表达式构建一个新的trigger + // 声明触发器 Trigger trigger = null; - // 有表达式的按表达式 + // 如果有cron表达式,则创建cron触发器 if(!StringUtils.isEmpty(cron)){ log.info("+++++表达式执行:"+ JSON.toJSONString(jobDetail)); - //表达式调度构建器 + // 创建cron调度构建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron); - trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build(); + // 构建触发器 + trigger = TriggerBuilder.newTrigger() + .withIdentity(jobName, jobGroup) + .withSchedule(scheduleBuilder) + .build(); }else{ - // 无表达式则立即执行 + // 无cron表达式则立即执行一次 log.info("+++++立即执行:"+ JSON.toJSONString(jobDetail)); - trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build(); + // 构建立即执行的触发器 + trigger = TriggerBuilder.newTrigger() + .withIdentity(jobName, jobGroup) + .startNow() + .build(); } + // 调度任务 scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { + // 打印异常堆栈信息 e.printStackTrace(); } } - + /** + * 添加立即执行的任务 + * 方法用于添加一个不需要cron表达式,立即执行一次的任务。 + * + * @param jobClass 任务类 + * @param jobName 任务名称 + * @param data 任务数据 + */ @Override public void addCronJob(Class jobClass, String jobName, String data) { - // 立即执行任务 + // 立即执行任务,不需要cron表达式,传入null this.addCronJob(jobClass, jobName, null, data); } - + /** + * 暂停任务 + * 方法用于暂停一个正在运行的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void pauseJob(String jobName, String jobGroup) { try { + // 创建触发器键并暂停触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.pauseTrigger(triggerKey); log.info("++++++++++暂停任务:{}", jobName); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } + /** + * 恢复任务 + * 方法用于恢复一个已暂停的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void resumeJob(String jobName, String jobGroup) { try { + // 创建触发器键并恢复触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.resumeTrigger(triggerKey); log.info("++++++++++重启任务:{}", jobName); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } + /** + * 删除任务 + * 方法用于删除一个定时任务,包括任务本身和相关的触发器。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void deleteJob(String jobName, String jobGroup) { try { + // 创建任务键并删除任务 JobKey jobKey = JobKey.jobKey(jobName,jobGroup); scheduler.deleteJob(jobKey); log.info("++++++++++删除任务:{}", jobKey); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java index 3bc2190..8d54a3e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java @@ -1,29 +1,39 @@ +// 定义包路径,用于存放自定义过滤器相关的类 package com.yf.exam.ability.shiro; -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; -import org.apache.shiro.web.filter.InvalidRequestFilter; -import org.apache.shiro.web.filter.mgt.DefaultFilter; -import org.apache.shiro.web.filter.mgt.FilterChainManager; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类,用于配置Shiro过滤器 +import org.apache.shiro.web.filter.InvalidRequestFilter; // Shiro无效请求过滤器,用于处理无效请求 +import org.apache.shiro.web.filter.mgt.DefaultFilter; // Shiro默认过滤器,提供默认的过滤逻辑 +import org.apache.shiro.web.filter.mgt.FilterChainManager; // Shiro过滤器链管理器,管理过滤器链的配置 -import javax.servlet.Filter; -import java.util.Map; +import javax.servlet.Filter; // Servlet过滤器接口,定义了过滤器的基本操作 +import java.util.Map; // Map集合类,用于存储键值对 /** - * 自定义过滤器,用于处理中文URL问题 - * 如:下载文件中包含中文会返回400错误,https://youdomain.com/upload/file/云帆考试系统用户手册.pdf + * 自定义过滤器工厂类,用于创建和管理Shiro过滤器链 + * 主要解决中文URL问题,如下载文件中包含中文字符时可能会返回400错误。 + * 例如:https://youdomain.com/upload/file/云帆考试系统用户手册.pdf 这样的URL可能会因为中文字符而导致问题。 * @author van */ public class CNFilterFactoryBean extends ShiroFilterFactoryBean { + /** + * 创建过滤器链管理器 + * 覆盖父类的创建方法,添加自定义的过滤器配置。 + * @return FilterChainManager 过滤器链管理器实例 + */ @Override protected FilterChainManager createFilterChainManager() { - FilterChainManager manager = super.createFilterChainManager(); - // URL携带中文400,servletPath中文校验bug - Map filterMap = manager.getFilters(); - Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); + FilterChainManager manager = super.createFilterChainManager(); // 调用父类方法创建过滤器链管理器 + + // 获取过滤器映射,以便修改特定过滤器的配置 + Map filterMap = manager.getFilters(); + // 获取无效请求过滤器实例 + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); if (invalidRequestFilter instanceof InvalidRequestFilter) { + // 设置无效请求过滤器不阻止非ASCII字符,以允许中文URL ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); } - return manager; + return manager; // 返回配置好的过滤器链管理器 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java index 76af5c5..d9b5844 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java @@ -1,131 +1,135 @@ +// 定义包路径,用于存放Shiro领域相关的类 package com.yf.exam.ability.shiro; - -import com.yf.exam.ability.shiro.jwt.JwtToken; -import com.yf.exam.ability.shiro.jwt.JwtUtils; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import com.yf.exam.modules.sys.user.service.SysUserRoleService; -import com.yf.exam.modules.sys.user.service.SysUserService; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.authc.AuthenticationException; -import org.apache.shiro.authc.AuthenticationInfo; -import org.apache.shiro.authc.AuthenticationToken; -import org.apache.shiro.authc.SimpleAuthenticationInfo; -import org.apache.shiro.authz.AuthorizationInfo; -import org.apache.shiro.authz.SimpleAuthorizationInfo; -import org.apache.shiro.realm.AuthorizingRealm; -import org.apache.shiro.subject.PrincipalCollection; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; - -import java.util.HashSet; -import java.util.List; +import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 +import com.yf.exam.ability.shiro.jwt.JwtUtils; // JWT工具类 +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 用户登录DTO +import com.yf.exam.modules.sys.user.service.SysUserRoleService; // 用户角色服务 +import com.yf.exam.modules.sys.user.service.SysUserService; // 用户服务 +import lombok.extern.slf4j.Slf4j; // 日志注解 +import org.apache.shiro.authc.AuthenticationException; // 认证异常 +import org.apache.shiro.authc.AuthenticationInfo; // 认证信息 +import org.apache.shiro.authc.AuthenticationToken; // 认证令牌 +import org.apache.shiro.authc.SimpleAuthenticationInfo; // 简单认证信息 +import org.apache.shiro.authz.AuthorizationInfo; // 授权信息 +import org.apache.shiro.authz.SimpleAuthorizationInfo; // 简单授权信息 +import org.apache.shiro.realm.AuthorizingRealm; // 授权领域 +import org.apache.shiro.subject.PrincipalCollection; // 主体集合 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 +import org.springframework.context.annotation.Lazy; // 延迟注入注解 +import org.springframework.stereotype.Component; // Spring组件注解 + +import java.util.HashSet; // 哈希集合 +import java.util.List; // 列表 /** - * 用户登录鉴权和获取用户授权 + * 用户登录鉴权和获取用户授权的Shiro领域类 + * 负责用户的认证和授权,是Shiro框架中的核心组件之一。 * @author bool */ -@Component -@Slf4j +@Component // 标记为Spring组件 +@Slf4j // 启用Slf4j日志 public class ShiroRealm extends AuthorizingRealm { - @Autowired - @Lazy - private SysUserService sysUserService; - - @Autowired - @Lazy - private SysUserRoleService sysUserRoleService; - - - @Override - public boolean supports(AuthenticationToken token) { - return token instanceof JwtToken; - } - - - /** - * 详细授权认证 - * @param principals - * @return - */ - @Override - protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - - String userId = null; - if (principals != null) { - SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); - userId = user.getId(); - } - SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); - - // 查找用户角色 - List roles = sysUserRoleService.listRoles(userId); - info.setRoles(new HashSet<>(roles)); - - log.info("++++++++++校验详细权限完成"); - return info; - } - - /** - * 校验用户的账号密码是否正确 - * @param auth - * @return - * @throws AuthenticationException - */ - @Override - protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { - String token = (String) auth.getCredentials(); - if (token == null) { - throw new AuthenticationException("token为空!"); - } - - // 校验token有效性 - SysUserLoginDTO user = this.checkToken(token); - return new SimpleAuthenticationInfo(user, token, getName()); - } - - - /** - * 校验Token的有效性 - * @param token - * @return - * @throws AuthenticationException - */ - public SysUserLoginDTO checkToken(String token) throws AuthenticationException { - - // 查询用户信息 - log.debug("++++++++++校验用户token: "+ token); - - // 从token中获取用户名 - String username = JwtUtils.getUsername(token); - log.debug("++++++++++用户名: "+ username); - - if (username == null) { - throw new AuthenticationException("无效的token"); - } - - // 查找登录用户对象 - SysUserLoginDTO user = sysUserService.token(token); - - // 校验token是否失效 - if (!JwtUtils.verify(token, username)) { - throw new AuthenticationException("登陆失效,请重试登陆!"); - } - - return user; - } - - - - /** - * 清除当前用户的权限认证缓存 - * @param principals - */ - @Override - public void clearCache(PrincipalCollection principals) { - super.clearCache(principals); + @Autowired + @Lazy // 延迟注入,避免循环依赖 + private SysUserService sysUserService; // 用户服务 + + @Autowired + @Lazy // 延迟注入,避免循环依赖 + private SysUserRoleService sysUserRoleService; // 用户角色服务 + + /** + * 判断是否支持JWT令牌 + * 确定当前领域是否支持处理JWT令牌类型的认证。 + * @param token 认证令牌 + * @return 是否支持JWT令牌 + */ + @Override + public boolean supports(AuthenticationToken token) { + // 判断是否支持JWT令牌 + return token instanceof JwtToken; // 返回是否为JwtToken + } + + /** + * 详细授权认证 + * 获取用户的授权信息,包括角色和权限。 + * @param principals 主体集合 + * @return 授权信息 + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + String userId = null; // 用户ID + if (principals != null) { + SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); // 获取用户信息 + userId = user.getId(); // 获取用户ID + } + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 创建授权信息 + + // 查找用户角色 + List roles = sysUserRoleService.listRoles(userId); // 获取用户角色列表 + info.setRoles(new HashSet<>(roles)); // 设置角色 + + log.info("++++++++++校验详细权限完成"); // 日志记录 + return info; // 返回授权信息 + } + + /** + * 校验用户的账号密码是否正确 + * 根据传入的认证令牌,验证用户的账号密码。 + * @param auth 认证令牌 + * @return 认证信息 + * @throws AuthenticationException 认证异常 + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { + String token = (String) auth.getCredentials(); // 获取token + if (token == null) { + throw new AuthenticationException("token为空!"); // 抛出异常 + } + + // 校验token有效性 + SysUserLoginDTO user = this.checkToken(token); // 验证token并获取用户信息 + return new SimpleAuthenticationInfo(user, token, getName()); // 返回认证信息 + } + + /** + * 校验Token的有效性 + * 验证JWT令牌的有效性,并获取对应的用户信息。 + * @param token JWT令牌 + * @return 用户登录DTO + * @throws AuthenticationException 认证异常 + */ + public SysUserLoginDTO checkToken(String token) throws AuthenticationException { + // 查询用户信息 + log.debug("++++++++++校验用户token: "+ token); // 日志记录 + + // 从token中获取用户名 + String username = JwtUtils.getUsername(token); // 获取用户名 + log.debug("++++++++++用户名: "+ username); // 日志记录 + + if (username == null) { + throw new AuthenticationException("无效的token"); // 抛出异常 + } + + // 查找登录用户对象 + SysUserLoginDTO user = sysUserService.token(token); // 获取用户信息 + + // 校验token是否失效 + if (!JwtUtils.verify(token, username)) { + throw new AuthenticationException("登陆失效,请重试登陆!"); // 抛出异常 + } + + return user; // 返回用户信息 } -} + /** + * 清除当前用户的权限认证缓存 + * 用于在用户信息变更后,清除缓存,确保权限信息的更新。 + * @param principals 主体集合 + */ + @Override + public void clearCache(PrincipalCollection principals) { + super.clearCache(principals); // 清除缓存 + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java index 88cf448..1fe9ff2 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java @@ -1,53 +1,84 @@ +// 定义包路径,用于存放Shiro JWT认证过滤器相关的类 package com.yf.exam.ability.shiro.aop; +// 导入所需的外部依赖包 +import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 +import com.yf.exam.aspect.utils.InjectUtils; // 工具类,用于注入错误信息 +import com.yf.exam.modules.Constant; // 常量类 +import lombok.extern.slf4j.Slf4j; // 日志注解 +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; // Shiro基础认证过滤器 -import com.yf.exam.ability.shiro.jwt.JwtToken; -import com.yf.exam.aspect.utils.InjectUtils; -import com.yf.exam.modules.Constant; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletRequest; // Servlet请求接口 +import javax.servlet.ServletResponse; // Servlet响应接口 +import javax.servlet.http.HttpServletRequest; // HTTP请求类 +import javax.servlet.http.HttpServletResponse; // HTTP响应类 /** - * 鉴权登录拦截器 + * JWT认证过滤器 + * 用于处理基于JWT的身份认证,确保只有持有有效JWT令牌的请求才能访问受保护的资源。 * @author bool */ -@Slf4j +@Slf4j // 启用Slf4j日志 public class JwtFilter extends BasicHttpAuthenticationFilter { - /** - * 执行登录认证 - * @param request - * @param response - * @param mappedValue - * @return - */ - @Override - protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { - try { - executeLogin(request, response); - return true; - } catch (Exception e) { - // 写出统一错误信息 - InjectUtils.restError((HttpServletResponse) response); - return false; - } - } + /** + * 判断是否允许访问 + * 所有的请求都会经过这个方法,用于判断是否需要登录认证。 + * 如果请求不需要认证(如访问公开资源),则直接返回true允许访问; + * 如果需要认证,则尝试执行登录认证,根据认证结果决定是否允许访问。 + * + * @param request 请求对象 + * @param response 响应对象 + * @param mappedValue 映射值 + * @return 是否允许访问 + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + try { + // 尝试执行登录认证 + executeLogin(request, response); + // 认证成功返回true + return true; + } catch (Exception e) { + // 认证失败时写入错误信息 + InjectUtils.restError((HttpServletResponse) response); + // 返回false表示不允许访问 + return false; + } + } + /** + * 执行登录认证 + * 从请求头中获取JWT token并进行认证,如果认证成功,则请求可以继续执行; + * 如果认证失败(如token无效或过期),则抛出异常,由isAccessAllowed方法处理。 + * + * @param request 请求对象 + * @param response 响应对象 + * @return 是否认证成功 + */ + @Override + protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { + // 将ServletRequest转换为HttpServletRequest + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + // 从请求头中获取token + String token = httpServletRequest.getHeader(Constant.TOKEN); - @Override - protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - String token = httpServletRequest.getHeader(Constant.TOKEN); + // 如果token为空,则抛出异常 + if (token == null || "".equals(token)) { + throw new Exception("token不能为空"); + } - JwtToken jwtToken = new JwtToken(token); - // 提交给realm进行登入,如果错误他会抛出异常并被捕获 - getSubject(request, response).login(jwtToken); - // 如果没有抛出异常则代表登入成功,返回true - return true; - } -} + // 创建JWT token对象 + JwtToken jwtToken = new JwtToken(token); + // 提交给realm进行登录认证 + try { + getSubject(request, response).login(jwtToken); + // 如果没有抛出异常则表示登录成功 + return true; + } catch (Exception e) { + // 登录失败,记录日志 + log.error("JWT认证失败", e); + throw e; + } + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java index d5baab3..1e1fe4c 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java @@ -1,33 +1,50 @@ +// 定义包路径,用于存放JWT令牌相关的类 package com.yf.exam.ability.shiro.jwt; - -import lombok.Data; -import org.apache.shiro.authc.AuthenticationToken; + +import lombok.Data; // Lombok注解,用于生成getter和setter +import org.apache.shiro.authc.AuthenticationToken; // Shiro认证令牌接口 /** + * JWT令牌实现类 + * 实现Shiro的AuthenticationToken接口,用于JWT认证 * @author bool */ -@Data +@Data // 自动生成getter和setter方法 public class JwtToken implements AuthenticationToken { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化ID /** - * JWT的字符token + * JWT的字符串token + * 用于存储实际的JWT令牌字符串 */ - private String token; - + private String token; // JWT令牌字符串 + /** + * 构造函数 + * @param token JWT令牌字符串 + */ public JwtToken(String token) { - this.token = token; + this.token = token; // 设置token } + /** + * 获取身份信息 + * 实现AuthenticationToken接口的方法 + * @return 返回token作为身份信息 + */ @Override public Object getPrincipal() { - return token; + return token; // 返回token作为身份信息 } + /** + * 获取凭证信息 + * 实现AuthenticationToken接口的方法 + * @return 返回token作为凭证信息 + */ @Override public Object getCredentials() { - return token; + return token; // 返回token作为凭证信息 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java index 4a66759..ec2d907 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java @@ -1,14 +1,15 @@ +// 定义包路径,用于存放JWT工具类 package com.yf.exam.ability.shiro.jwt; -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.yf.exam.core.utils.file.Md5Util; +import com.auth0.jwt.JWT; // JWT工具类 +import com.auth0.jwt.JWTVerifier; // JWT验证器 +import com.auth0.jwt.algorithms.Algorithm; // JWT算法 +import com.auth0.jwt.exceptions.JWTDecodeException; // JWT解码异常 +import com.auth0.jwt.interfaces.DecodedJWT; // 解码后的JWT +import com.yf.exam.core.utils.file.Md5Util; // MD5工具类 -import java.util.Calendar; -import java.util.Date; +import java.util.Calendar; // 日历类 +import java.util.Date; // 日期类 /** * JWT工具类 @@ -19,81 +20,74 @@ public class JwtUtils { /** * 有效期24小时 */ - private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; - + private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; // JWT有效期 /** * 校验是否正确 - * @param token - * @param username - * @return + * @param token JWT令牌 + * @param username 用户名 + * @return 是否有效 */ public static boolean verify(String token, String username) { try { // 根据密码生成JWT效验器 - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); - JWTVerifier verifier = JWT.require(algorithm) - .withClaim("username", username) - .build(); + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 + JWTVerifier verifier = JWT.require(algorithm) // 创建验证器 + .withClaim("username", username) // 添加用户名声明 + .build(); // 构建验证器 // 效验TOKEN - verifier.verify(token); - return true; + verifier.verify(token); // 验证token + return true; // 返回验证成功 } catch (Exception exception) { - return false; + return false; // 返回验证失败 } } - - - - /** * 从Token中解密获得用户名 - * @param token - * @return + * @param token JWT令牌 + * @return 用户名 */ public static String getUsername(String token) { try { - DecodedJWT jwt = JWT.decode(token); - return jwt.getClaim("username").asString(); + DecodedJWT jwt = JWT.decode(token); // 解码JWT + return jwt.getClaim("username").asString(); // 获取用户名 } catch (JWTDecodeException e) { - return null; + return null; // 返回null表示解码失败 } } /** * 生成JWT Token字符串 - * @param username - * @return + * @param username 用户名 + * @return JWT令牌字符串 */ public static String sign(String username) { - Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); // 设置过期时间 + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 // 附带username信息 - return JWT.create() - .withClaim("username", username) - .withExpiresAt(date).sign(algorithm); - + return JWT.create() // 创建JWT + .withClaim("username", username) // 添加用户名声明 + .withExpiresAt(date).sign(algorithm); // 设置过期时间并签名 } /** * 根据用户名和秘钥,生成一个新的秘钥,用于JWT加强一些安全性 - * @param userName - * @return + * @param userName 用户名 + * @return 加密后的秘钥 */ private static String encryptSecret(String userName){ - // 一个简单的登录规则,用户名+当前月份为加密串,意思每个月会变,要重新登录 // 可自行修改此规则 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - StringBuffer sb = new StringBuffer(userName) - .append("&") - .append(cl.get(Calendar.MONTH)); + Calendar cl = Calendar.getInstance(); // 获取当前日历 + cl.setTimeInMillis(System.currentTimeMillis()); // 设置当前时间 + StringBuffer sb = new StringBuffer(userName) // 创建字符串缓冲区 + .append("&") // 添加分隔符 + .append(cl.get(Calendar.MONTH)); // 添加当前月份 // 获取MD5 - String secret = Md5Util.md5(sb.toString()); + String secret = Md5Util.md5(sb.toString()); // 生成MD5秘钥 - return Md5Util.md5(userName + "&" + secret); + return Md5Util.md5(userName + "&" + secret); // 返回加密后的秘钥 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java index e35d73d..a0cb14b 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java @@ -1,32 +1,36 @@ +// 定义包路径,用于存放文件上传配置相关的类 package com.yf.exam.ability.upload.config; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - +import lombok.Data; // Lombok注解,用于简化数据类的编写,自动生成getter和setter +import org.springframework.boot.context.properties.ConfigurationProperties; // Spring Boot配置属性注解,用于将配置文件中的属性绑定到Java对象 +import org.springframework.context.annotation.Configuration; // Spring配置注解,标记为配置类 /** - * 文件上传配置 + * 文件上传配置类 + * 用于定义文件上传的相关配置,如访问路径、物理目录和允许的文件后缀等。 + * 这些配置通常在application.yml或application.properties中定义,并由Spring Boot自动加载。 * @author van */ -@Data -@Configuration -@ConfigurationProperties(prefix = "conf.upload") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@Configuration // 标记为Spring配置类,表示这是一个配置类 +@ConfigurationProperties(prefix = "conf.upload") // 指定配置文件中属性的前缀,这里是"conf.upload" public class UploadConfig { /** - * 访问路径 + * 文件访问路径 + * 定义文件上传后对外访问的基础URL路径。 */ - private String url; + private String url; // 文件访问的URL /** - * 物理目录 + * 文件存储物理目录 + * 定义文件上传后在服务器上的存储路径。 */ - private String dir; + private String dir; // 文件存储的物理目录 /** - * 允许的后缀 + * 允许的文件后缀 + * 定义允许上传的文件类型,通过文件后缀来限制。 */ - private String [] allowExtensions; - -} + private String[] allowExtensions; // 允许上传的文件后缀 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java index 4c85250..1849a4b 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java @@ -1,57 +1,62 @@ +// 定义包路径,用于存放文件上传下载请求类 package com.yf.exam.ability.upload.controller; +import com.yf.exam.ability.Constant; // 常量类,包含系统配置的常量值 +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 文件上传请求DTO,封装上传文件所需的数据 +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 文件上传响应DTO,封装上传文件后的响应数据 +import com.yf.exam.ability.upload.service.UploadService; // 文件上传服务,提供文件上传和下载的业务逻辑 +import com.yf.exam.core.api.ApiRest; // API响应类,封装统一的API响应格式 +import com.yf.exam.core.api.controller.BaseController; // 基础控制器,提供基础的控制器功能 +import io.swagger.annotations.Api; // Swagger API注解,用于描述API信息 +import io.swagger.annotations.ApiOperation; // Swagger API操作注解,用于描述单个API操作 +import lombok.extern.log4j.Log4j2; // 日志注解,提供日志功能 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解,用于注入Spring管理的Bean +import org.springframework.web.bind.annotation.GetMapping; // GET请求映射注解,用于映射GET请求到方法 +import org.springframework.web.bind.annotation.ModelAttribute; // 模型属性注解,用于将请求参数绑定到模型对象 +import org.springframework.web.bind.annotation.PostMapping; // POST请求映射注解,用于映射POST请求到方法 +import org.springframework.web.bind.annotation.RestController; // REST控制器注解,标记为REST风格的控制器 -import com.yf.exam.ability.Constant; -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; -import com.yf.exam.ability.upload.service.UploadService; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; // HTTP请求类,表示HTTP请求 +import javax.servlet.http.HttpServletResponse; // HTTP响应类,表示HTTP响应 /** * 本地文件上传下载请求类 + * 负责处理文件上传和下载的请求,提供RESTful API接口。 * @author bool */ -@Log4j2 -@Api(tags = {"文件上传"}) -@RestController +@Log4j2 // 启用Log4j2日志 +@Api(tags = {"文件上传"}) // Swagger API标签,用于分类API +@RestController // 标记为REST控制器,表示该类是一个REST风格的控制器 public class UploadController extends BaseController { @Autowired - private UploadService uploadService; + private UploadService uploadService; // 文件上传服务,自动注入 /** * 文件上传 - * @param reqDTO - * @return + * 处理文件上传请求,接收上传文件的数据,并返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应,封装上传文件后的响应数据 */ - @PostMapping("/common/api/file/upload") - @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") + @PostMapping("/common/api/file/upload") // POST请求映射,指定请求路径 + @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") // Swagger API操作描述 public ApiRest upload(@ModelAttribute UploadReqDTO reqDTO) { // 上传并返回URL - UploadRespDTO respDTO = uploadService.upload(reqDTO); - return super.success(respDTO); + UploadRespDTO respDTO = uploadService.upload(reqDTO); // 调用上传服务 + return super.success(respDTO); // 返回成功响应 } /** * 独立文件下载 - * @param request - * @param response + * 处理文件下载请求,根据请求参数返回对应的文件。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 */ - @GetMapping(Constant.FILE_PREFIX+"**") - @ApiOperation(value = "文件下载", notes = "文件下载") + @GetMapping(Constant.FILE_PREFIX+"**") // GET请求映射,指定请求路径前缀 + @ApiOperation(value = "文件下载", notes = "文件下载") // Swagger API操作描述 public void download(HttpServletRequest request, HttpServletResponse response) { - uploadService.download(request, response); + uploadService.download(request, response); // 调用下载服务 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java index df2f286..0e4a0f1 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java @@ -1,22 +1,26 @@ +// 定义包路径,用于存放文件上传请求DTO package com.yf.exam.ability.upload.dto; - -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.springframework.web.multipart.MultipartFile; +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 +import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写,自动生成getter和setter +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 /** * 文件上传请求类 - * @author + * 用于封装文件上传请求中的数据,包括上传的文件内容。 + * @author van * @date 2019-12-26 17:54 */ -@Data -@ApiModel(value="文件上传参数", description="文件上传参数") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@ApiModel(value="文件上传参数", description="文件上传参数") // 使用Swagger注解,描述API模型 public class UploadReqDTO extends BaseDTO { - @ApiModelProperty(value = "上传文件内容", required=true) - private MultipartFile file; - -} + /** + * 上传文件内容 + * 用于存储上传文件的数据,包括文件名、文件类型、文件大小等信息。 + */ + @ApiModelProperty(value = "上传文件内容", required=true) // 使用Swagger注解,描述API模型属性 + private MultipartFile file; // 上传的文件内容 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java index b91106e..cbce697 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java @@ -1,23 +1,28 @@ +// 定义包路径,用于存放文件上传响应DTO package com.yf.exam.ability.upload.dto; -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 +import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 +import lombok.AllArgsConstructor; // 导入Lombok注解,用于生成全参构造函数 +import lombok.Data; // 导入Lombok注解,用于生成getter和setter方法 +import lombok.NoArgsConstructor; // 导入Lombok注解,用于生成无参构造函数 /** - * 上传文件结果 + * 文件上传响应DTO + * 用于封装文件上传操作的结果,包括上传后的文件URL等信息。 * @author bool */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel(value="文件上传响应", description="文件上传响应") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@AllArgsConstructor // 使用Lombok注解,生成全参构造函数 +@NoArgsConstructor // 使用Lombok注解,生成无参构造函数 +@ApiModel(value="文件上传响应", description="文件上传响应") // 使用Swagger注解,描述API模型 public class UploadRespDTO extends BaseDTO { - @ApiModelProperty(value = "上传后的完整的URL地址", required=true) - private String url; - -} + /** + * 上传后的完整URL地址 + * 存储文件上传成功后,文件的完整访问URL地址。 + */ + @ApiModelProperty(value = "上传后的完整的URL地址", required=true) // 使用Swagger注解,描述API模型属性 + private String url; // 上传后的完整URL地址 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java index ef516ec..44617b6 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java @@ -1,30 +1,62 @@ package com.yf.exam.ability.upload.service; +// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.service。 +// 包用于组织和管理相关的Java类,避免类名冲突,方便代码的模块化和复用。 -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO +// 导入了名为UploadReqDTO的类,它位于com.yf.exam.ability.upload.dto包下。 +// 这个类通常用于封装文件上传请求相关的数据,比如要上传的文件信息、上传的相关参数等。 -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO +// 导入了名为UploadRespDTO的类,同样位于com.yf.exam.ability.upload.dto包下。 +// 它主要用于封装文件上传操作完成后返回的响应数据,例如上传是否成功的标识、上传后的文件存储路径等信息。 + +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类 +// 引入了Java EE中用于处理HTTP请求的标准类HttpServletRequest。 +// 在文件下载等操作中,会通过这个类获取客户端发送过来的关于下载请求的各种信息,如请求的URL、请求头信息等。 + +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类 +// 引入了Java EE中用于处理HTTP响应的标准类HttpServletResponse。 +// 在文件下载操作中,会使用这个类来设置响应的状态码、响应头信息以及将文件内容返回给客户端。 /** - * 阿里云OSS业务类 - * @author bool + * 文件上传服务接口 + * 定义文件上传和下载的相关业务操作,提供统一的接口供外部调用。 + * @author bool * @date 2019-07-12 16:45 */ +// 这是一个Java接口的文档注释,用于描述该接口的整体功能和用途。 +// 说明这个接口主要是用来定义与文件上传和下载相关的业务操作方法, +// 并且其他类可以通过实现这个接口来提供具体的实现,以达到统一调用的目的。 +// 同时标注了接口的作者是bool,创建日期是2019年7月12日16:45。 + public interface UploadService { + // 这里定义了一个名为UploadService的公共接口。 + // 接口中只包含方法的声明,不包含方法的具体实现,具体实现由实现该接口的类来完成。 /** * 文件上传 - * @param reqDTO - * @return + * 方法用于处理文件上传请求,接收上传文件的数据,并返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应DTO,封装上传文件后的响应数据 */ + // 这是接口中定义的一个方法声明,名为upload。 + // 它的功能是处理文件上传请求,通过接收传入的UploadReqDTO对象(其中包含了上传文件所需的各种数据), + // 然后在具体实现类中执行实际的上传操作,最后返回一个UploadRespDTO对象,该对象封装了上传文件后的响应数据。 + UploadRespDTO upload(UploadReqDTO reqDTO); /** - * 下载文件 - * @param request - * @param response + * 文件下载 + * 方法用于处理文件下载请求,根据请求参数返回对应的文件。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 */ - void download(HttpServletRequest request, HttpServletResponse response); + // 这是接口中定义的另一个方法声明,名为download。 + // 它用于处理文件下载请求,会接收一个HttpServletRequest对象(其中包含了客户端发送的关于下载请求的所有信息) + // 和一个HttpServletResponse对象(用于设置响应相关的信息并将文件内容返回给客户端), + // 在具体实现类中根据请求参数找到对应的要下载的文件,并通过HttpServletResponse将文件内容返回给客户端。 -} + void download(HttpServletRequest request, HttpServletResponse response); +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java index ef70f40..6d1a60e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java @@ -1,135 +1,143 @@ +// 定义包路径,用于存放文件上传服务实现类 package com.yf.exam.ability.upload.service.impl; -import com.yf.exam.ability.Constant; -import com.yf.exam.ability.upload.config.UploadConfig; -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; -import com.yf.exam.ability.upload.service.UploadService; -import com.yf.exam.ability.upload.utils.FileUtils; -import com.yf.exam.core.exception.ServiceException; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import com.yf.exam.ability.Constant; // 导入常量类,包含系统配置的常量值 +import com.yf.exam.ability.upload.config.UploadConfig; // 导入文件上传配置类,包含文件上传的相关配置 +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO,封装上传文件所需的数据 +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO,封装上传文件后的响应数据 +import com.yf.exam.ability.upload.service.UploadService; // 导入文件上传服务接口,定义文件上传的相关业务操作 +import com.yf.exam.ability.upload.utils.FileUtils; // 导入文件工具类,提供文件操作的辅助功能 +import com.yf.exam.core.exception.ServiceException; // 导入服务异常类,处理业务逻辑中的异常情况 +import lombok.extern.log4j.Log4j2; // 导入日志注解,提供日志功能 +import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,提供文件名和扩展名操作的辅助功能 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring自动注入注解,用于注入Spring管理的Bean +import org.springframework.stereotype.Service; // 导入Spring服务注解,标记为服务组件 +import org.springframework.util.FileCopyUtils; // 导入文件复制工具类,提供文件复制的功能 +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,处理上传的文件 + +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示HTTP请求 +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示HTTP响应 +import java.io.FileOutputStream; // 导入文件输出流,用于将文件内容写入文件 +import java.io.IOException; // 导入IO异常类,处理IO操作中的异常情况 +import java.io.UnsupportedEncodingException; // 导入不支持的编码异常类,处理编码问题 +import java.net.URLDecoder; // 导入URL解码类,用于解码URL +import java.util.regex.Matcher; // 导入正则表达式匹配器,用于匹配正则表达式 +import java.util.regex.Pattern; // 导入正则表达式类,用于编译正则表达式 /** * 文件上传业务类 + * 实现文件上传服务接口,提供文件上传和下载的业务逻辑。 * @author bool * @date 2019-07-30 21:02 */ -@Log4j2 -@Service +@Log4j2 // 使用Log4j2日志注解,启用日志功能 +@Service // 使用Spring服务注解,标记为服务组件 public class UploadServiceImpl implements UploadService { @Autowired - private UploadConfig conf; + private UploadConfig conf; // 自动注入文件上传配置 + /** + * 文件上传 + * 实现文件上传业务逻辑,包括文件验证、文件保存和返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应DTO,封装上传文件后的响应数据 + */ @Override public UploadRespDTO upload(UploadReqDTO reqDTO) { - - // 文件内容 - MultipartFile file = reqDTO.getFile(); + MultipartFile file = reqDTO.getFile(); // 获取上传的文件 // 验证文件后缀 - boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); + boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); // 验证文件后缀 if(!allow){ - throw new ServiceException("文件类型不允许上传!"); + throw new ServiceException("文件类型不允许上传!"); // 抛出异常 } // 上传文件夹 - String fileDir = conf.getDir(); + String fileDir = conf.getDir(); // 获取文件存储目录 // 真实物理地址 String fullPath; try { - // 新文件 - String filePath = FileUtils.processPath(file); + String filePath = FileUtils.processPath(file); // 处理文件路径 // 文件保存地址 - fullPath = fileDir + filePath; + fullPath = fileDir + filePath; // 拼接完整路径 // 创建文件夹 - FileUtils.checkDir(fullPath); + FileUtils.checkDir(fullPath); // 检查并创建文件夹 // 上传文件 - FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); + FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); // 复制文件内容到指定路径 - return this.generateResult(filePath); + return this.generateResult(filePath); // 返回上传结果 } catch (IOException e) { - e.printStackTrace(); - throw new ServiceException("文件上传失败:"+e.getMessage()); + e.printStackTrace(); // 打印异常堆栈 + throw new ServiceException("文件上传失败:"+e.getMessage()); // 抛出异常 } } - - + /** + * 独立文件下载 + * 实现文件下载业务逻辑,包括获取文件真实路径和返回文件内容。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 + */ @Override public void download(HttpServletRequest request, HttpServletResponse response) { - // 获取真实的文件路径 - String filePath = this.getRealPath(request.getRequestURI()); + String filePath = this.getRealPath(request.getRequestURI()); // 获取文件的真实路径 // 处理中文问题 try { - filePath = URLDecoder.decode(filePath, "utf-8"); + filePath = URLDecoder.decode(filePath, "utf-8"); // 解码文件路径 } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); // 抛出运行时异常 } - System.out.println("++++完整路径为:"+filePath); + System.out.println("++++完整路径为:"+filePath); // 打印完整路径 try { - FileUtils.writeRange(request, response, filePath); + FileUtils.writeRange(request, response, filePath); // 调用文件工具类进行文件写入 } catch (IOException e) { - response.setStatus(404); - log.error("预览文件失败" + e.getMessage()); + response.setStatus(404); // 设置响应状态为404 + log.error("预览文件失败" + e.getMessage()); // 打印错误日志 } } - /** * 构造返回 - * @param fileName - * @return + * 根据文件名构造上传响应DTO,包含上传后的完整URL地址。 + * + * @param fileName 文件名 + * @return 上传响应DTO */ private UploadRespDTO generateResult(String fileName) { - //获取加速域名 - String domain = conf.getUrl(); + String domain = conf.getUrl(); // 获取文件访问的URL // 返回结果 - return new UploadRespDTO(domain + fileName); + return new UploadRespDTO(domain + fileName); // 返回上传响应DTO } - /** * 获取真实物理文件地址 - * @param uri - * @return + * 根据请求URI获取文件的真实物理路径。 + * + * @param uri 请求URI + * @return 真实文件路径 */ public String getRealPath(String uri){ - - String regx = Constant.FILE_PREFIX+"(.*)"; + String regx = Constant.FILE_PREFIX+"(.*)"; // 正则表达式匹配文件路径 // 查找全部变量 - Pattern pattern = Pattern.compile(regx); - Matcher m = pattern.matcher(uri); + Pattern pattern = Pattern.compile(regx); // 编译正则表达式 + Matcher m = pattern.matcher(uri); // 创建匹配器 if (m.find()) { - String str = m.group(1); - return conf.getDir() + str; + String str = m.group(1); // 获取匹配的文件路径 + return conf.getDir() + str; // 返回真实文件路径 } - return null; + return null; // 返回null表示未找到 } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java index 539ecb0..0c45c41 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java @@ -1,172 +1,169 @@ +// 定义包路径,用于存放文件工具类 package com.yf.exam.ability.upload.utils; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.yf.exam.core.utils.DateUtils; -import org.apache.commons.io.FilenameUtils; -import org.springframework.web.multipart.MultipartFile; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入ID生成工具,用于生成唯一的文件名 +import com.yf.exam.core.utils.DateUtils; // 导入日期工具类,用于处理日期相关的操作 +import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,用于处理文件名和扩展名 +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Date; +import javax.servlet.ServletOutputStream; // 导入Servlet输出流,用于写入HTTP响应 +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示客户端的请求 +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示服务器的响应 +import java.io.File; // 导入文件类,用于操作文件和目录 +import java.io.IOException; // 导入IO异常类,处理IO操作中的异常 +import java.io.RandomAccessFile; // 导入随机访问文件类,用于高效地读写文件 +import java.util.Date; // 导入日期类,用于处理日期和时间 /** * 文件工具类 + * 提供文件操作的辅助功能,包括文件上传、下载、重命名和目录管理等。 * @author bool */ public class FileUtils { - /** - * 后缀分割符号 - */ - private static final String SUFFIX_SPLIT = "."; - - - /** - * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 - * @param request - * @param response - * @param filePath - * @throws IOException - */ - public static void writeRange(HttpServletRequest request, - HttpServletResponse response, String filePath) throws IOException { - - // 读取文件 - File file = new File(filePath); - - //只读模式 - RandomAccessFile randomFile = new RandomAccessFile(file, "r"); - long contentLength = randomFile.length(); - String range = request.getHeader("Range"); - int start = 0, end = 0; - if (range != null && range.startsWith("bytes=")) { - String[] values = range.split("=")[1].split("-"); - start = Integer.parseInt(values[0]); - if (values.length > 1) { - end = Integer.parseInt(values[1]); - } - } - int requestSize; - if (end != 0 && end > start) { - requestSize = end - start + 1; - } else { - requestSize = Integer.MAX_VALUE; - } - - byte[] buffer = new byte[128]; - response.setContentType(MediaUtils.getContentType(filePath)); - response.setHeader("Accept-Ranges", "bytes"); - response.setHeader("ETag", file.getName()); - response.setHeader("Last-Modified", new Date().toString()); - //第一次请求只返回content length来让客户端请求多次实际数据 - if (range == null) { - response.setHeader("Content-length", contentLength + ""); - } else { - //以后的多次以断点续传的方式来返回视频数据 - response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - long requestStart = 0, requestEnd = 0; - String[] ranges = range.split("="); - if (ranges.length > 1) { - String[] rangeData = ranges[1].split("-"); - requestStart = Integer.parseInt(rangeData[0]); - if (rangeData.length > 1) { - requestEnd = Integer.parseInt(rangeData[1]); - } - } - long length; - if (requestEnd > 0) { - length = requestEnd - requestStart + 1; - response.setHeader("Content-length", "" + length); - response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); - } else { - length = contentLength - requestStart; - response.setHeader("Content-length", "" + length); - response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); - } - } - ServletOutputStream out = response.getOutputStream(); - int needSize = requestSize; - randomFile.seek(start); - while (needSize > 0) { - int len = randomFile.read(buffer); - if (needSize < buffer.length) { - out.write(buffer, 0, needSize); - } else { - out.write(buffer, 0, len); - if (len < buffer.length) { - break; - } - } - needSize -= buffer.length; - } - randomFile.close(); - out.close(); - } - - - - - /** - * 重命名文件 - * @param fileName - * @return - */ - public static String renameFile(String fileName) { - - //没有后缀名不处理 - if (!fileName.contains(SUFFIX_SPLIT)) { - return fileName; - } - - //文件后缀 - String extension = FilenameUtils.getExtension(fileName); - - //以系统时间命名 - return IdWorker.getIdStr() + "."+ extension; - - } - - - /** - * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 - * @param file 文件 - * @return - */ - public static String processPath(MultipartFile file){ - - // 创建OSSClient实例。 - String fileName = file.getOriginalFilename(); - - // 需要重命名 - fileName = renameFile(fileName); - - //获得上传的文件夹 - String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); - - return new StringBuffer(dir).append(fileName).toString(); - - } - - /** - * 检查文件夹是否存在,不存在则创建 - * @param fileName - * @return - */ - public static void checkDir(String fileName){ - int index = fileName.lastIndexOf("/"); - if(index == -1){ - return; - } - - File file = new File(fileName.substring(0,index)); - if(!file.exists()){ - file.mkdirs(); - } - } - - -} + /** + * 后缀分割符号 + * 用于分割文件名和扩展名。 + */ + private static final String SUFFIX_SPLIT = "."; // 文件后缀分隔符 + + /** + * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 + * 方法用于处理HTTP请求,以断点续传的方式输出文件内容,支持文件在线预览和视频在线播放。 + * + * @param request HTTP请求,包含客户端的请求信息 + * @param response HTTP响应,包含服务器的响应信息 + * @param filePath 文件路径,指定要输出的文件 + * @throws IOException IO异常,处理文件操作中的异常 + */ + public static void writeRange(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException { + // 读取文件 + File file = new File(filePath); // 创建文件对象 + + // 只读模式 + RandomAccessFile randomFile = new RandomAccessFile(file, "r"); // 创建随机访问文件对象 + long contentLength = randomFile.length(); // 获取文件长度 + String range = request.getHeader("Range"); // 获取请求头中的Range + int start = 0, end = 0; // 初始化起始和结束位置 + if (range != null && range.startsWith("bytes=")) { + String[] values = range.split("=")[1].split("-"); // 解析Range + start = Integer.parseInt(values[0]); // 获取起始位置 + if (values.length > 1) { + end = Integer.parseInt(values[1]); // 获取结束位置 + } + } + int requestSize; // 请求大小 + if (end != 0 && end > start) { + requestSize = end - start + 1; // 计算请求大小 + } else { + requestSize = Integer.MAX_VALUE; // 设置为最大值 + } + + byte[] buffer = new byte[128]; // 创建缓冲区 + response.setContentType(MediaUtils.getContentType(filePath)); // 设置响应内容类型 + response.setHeader("Accept-Ranges", "bytes"); // 设置支持的范围 + response.setHeader("ETag", file.getName()); // 设置文件名 + response.setHeader("Last-Modified", new Date().toString()); // 设置最后修改时间 + // 第一次请求只返回content length来让客户端请求多次实际数据 + if (range == null) { + response.setHeader("Content-length", contentLength + ""); // 设置内容长度 + } else { + // 以后的多次以断点续传的方式来返回视频数据 + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 设置部分内容状态 + long requestStart = 0, requestEnd = 0; // 初始化请求起始和结束位置 + String[] ranges = range.split("="); // 解析Range + if (ranges.length > 1) { + String[] rangeData = ranges[1].split("-"); // 获取范围数据 + requestStart = Integer.parseInt(rangeData[0]); // 获取请求起始位置 + if (rangeData.length > 1) { + requestEnd = Integer.parseInt(rangeData[1]); // 获取请求结束位置 + } + } + long length; // 请求长度 + if (requestEnd > 0) { + length = requestEnd - requestStart + 1; // 计算请求长度 + response.setHeader("Content-length", "" + length); // 设置内容长度 + response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); // 设置内容范围 + } else { + length = contentLength - requestStart; // 计算请求长度 + response.setHeader("Content-length", "" + length); // 设置内容长度 + response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); // 设置内容范围 + } + } + ServletOutputStream out = response.getOutputStream(); // 获取输出流 + int needSize = requestSize; // 需要的大小 + randomFile.seek(start); // 移动到起始位置 + while (needSize > 0) { + int len = randomFile.read(buffer); // 读取文件内容 + if (needSize < buffer.length) { + out.write(buffer, 0, needSize); // 写入需要的大小 + } else { + out.write(buffer, 0, len); // 写入缓冲区内容 + if (len < buffer.length) { + break; // 如果读取的长度小于缓冲区长度,退出循环 + } + } + needSize -= buffer.length; // 减少需要的大小 + } + randomFile.close(); // 关闭随机访问文件 + out.close(); // 关闭输出流 + } + + /** + * 重命名文件 + * 方法用于生成新的文件名,避免文件名冲突。 + * + * @param fileName 文件名 + * @return 新文件名 + */ + public static String renameFile(String fileName) { + // 没有后缀名不处理 + if (!fileName.contains(SUFFIX_SPLIT)) { + return fileName; // 返回原文件名 + } + + // 文件后缀 + String extension = FilenameUtils.getExtension(fileName); // 获取文件后缀 + + // 以系统时间命名 + return IdWorker.getIdStr() + "." + extension; // 返回新文件名 + } + + /** + * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 + * 方法用于处理上传文件的路径,根据当前日期生成目录结构。 + * + * @param file 文件 + * @return 处理后的文件路径 + */ + public static String processPath(MultipartFile file) { + // 创建OSSClient实例。 + String fileName = file.getOriginalFilename(); // 获取原始文件名 + + // 需要重命名 + fileName = renameFile(fileName); // 重命名文件 + + // 获得上传的文件夹 + String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); // 获取当前日期格式化后的目录 + + return new StringBuffer(dir).append(fileName).toString(); // 返回处理后的文件路径 + } + + /** + * 检查文件夹是否存在,不存在则创建 + * 方法用于检查指定的文件夹是否存在,如果不存在则创建。 + * + * @param fileName 文件名 + */ + public static void checkDir(String fileName) { + int index = fileName.lastIndexOf("/"); // 获取最后一个斜杠的位置 + if (index == -1) { + return; // 如果没有斜杠,返回 + } + + File file = new File(fileName.substring(0, index)); // 创建文件对象 + if (!file.exists()) { + file.mkdirs(); // 如果文件夹不存在,创建文件夹 + } + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java index b4394c0..aff5557 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java @@ -1,47 +1,75 @@ package com.yf.exam.ability.upload.utils; +// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.utils。 +// 包用于对相关的Java类进行组织和管理,方便代码的分类、复用以及避免类名冲突。 -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类,用于字符串操作 +// 引入了Apache Commons Lang库中的StringUtils类。 +// 这个类提供了许多方便的字符串操作方法,比如判断字符串是否为空、是否空白(包含空格等空白字符)、字符串的拼接、截取等操作,在这里主要用于对文件路径字符串进行相关判断。 -import java.util.HashMap; -import java.util.Map; +import java.util.HashMap; // 导入Java的HashMap类,用于创建映射 +// 导入了Java标准库中的HashMap类。 +// HashMap是实现了Map接口的一个具体类,它用于存储键值对形式的数据,通过键可以快速获取对应的值,在这里用于创建文件后缀名到MIME类型的映射关系。 + +import java.util.Map; // 导入Java的Map接口,用于键值对映射 +// 引入了Java标准库中的Map接口。 +// Map接口定义了键值对数据结构的通用操作规范,如添加键值对、根据键获取值、删除键值对等操作。 +// 虽然这里同时导入了HashMap类,但导入Map接口使得代码在使用映射数据结构时更具通用性,方便后续可能的替换为其他实现Map接口的类。 /** - * 媒体工具,判断媒体类型 - * @author bool + * 媒体工具类,用于判断和获取媒体文件的MIME类型 + * 该类提供了一个静态映射,用于将文件后缀名映射到对应的MIME类型,以便在处理文件上传和下载时确定正确的媒体类型。 + * @author bool * @date 2019-11-14 16:21 */ -public class MediaUtils { +// 这是一个Java类的文档注释,用于描述该类的整体功能和用途。 +// 说明这个类主要是作为媒体工具类,其核心功能是判断和获取媒体文件的MIME类型。 +// 通过维护一个静态的映射关系(文件后缀名到MIME类型的映射),在文件上传和下载的业务场景中,能够依据文件的后缀名准确地确定其对应的MIME类型,从而正确处理文件的传输和展示等操作。 +// 同时标注了类的作者是bool,创建日期是2019年11月14日16:21。 - public static final Map MEDIA_MAP = new HashMap(){ - { +public class MediaUtils { - //本来是pdf的 - put(".pdf", "application/pdf"); + /** + * 媒体类型映射 + * 静态映射,包含文件后缀名到MIME类型的映射。 + */ + // 这是对下面定义的MEDIA_MAP成员变量的文档注释,说明它是一个静态的映射,用于存储文件后缀名和对应的MIME类型之间的映射关系。 - //视频 - put(".mp4", "video,video/mp4"); - - } - }; + public static final Map MEDIA_MAP = new HashMap() {{ + // 初始化映射 + // PDF文件的MIME类型 + put(".pdf", "application/pdf"); + // 视频文件的MIME类型 + put(".mp4", "video/mp4"); + }}; + // 这里定义了一个名为MEDIA_MAP的公共静态最终变量,它是一个HashMap类型的映射。 + // 通过匿名内部类的初始化方式,在创建HashMap实例的同时向其中添加了一些常见的文件后缀名到MIME类型的映射关系,比如将".pdf"后缀名映射到"application/pdf"这个MIME类型,将".mp4"后缀名映射到"video/mp4"这个MIME类型。 + // 由于被声明为静态最终变量,它在类加载时就会被初始化,并且其值不能再被修改,方便在整个类的其他地方直接使用这个映射关系来获取文件的MIME类型。 /** - * 获得文件类型 - * @param filePath - * @return + * 根据文件路径获取文件的MIME类型 + * 方法根据文件的后缀名,从MEDIA_MAP中获取对应的MIME类型。 + * + * @param filePath 文件路径 + * @return 文件的MIME类型 */ - public static String getContentType(String filePath){ - - if(!StringUtils.isBlank(filePath) - && filePath.indexOf(".")!=-1) { + // 这是对下面定义的getContentType方法的文档注释,说明该方法的功能是根据传入的文件路径,提取出文件的后缀名,然后从MEDIA_MAP这个静态映射中获取对应的MIME类型并返回。 - // 后缀转换成小写 + public static String getContentType(String filePath) { + if (!StringUtils.isBlank(filePath) && filePath.indexOf(".")!= -1) { + // 提取文件后缀名,并转换为小写 String suffix = filePath.substring(filePath.lastIndexOf(".")).toLowerCase(); + // 从映射中获取MIME类型 if (MEDIA_MAP.containsKey(suffix)) { return MEDIA_MAP.get(suffix); } } + // 如果没有找到对应的MIME类型,返回默认值 return "application/octet-stream"; } -} + // 这是定义的一个公共静态方法getContentType,它接受一个字符串类型的参数filePath,表示文件的路径。 + // 首先,通过StringUtils.isBlank方法判断文件路径是否不为空且包含小数点(即有文件后缀名)。 + // 如果满足条件,就使用substring方法从文件路径中提取出文件的后缀名,并通过toLowerCase方法将其转换为小写形式。 + // 然后,检查提取出的后缀名是否存在于MEDIA_MAP这个静态映射中,如果存在,就返回对应的MIME类型;如果不存在,就返回默认的MIME类型"application/octet-stream",这个默认值通常用于表示未知类型的二进制数据文件。 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java index 441a154..a85ec9a 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java +++ b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java @@ -1,156 +1,189 @@ package com.yf.exam.aspect; +// 导入FastJSON库,用于将Java对象转换为JSON字符串以及从JSON字符串解析为Java对象等操作, +// 在本类的多个方法中用于对象与JSON字符串之间的转换,以便于处理数据字典相关的值。 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; + +// 导入MyBatis Plus的接口,用于处理分页相关的数据结构,在本类中用于判断和处理分页数据中的数据字典值。 import com.baomidou.mybatisplus.core.metadata.IPage; + +// 导入Jackson库的注解,用于指定日期格式的序列化和反序列化方式, +// 在本类的parseObject方法中用于根据注解设置日期字段的格式化输出。 import com.fasterxml.jackson.annotation.JsonFormat; + +// 导入自定义的注解,可能用于标记与数据字典相关的字段,以便在本类中识别并处理这些字段的数据字典值。 import com.yf.exam.core.annon.Dict; + +// 导入自定义的API响应类,用于封装API调用的返回结果,包括数据、状态码等信息, +// 在本类的多个方法中用于获取和设置返回结果中的数据部分,以便处理其中的数据字典值。 import com.yf.exam.core.api.ApiRest; + +// 导入自定义的反射工具类,可能用于获取对象的所有字段等反射相关操作, +// 在本类的parseObject方法中用于获取对象的所有字段以便遍历处理数据字典值。 import com.yf.exam.core.utils.Reflections; + +// 导入系统数据字典服务类,用于查询数据字典表以获取数据字典值的翻译文本, +// 在本类的translateDictValue方法中用于根据字典代码、文本、表名和键值查询对应的字典文本。 import com.yf.exam.modules.sys.system.service.SysDictService; -import lombok.extern.slf4j.Slf4j; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 +import lombok.extern.log4j.Log4j2; + +// 导入AspectJ的相关类,用于定义切面、切点和环绕通知等AOP相关的操作, +// 在本类中用于实现对特定方法的拦截和处理,以实现数据字典值的翻译等功能。 import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; + +// 导入Spring框架的注解,用于自动注入依赖对象和标记类为Spring组件, +// 在本类中通过@Autowired注入SysDictService对象,并通过@Component标记本类为Spring组件,使其可被Spring容器管理。 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; + +// 导入Spring框架的工具类,用于判断字符串是否为空等操作, +// 在本类的多个方法中用于判断字符串是否为空,以便进行相应的处理逻辑。 import org.springframework.util.StringUtils; +// 导入Java标准库中的反射相关类,用于通过反射操作对象的字段、获取类型信息等, +// 在本类的多个方法中广泛用于获取对象的字段、判断字段类型、获取字段注解等操作。 import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; + +// 导入Java标准库中的日期格式化类和日期类,用于处理日期格式的转换和操作, +// 在本类的parseObject方法中用于根据注解或默认格式对日期字段进行格式化输出。 import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** - * 数据字典AOP类,处理数据字典值 + * 数据字典AOP类,主要功能是处理数据字典值。通过拦截特定的方法调用, + * 对返回结果中的数据字典相关字段进行翻译、格式化等处理,以提供更友好的展示效果。 * * @author bool */ -@Aspect -@Component -@Slf4j +@Aspect // 标记该类为一个AspectJ切面类,用于定义切面相关的逻辑。 +@Component // 标记该类为Spring组件,使其能够被Spring容器管理和实例化,以便在应用中使用。 +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 public class DictAspect { @Autowired - private SysDictService sysDictService; + private SysDictService sysDictService; // 通过自动注入获取系统数据字典服务对象,用于查询数据字典值。 /** - * 切入Controller执行 - * @param pjp - * @return - * @throws Throwable + * 定义一个环绕通知,切入到指定的Controller方法执行前后。 + * 这里的切点表达式指定了拦截所有在com.yf.exam包及其子包下的所有Controller类中的所有公有方法。 + * + * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 + * @return 返回结果,经过处理后的方法执行结果,可能经过了数据字典值的处理等操作。 + * @throws Throwable 如果在环绕通知的执行过程中出现异常,则抛出。 */ @Around("execution(public * com.yf.exam..*.*Controller.*(..))") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { - return this.translate(pjp); + return this.translate(pjp); // 调用translate方法对被拦截方法的执行结果进行处理,主要是处理数据字典值。 } /** - * 进行翻译并返回,调用前必须实现:BaseDictService + * 对被拦截方法的执行结果进行翻译处理,并返回处理后的结果。 + * 在调用此方法之前,通常需要确保相关的BaseDictService(可能是数据字典相关的基础服务)已经实现。 * - * @param pjp - * @return - * @throws Throwable + * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 + * @return 返回结果,经过数据字典值处理后的方法执行结果。 + * @throws Throwable 如果在处理过程中出现异常,则抛出。 */ public Object translate(ProceedingJoinPoint pjp) throws Throwable { - // 处理字典 + // 调用被拦截方法获取原始结果,然后调用parseAllDictText方法对结果进行数据字典值的处理。 return this.parseAllDictText(pjp.proceed()); } /** - * 转换全部数据字典 + * 根据结果对象的类型,判断是否需要对其进行数据字典值的处理。 + * 如果结果对象是ApiRest类型,则调用parseFullDictText方法进行完整的数据字典值处理。 * - * @param result + * @param result 结果对象,即被拦截方法执行后的返回结果。 */ private Object parseAllDictText(Object result) { - - // 非ApiRest类型不处理 + // 判断结果对象是否是ApiRest类型,如果是则进行数据字典值的处理。 if (result instanceof ApiRest) { parseFullDictText(result); } - return result; } - /** - * 转换所有类型的数据字典、包含子列表 + * 对ApiRest类型的结果对象进行完整的数据字典值处理,包括处理分页数据、列表数据以及单对象数据等情况。 * - * @param result + * @param result 结果对象,即ApiRest类型的返回结果,其中包含了要处理的数据部分。 */ private void parseFullDictText(Object result) { - try { + Object rest = ((ApiRest) result).getData(); // 获取ApiRest对象中的数据部分,这部分数据可能包含数据字典相关字段。 - Object rest = ((ApiRest) result).getData(); - - // 不处理普通数据类型 + // 如果数据部分为空或者是基本数据类型,则不需要进行数据字典值的处理,直接返回。 if (rest == null || this.isBaseType(rest.getClass())) { return; } - // 分页的 + // 如果数据部分是分页数据类型(IPage),则对分页数据中的每条记录进行数据字典值处理。 if (rest instanceof IPage) { List items = new ArrayList<>(16); for (Object record : ((IPage) rest).getRecords()) { - Object item = this.parseObject(record); + Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 items.add(item); } - ((IPage) rest).setRecords(items); + ((IPage) rest).setRecords(items); // 将处理后的记录列表重新设置回分页对象中。 return; } - // 数据列表的 + // 如果数据部分是列表数据类型(List),则对列表中的每条记录进行数据字典值处理。 if (rest instanceof List) { List items = new ArrayList<>(); for (Object record : ((List) rest)) { - Object item = this.parseObject(record); + Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 items.add(item); } - // 重新回写值 + // 将处理后的记录列表重新设置回ApiRest对象的数据部分。 ((ApiRest) result).setData(items); return; } - // 处理单对象 + // 如果数据部分是单对象数据,则对该单对象进行数据字典值处理。 Object item = this.parseObject(((ApiRest) result).getData()); ((ApiRest) result).setData(item); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(); // 如果在处理过程中出现异常,则打印异常堆栈信息。 } } /** - * 处理数据字典值 + * 对单个记录对象进行数据字典值处理,包括处理列表字段、带有数据字典注解的普通字段以及日期字段等情况。 * - * @param record - * @return + * @param record 记录对象,即要进行数据字典值处理的对象。 + * @return 处理后的对象,经过数据字典值处理后的记录对象。 */ public Object parseObject(Object record) { - if (record == null) { return null; } - // 不处理普通数据类型 + // 如果记录对象是基本数据类型,则不需要进行数据字典值处理,直接返回原对象。 if (this.isBaseType(record.getClass())) { return record; } - // 转换JSON字符 + // 将记录对象转换为JSON字符串,再解析为JSONObject对象,以便于通过字段名获取和设置值。 String json = JSON.toJSONString(record); JSONObject item = JSONObject.parseObject(json); - for (Field field : Reflections.getAllFields(record)) { + for (Field field : Reflections.getAllFields(record)) { // 遍历记录对象的所有字段。 - // 如果是List类型 + // 如果字段类型是List类型,则对列表字段进行特殊处理。 if (List.class.isAssignableFrom(field.getType())) { try { - List list = this.processList(field, item.getObject(field.getName(), List.class)); + List list = this.processList(field, item.getObject(field.getName(), List.class)); // 调用processList方法处理列表字段。 item.put(field.getName(), list); continue; } catch (Exception e) { @@ -159,14 +192,14 @@ public class DictAspect { continue; } - // 处理普通字段 - if (field.getAnnotation(Dict.class) != null) { + // 如果字段带有数据字典注解(Dict),则对该字段进行数据字典值的翻译处理。 + if (field.getAnnotation(Dict.class)!= null) { String code = field.getAnnotation(Dict.class).dicCode(); String text = field.getAnnotation(Dict.class).dicText(); String table = field.getAnnotation(Dict.class).dictTable(); String key = String.valueOf(item.get(field.getName())); - //翻译字典值对应的txt + // 调用translateDictValue方法翻译字典值对应的文本,根据字典代码、文本、表名和键值查询对应的字典文本。 String textValue = this.translateDictValue(code, text, table, key); if (StringUtils.isEmpty(textValue)) { textValue = ""; @@ -175,24 +208,22 @@ public class DictAspect { continue; } - //日期格式转换 - if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName()) != null) { - - // 获取注解 + // 如果字段类型是日期类型(java.util.Date)且字段值不为空,则对日期字段进行格式转换处理。 + if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName())!= null) { + // 获取字段上的JsonFormat注解。 JsonFormat ann = field.getAnnotation(JsonFormat.class); - // 格式化方式 + // 定义日期格式化对象。 SimpleDateFormat fmt; - // 使用注解指定的 - if (ann != null && !StringUtils.isEmpty(ann.pattern())) { + // 如果注解不为空且指定了日期格式模式,则使用注解指定的格式创建日期格式化对象。 + if (ann!= null &&!StringUtils.isEmpty(ann.pattern())) { fmt = new SimpleDateFormat(ann.pattern()); } else { - // 默认时间样式 + // 如果注解为空或未指定格式,则使用默认的日期格式创建日期格式化对象。 fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } item.put(field.getName(), fmt.format(new Date((Long) item.get(field.getName())))); continue; - } } @@ -200,49 +231,53 @@ public class DictAspect { } /** - * 获得类型为List的值 + * 处理类型为List的字段,对列表中的每个元素进行数据字典值处理等操作。 * - * @param field - * @return + * @param field 字段对象,即要处理的List类型字段。 + , + * @param list 列表对象,即字段对应的列表值。 + * @return 处理后的列表,经过数据字典值处理后的列表对象。 */ private List processList(Field field, List list) { - - // 空判断 + // 如果列表为空,则返回一个空的ArrayList对象。 if (list == null || list.size() == 0) { return new ArrayList<>(); } - // 获得List属性的真实类 + // 获取List属性的真实类型,通过反射获取字段的泛型类型,再尝试获取其实际的类型参数。 Type genericType = field.getGenericType(); Class actualType = null; if (genericType instanceof ParameterizedType) { - // 尝试获取数据类型 ParameterizedType pt = (ParameterizedType) genericType; try { actualType = (Class) pt.getActualTypeArguments()[0]; - }catch (Exception e){ + } catch (Exception e) { return list; } } - // 常规列表无需处理 + // 如果列表元素的类型是基本数据类型,则不需要进行数据字典值处理,直接返回原列表。 if (isBaseType(actualType)) { return list; } - // 返回列表 + // 创建一个新的ArrayList对象,用于存储处理后的列表元素。 List result = new ArrayList<>(16); for (int i = 0; i < list.size(); i++) { - // 创建实例-->赋值-->字典处理 + // 获取列表中的每个元素。 Object data = list.get(i); try { + // 将列表元素转换为JSON字符串,再解析为其真实类型的对象,以便进行数据字典值处理。 data = JSON.parseObject(JSON.toJSONString(data), actualType); - }catch (Exception e){ - // 转换出错不处理 + } catch (Exception e) { + // 如果转换过程中出现错误,则不进行处理,直接使用原元素。 + // 这里可以根据实际需求进一步处理错误情况,比如记录日志等。 + // 目前只是简单地忽略错误,继续处理下一个元素。 + ; } - // 处理后的数据 + // 对处理后的元素进行数据字典值处理,调用parseObject方法。 Object pds = this.parseObject(data); result.add(pds); } @@ -251,23 +286,25 @@ public class DictAspect { } /** - * 翻译实现 + , + * 根据字典代码、文本、表名和键值翻译数据字典值对应的文本。 * - * @param code - * @param text - * @param table - * @param key - * @return + * @param code 字典代码,用于在数据字典表中定位特定的字典项。 + * @param text 字典文本,可能是与字典代码相关的描述信息等。 + * @param table 字典表名,指定要查询的数据字典表。 + * @param key 字典键值,用于在字典表中查找对应的字典项。 + * @return 翻译后的值,即根据字典代码、文本、表名和键值查询到的字典文本值,如果未找到则返回空字符串。 */ - private String translateDictValue(String code, String text, String table, String key) { + private String translateDictValue(String code, String text, String table, String键值) { if (StringUtils.isEmpty(key)) { return null; } try { - // 翻译值 + // 定义变量用于存储翻译后的字典文本值。 String dictText = null; if (!StringUtils.isEmpty(table)) { - dictText = sysDictService.findDict(table, text, code, key.trim()); + // 如果字典表名不为空,则调用sysDictService的findDict方法查询数据字典表,获取对应的字典文本值。 + dictText = sysDictService.findDict(table, text, code, key.trim()); } if (!StringUtils.isEmpty(dictText)) { @@ -280,15 +317,13 @@ public class DictAspect { } /** - * 判断是否基本类型 + * 判断给定的类是否是基本数据类型,包括常见的整数、字节、长整数、双精度浮点数、单精度浮点数、字符、短整数、布尔值以及字符串和数字类型等。 * - * @param clazz - * @return + * @param clazz 要判断的类对象。 + * @return 是否基本类型,如果是基本数据类型则返回true,否则返回false。 */ private boolean isBaseType(Class clazz) { - - - // 基础数据类型 + // 判断是否是常见的基本数据类型,如整数、字节、长整数等。 if (clazz.equals(java.lang.Integer.class) || clazz.equals(java.lang.Byte.class) || clazz.equals(java.lang.Long.class) || @@ -300,18 +335,16 @@ public class DictAspect { return true; } - // String类型 + // 判断是否是字符串类型。 if (clazz.equals(java.lang.String.class)) { return true; } - // 数字 + // 判断是否是数字类型(这里的数字类型可能是指抽象的数字类型,比如Number的子类等)。 if (clazz.equals(java.lang.Number.class)) { return true; } return false; } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java index 6b958ca..2ca40a4 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java @@ -1,144 +1,255 @@ package com.yf.exam.aspect.mybatis; +// 导入MyBatis Plus的分页拦截器类,用于实现分页功能, +// 本类继承自该类以在拦截查询操作时能正确处理分页相关逻辑。 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; + +// 导入系统用户登录信息的数据传输对象(DTO)类,用于获取当前登录用户的相关信息, +// 比如在处理查询拦截时可能需要根据登录用户的信息来过滤或修改查询语句。 import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入JSqlParser库中的解析器管理器类,用于解析SQL语句, +// 在本类中用于解析查询语句以便进行后续的处理,如替换用户ID等操作。 import net.sf.jsqlparser.parser.CCJSqlParserManager; + +// 导入JSqlParser库中表示简单查询语句的类,它是查询语句的一种具体表示形式, +// 在解析查询语句后可以获取到该对象来进一步处理查询语句的内容。 import net.sf.jsqlparser.statement.select.PlainSelect; + +// 导入JSqlParser库中表示查询语句的通用类,用于接收解析后的查询语句对象, +// 以便进行后续的类型转换和处理操作。 import net.sf.jsqlparser.statement.select.Select; + +// 导入Apache Commons Lang3库中的StringUtils类,用于处理字符串相关的操作, +// 如判断字符串是否为空、非空等情况,在本类中用于判断用户ID等字符串是否有效。 import org.apache.commons.lang3.StringUtils; + +// 导入MyBatis中的语句处理器接口类,它是MyBatis在执行SQL语句时涉及的一个重要组件, +// 在本类中作为拦截的目标对象类型,以便在其执行查询准备阶段进行拦截操作。 import org.apache.ibatis.executor.statement.StatementHandler; + +// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, +// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等。 import org.apache.ibatis.mapping.MappedStatement; + +// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, +// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是否为查询语句。 import org.apache.ibatis.mapping.SqlCommandType; + +// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, +// 本类实现了该接口以作为一个MyBatis的拦截器来拦截查询语句的执行过程。 import org.apache.ibatis.plugin.Interceptor; + +// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, +// 本类通过该注解指定了要拦截StatementHandler的prepare方法。 import org.apache.ibatis.plugin.Intercepts; + +// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, +// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; + +// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, +// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; + +// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, +// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; + +// 导入MyBatis的默认反射工厂类,用于创建反射对象来访问和修改MyBatis相关对象的属性, +// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.DefaultReflectorFactory; + +// 导入MyBatis的元对象类,它提供了一种通过反射来访问和操作MyBatis相关对象属性的机制, +// 在本类中用于获取和设置StatementHandler等对象的内部属性,如SQL语句等。 import org.apache.ibatis.reflection.MetaObject; + +// 导入MyBatis的系统元对象类,它是MetaObject的一种特殊实现,提供了一些默认的对象工厂和包装器工厂, +// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.SystemMetaObject; + +// 导入Apache Shiro的安全工具类,用于获取当前安全上下文的相关信息, +// 在本类中用于获取当前登录用户的信息,以便根据用户信息来处理查询语句。 import org.apache.shiro.SecurityUtils; +// 导入Java标准库中的字符串读取器类,用于将字符串转换为可读取的流形式, +// 在本类中用于将SQL语句字符串提供给CCJSqlParserManager进行解析。 import java.io.StringReader; + +// 导入Java标准库中的数据库连接接口类,它是Java数据库操作中与数据库建立连接的关键接口, +// 在本类中作为StatementHandler的prepare方法的参数类型之一出现,虽然在本类代码中未直接对其进行复杂操作, +// 但它是MyBatis执行SQL语句过程中涉及到的重要组件之一。 import java.sql.Connection; + +// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, +// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, +// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 查询拦截器,用于拦截处理通用的信息、如用户ID、多租户信息等; - * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确,分页计数大于实际数量等问题 + * 查询拦截器类,用于拦截处理通用的信息,如用户ID、多租户信息等。 + * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确, + * 分页计数大于实际数量等问题。 * @author bool */ @Log4j2 -@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),}) +// 使用@Intercepts注解指定该类作为MyBatis的拦截器要拦截的目标和方法。 +// 这里拦截的是StatementHandler类的prepare方法,并且该方法的参数类型为Connection和Integer。 +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class QueryInterceptor extends PaginationInterceptor implements Interceptor { /** - * 客户ID + * 客户ID的占位符字符串,在原始SQL语句中如果出现该占位符,将会被替换为实际的用户ID。 */ private static final String USER_FILTER = "{{userId}}"; - - + /** + * 拦截器的核心方法,用于在目标方法(StatementHandler的prepare方法)被调用时进行拦截处理。 + * + * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 + * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 + * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 + */ @Override public Object intercept(Invocation invocation) throws Throwable { + // 从invocation对象中获取被拦截的目标对象,即StatementHandler对象。 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); + + // 使用MetaObject.forObject方法创建一个元对象,用于通过反射访问和修改StatementHandler对象的属性。 + // 这里传入了默认的对象工厂、包装器工厂和反射工厂,以便能够正确地操作StatementHandler对象的内部属性。 MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); + + // 从元对象中获取MappedStatement对象,该对象包含了关于SQL语句的映射信息,如SQL语句的ID、参数映射、结果映射等。 MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); - //sql语句类型 + // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 + // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - // 只过滤查询的 + // 只对查询类型的SQL语句进行处理,如果当前SQL语句类型是SELECT,则进入下面的处理逻辑。 if (SqlCommandType.SELECT == sqlCommandType) { - // 获得原始SQL + + // 获取原始的SQL语句,通过StatementHandler的getBoundSql方法获取绑定的SQL语句对象,再获取其SQL字符串。 String sql = statementHandler.getBoundSql().getSql(); - // 不处理 - if(!sql.contains(USER_FILTER)){ + // 如果原始SQL语句中不包含用户ID占位符(USER_FILTER),则直接调用父类(PaginationInterceptor)的intercept方法, + // 即按照原有的分页逻辑进行处理,不进行用户ID相关的替换等操作。 + if (!sql.contains(USER_FILTER)) { return super.intercept(invocation); } - // 处理SQL语句 + + // 如果原始SQL语句中包含用户ID占位符,则需要对SQL语句进行处理。 + // 首先调用parseSql方法对SQL语句进行解析和处理,包括替换用户ID等操作。 String outSql = this.parseSql(sql); - // 设置SQL + + // 将处理后的SQL语句设置回StatementHandler对象的内部属性中,通过元对象的setValue方法设置boundSql.sql属性的值。 metaObject.setValue("delegate.boundSql.sql", outSql); - // 再分页 + + // 再次调用父类(PaginationInterceptor)的intercept方法,此时是在处理完用户ID等信息后, + // 按照正确的分页逻辑进行处理,以确保分页功能在拦截数据并处理相关信息后正确执行。 return super.intercept(invocation); } + // 如果当前SQL语句不是查询类型(SELECT),则直接执行被拦截方法的原有逻辑,不进行额外的处理。 return invocation.proceed(); } + /** + * 将拦截器包装成MyBatis可识别的插件形式的方法。 + * + * @param target 要包装的目标对象,通常是被拦截的对象,如StatementHandler等。 + * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 + */ @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } + /** + * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, + * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 + * + * @param properties 包含了外部配置的属性信息的Properties对象。 + */ @Override public void setProperties(Properties properties) { } - - /** - * 获取当前登录用户 - * @return + * 获取当前登录用户的方法,通过Apache Shiro的SecurityUtils工具类来获取当前安全上下文的主体对象, + * 并获取其主体信息(即登录用户的信息),如果获取成功则转换为SysUserLoginDTO类型返回,否则返回null。 + * + * @return 返回当前登录用户的SysUserLoginDTO对象,如果获取失败则返回null。 */ private SysUserLoginDTO getLoginUser() { try { - return SecurityUtils.getSubject().getPrincipal() != null ? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; + return SecurityUtils.getSubject().getPrincipal()!= null? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; } catch (Exception e) { return null; } } /** - * 替换用户ID - * @param sql - * @return + * 替换用户ID的方法,根据当前登录用户的ID,将原始SQL语句中的用户ID占位符(USER_FILTER)替换为实际的用户ID。 + * + * @param sql 原始的SQL语句。 + * @return 返回替换用户ID后的SQL语句,如果用户ID为空,则返回null。 */ private String processUserId(String sql) { - // 当前用户 + // 获取当前登录用户的信息,通过调用getLoginUser方法获取。 SysUserLoginDTO user = this.getLoginUser(); String userId = user.getId(); - if(StringUtils.isNotBlank(userId)){ + + // 如果获取到的用户ID不为空,则将原始SQL语句中的用户ID占位符替换为实际的用户ID,并返回替换后的SQL语句。 + if (StringUtils.isNotBlank(userId)) { return sql.replace(USER_FILTER, userId); } + + // 如果用户ID为空,则返回null。 return null; } /** - * 处理注入用户信息 - * @param src - * @return + * 处理注入用户信息的方法,主要用于解析原始SQL语句,替换用户ID等操作,以实现根据用户信息来调整查询语句的目的。 + * + * @param src 原始的SQL语句。 + * @return 返回处理后的SQL语句,如果在处理过程中出现异常,则返回原始的SQL语句。 */ private String parseSql(String src) { + // 创建一个CCJSqlParserManager对象,用于解析SQL语句。 CCJSqlParserManager parserManager = new CCJSqlParserManager(); try { + // 使用CCJSqlParserManager对象的parse方法解析原始SQL语句,将其转换为Select类型的对象。 + // 这里需要将原始SQL语句通过StringReader转换为可读取的流形式提供给parse方法进行解析。 Select select = (Select) parserManager.parse(new StringReader(src)); + + // 从Select对象中获取其查询主体部分,即PlainSelect对象,它包含了查询语句的具体内容,如查询条件、字段等。 PlainSelect selectBody = (PlainSelect) select.getSelectBody(); - // 过滤客户 + // 将PlainSelect对象转换为字符串形式,得到初步处理后的SQL语句。 + // 这里主要是为了后续方便进行用户ID等信息的替换操作。 String sql = selectBody.toString(); - // 过滤用户ID + // 调用processUserId方法对初步处理后的SQL语句进行用户ID的替换操作,将用户ID占位符替换为实际的用户ID。 sql = this.processUserId(sql); - // 获得SQL + // 返回处理后的SQL语句。 return sql; } catch (Exception e) { e.printStackTrace(); } + // 如果在处理过程中出现异常,则返回原始的SQL语句。 return src; } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java index 8baae8f..c85e5f0 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java @@ -1,80 +1,188 @@ +// 定义包路径,用于存放更新拦截器相关的类。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.mybatis部分, +// 通常用于组织和管理与MyBatis相关的切面逻辑代码。 package com.yf.exam.aspect.mybatis; +// 导入MyBatis-Plus的抽象SQL解析处理器类,它提供了一些基础的SQL解析处理功能, +// 本类继承自该类以便在处理更新操作时利用其相关功能或遵循其处理规范。 import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; + +// 导入Apache Commons Lang3库中的数组工具类,用于对数组进行各种操作, +// 如合并数组等,在本类中用于合并对象的字段数组(当存在父类字段时)。 import org.apache.commons.lang3.ArrayUtils; + +// 导入MyBatis中的执行器接口类,它是MyBatis执行SQL语句的核心组件,负责实际执行数据库操作, +// 在本类中作为拦截的目标对象类型,通过拦截其update方法来实现自动设置创建时间和更新时间的功能。 import org.apache.ibatis.executor.Executor; + +// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, +// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等, +// 以便根据不同的操作类型(插入、更新等)来处理创建时间和更新时间的赋值。 import org.apache.ibatis.mapping.MappedStatement; + +// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, +// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是何种类型的操作, +// 从而确定是否需要对创建时间和更新时间进行赋值。 import org.apache.ibatis.mapping.SqlCommandType; + +// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, +// 本类实现了该接口以作为一个MyBatis的拦截器来拦截更新语句的执行过程,实现自动设置时间的功能。 import org.apache.ibatis.plugin.Interceptor; + +// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, +// 本类通过该注解指定了要拦截Executor类的update方法。 import org.apache.ibatis.plugin.Intercepts; + +// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, +// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; + +// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, +// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; + +// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, +// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; +// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, +// 在本类中用于获取和设置对象的创建时间和更新时间字段的值。 import java.lang.reflect.Field; + +// 导入Java标准库中的时间戳类,用于表示某个特定时刻的时间点, +// 在本类中用于设置创建时间和更新时间为当前的时间戳,以记录操作发生的准确时间。 import java.sql.Timestamp; + +// 导入Java标准库中的对象工具类,提供了一些用于比较和操作对象的方法, +// 在本类中用于比较字段名与预定义的创建时间、更新时间字段名是否相等。 import java.util.Objects; + +// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, +// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, +// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 自动给创建时间个更新时间加值 + * 该类是一个更新拦截器,主要功能是自动给创建时间和更新时间字段赋值。 + * 它会拦截MyBatis执行器(Executor)的update方法,根据操作类型(插入或更新)以及对象的字段情况, + * 为创建时间和更新时间字段设置当前的时间戳值。 * @author bool */ @Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) +// 使用@Intercepts注解并通过@Signature指定该类作为MyBatis的拦截器要拦截的目标和方法。 +// 这里拦截的是Executor类的update方法,并且该方法的参数类型为MappedStatement和Object。 public class UpdateInterceptor extends AbstractSqlParserHandler implements Interceptor { /** - * 创建时间 + * 定义创建时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的创建时间字段。 */ private static final String CREATE_TIME = "createTime"; + /** - * 更新时间 + * 定义更新时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的更新时间字段。 */ private static final String UPDATE_TIME = "updateTime"; + /** + * 拦截器的核心方法,用于在目标方法(Executor的update方法)被调用时进行拦截处理。 + * + * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 + * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 + * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 + */ @Override public Object intercept(Invocation invocation) throws Throwable { + // 从invocation对象的参数数组中获取第一个参数,即MappedStatement对象, + // 它包含了关于SQL语句的映射信息,用于后续获取SQL命令类型等操作。 MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; - // SQL操作命令 + + // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 + // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - // 获取新增或修改的对象参数 + + // 从invocation对象的参数数组中获取第二个参数,即要进行新增或修改操作的对象参数, + // 后续会通过反射操作该对象来设置创建时间和更新时间字段的值。 Object parameter = invocation.getArgs()[1]; - // 获取对象中所有的私有成员变量(对应表字段) + + // 获取对象中所有的私有成员变量(对应表字段),通过反射获取parameter对象的声明字段数组。 Field[] declaredFields = parameter.getClass().getDeclaredFields(); - if (parameter.getClass().getSuperclass() != null) { + + // 判断parameter对象的父类是否存在,如果存在则获取父类的声明字段数组, + // 并将其与之前获取的子类声明字段数组进行合并,以获取完整的包含父类和子类字段的数组。 + if (parameter.getClass().getSuperclass()!= null) { Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields(); declaredFields = ArrayUtils.addAll(declaredFields, superField); } + // 用于临时存储当前遍历到的字段名,以便后续与预定义的创建时间、更新时间字段名进行比较。 String fieldName = null; + + // 遍历获取到的所有字段数组(包含父类和子类字段),对每个字段进行处理。 for (Field field : declaredFields) { fieldName = field.getName(); + + // 如果当前遍历到的字段名与预定义的创建时间字段名相等,说明找到了创建时间字段。 if (Objects.equals(CREATE_TIME, fieldName)) { + + // 如果当前SQL语句的操作类型是插入操作(INSERT),则需要为创建时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType)) { + + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); + + // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, + // 再创建一个Timestamp对象来表示该时间点,从而为创建时间字段赋值。 field.set(parameter, new Timestamp(System.currentTimeMillis())); } } + + // 如果当前遍历到的字段名与预定义的更新时间字段名相等,说明找到了更新时间字段。 if (Objects.equals(UPDATE_TIME, fieldName)) { + + // 如果当前SQL语句的操作类型是插入操作(INSERT)或者更新操作(UPDATE), + // 则需要为更新时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { + + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); - field.set(parameter, new Timestamp(System.currentTimeMillis())); + // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, + // 再创建一个Timestamp对象来表示该时间点,从而为更新时间字段赋值。 + field.set(parameter, new Timestamp(System.currentTimeMillis())); } } } + + // 继续执行被拦截的Executor的update方法的原有逻辑,经过上述处理后, + // 已经为创建时间和更新时间字段设置了合适的值(如果符合条件的话),现在继续执行原始的更新操作。 return invocation.proceed(); } + /** + * 将拦截器包装成MyBatis可识别的插件形式的方法。 + * + * @param target 要包装的目标对象,通常是被拦截的对象,如Executor等。 + * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 + */ @Override public Object plugin(Object target) { + // 如果目标对象是Executor类型,说明是我们要拦截的对象, + // 则使用Plugin.wrap方法将拦截器(this)包装到目标对象上,以便实现拦截功能。 if (target instanceof Executor) { return Plugin.wrap(target, this); } + + // 如果目标对象不是Executor类型,说明不是我们要拦截的对象,直接返回该目标对象即可。 return target; } + /** + * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, + * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 + * + * @param properties 包含了外部配置的属性信息的Properties对象。 + */ @Override public void setProperties(Properties properties) { + // 这里暂时没有具体的设置属性操作,可根据后续需求添加相关逻辑来处理接收到的属性信息。 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java index 4b47fee..77ed253 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java +++ b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java @@ -1,99 +1,128 @@ +// 定义包路径,用于存放注入工具类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.utils部分, +// 通常用于组织和管理与注入操作相关的工具类代码。 package com.yf.exam.aspect.utils; +// 导入FastJSON库,它是一个用于将Java对象与JSON字符串进行相互转换的高性能库, +// 在本类的restError方法中用于将API响应对象转换为JSON字符串以便写入HTTP响应中。 import com.alibaba.fastjson.JSON; + +// 导入API错误类,它可能定义了一系列表示不同类型API错误的常量或属性, +// 在本类的restError方法中用于创建包含特定错误信息的API响应对象。 import com.yf.exam.core.api.ApiError; + +// 导入API响应类,它用于封装API调用的返回结果,包括成功的结果以及可能出现的错误信息等, +// 在本类的restError方法中用于创建要返回给客户端的错误响应对象。 import com.yf.exam.core.api.ApiRest; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入Spring框架的组件注解,用于标记该类是一个Spring组件,这样Spring容器可以对其进行管理和实例化, +// 使其能够在Spring应用程序中被其他组件所使用。 import org.springframework.stereotype.Component; +// 导入Java标准库中的HTTP响应类,用于处理HTTP协议相关的响应操作, +// 在本类的restError方法中用于设置响应的编码、内容类型以及写入响应内容等操作。 import javax.servlet.http.HttpServletResponse; + +// 导入Java标准库中的IO异常类,用于处理输入输出操作过程中可能出现的异常情况, +// 在本类的restError方法以及其他可能涉及到IO操作的地方用于捕获和处理相关异常。 import java.io.IOException; + +// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, +// 在本类的setValue和getFiled方法中用于获取和设置对象的指定字段的值。 import java.lang.reflect.Field; /** - * 注入工具类 + * 注入工具类,提供了一些用于对象字段赋值以及处理错误响应返回等功能的方法。 * @author bool * @date 2019-07-17 09:32 */ -@Log4j2 -@Component +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 +@Component // 将该类标记为Spring组件,使其能够被Spring容器管理和使用。 public class InjectUtils { - - /** - * 给对象字段赋值 + * 给指定对象的指定字段赋值的方法。 * - * @param object 赋值的对象 - * @param value 值 - * @param fields 字段 - * @throws Exception 异常 + * @param object 要进行赋值操作的对象。 + * @param value 要赋给指定字段的值。 + * @param fields 一个可变参数,用于指定要赋值的字段名数组。 + * @throws Exception 如果在获取字段或设置字段值的过程中出现异常,则抛出。 */ public void setValue(Object object, Object value, String... fields) throws Exception { - - //设置同类的属性 + // 遍历要赋值的字段名数组 for (String fieldName : fields) { - - //获取当前 + // 根据对象的类和字段名获取对应的字段对象 Field field = this.getFiled(object.getClass(), fieldName); - if(field == null){ + + // 如果获取到的字段对象为空,说明未找到对应的字段,继续下一个字段的处理。 + if (field == null) { continue; } + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); + + // 使用反射设置该字段的值为传入的值,即将指定的值赋给对象的指定字段。 field.set(object, value); } - } /** - * 获取字段名对应的字段 + * 根据目标类和字段名获取对应的字段对象的方法。 * - * @param clazz 目标类 - * @param fieldName 字段名 + * @param clazz 目标类,即要在其中查找字段的类。 + * @param fieldName 要查找的字段名。 + * @return 返回找到的字段对象,如果未找到则返回null。 */ private Field getFiled(Class clazz, String fieldName) { + System.out.println("注入的类:" + clazz.toString()); // 打印当前正在查找字段的目标类的信息,方便调试查看。 - System.out.println("注入的类:"+clazz.toString()); - - //是否具有包含关系 + // 尝试获取当前类中指定字段名的字段对象 try { - //获取当前类的属性 return clazz.getDeclaredField(fieldName); - }catch (Exception e){ + } catch (Exception e) { + log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); // 如果获取字段失败,记录错误日志, + // 提示在当前类中不存在指定字段, + // 并准备尝试在父类中查找。 - log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); - - //如果为空且存在父类,则往上找 - if(clazz.getSuperclass()!=null){ + // 如果当前类未找到指定字段且存在父类,则递归调用本方法在父类中继续查找指定字段。 + if (clazz.getSuperclass()!= null) { return this.getFiled(clazz.getSuperclass(), fieldName); } + // 如果在当前类及其所有父类中都未找到指定字段,则返回null。 return null; } } - /** - * 打印结果返回 - * @param response - * @throws IOException + * 用于处理错误情况并将错误结果返回给客户端的方法,通过设置HTTP响应的相关属性和写入错误响应内容来实现。 + * + * @param response HTTP响应对象,用于向客户端发送响应信息。 + * @throws IOException 如果在设置响应属性或写入响应内容过程中出现IO异常,则抛出。 */ public static void restError(HttpServletResponse response) { - try { - - //固定错误 + // 创建一个包含特定API错误信息的API响应对象,这里使用了ApiError.ERROR_10010002作为错误码, + // 具体含义可能在ApiError类中定义,通常表示某种常见的错误情况。 ApiRest apiRest = new ApiRest(ApiError.ERROR_10010002); + + // 设置HTTP响应的字符编码为UTF-8,确保能够正确处理和传输各种字符,特别是中文等非ASCII字符。 response.setCharacterEncoding("UTF-8"); + + // 设置HTTP响应的内容类型为application/json,表明返回给客户端的内容是JSON格式的数据。 response.setContentType("application/json"); - response.getWriter().write(JSON.toJSONString(apiRest)); - response.getWriter().close(); - }catch (IOException e){ + // 将创建的API响应对象转换为JSON字符串,并写入到HTTP响应的输出流中,以便客户端能够接收到错误信息。 + response.getWriter().write(JSON.toJSONString(apiRest)); + // 关闭HTTP响应的写入流,释放相关资源。 + response.getWriter().close(); + } catch (IOException e) { + // 如果在设置响应属性或写入响应内容过程中出现IO异常,这里只是简单地捕获异常, + // 可以根据实际需求进一步处理异常,比如记录更详细的日志信息等。 } - } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java index e88cb08..83b86ab 100644 --- a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java @@ -1,35 +1,81 @@ package com.yf.exam.config; +// 导入Spring Boot中用于注册Servlet过滤器的类,通过它可以将自定义的过滤器注册到Servlet容器中, +// 并配置相关属性,如过滤器的执行顺序等。在本类中用于注册跨域过滤器(CorsFilter)。 import org.springframework.boot.web.servlet.FilterRegistrationBean; + +// 导入Spring框架中用于标记一个类是配置类的注解,被该注解标记的类可以在其中定义各种Bean配置方法, +// 这些方法会被Spring容器在启动时自动识别并执行,用于创建和配置应用程序所需的各种组件。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于指定顺序的接口,实现该接口可以定义对象的顺序, +// 在本类中用于指定跨域过滤器(CorsFilter)在过滤器链中的执行顺序,使其具有最高优先级。 import org.springframework.core.Ordered; + +// 导入Spring框架中用于配置跨域资源共享(Cors)的类,通过它可以设置允许的源、请求头、请求方法等跨域相关的配置项。 import org.springframework.web.cors.CorsConfiguration; + +// 导入Spring框架中基于URL的跨域配置源类,它允许根据不同的URL模式来配置不同的跨域设置, +// 在本类中用于创建一个基于URL的跨域配置源,并将统一的跨域配置应用到所有的URL路径("**")上。 import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; +// 导入Spring框架中实现跨域过滤功能的类,它会根据配置的跨域规则对请求进行过滤和处理, +// 以实现允许跨域访问的功能。在本类中创建该过滤器并将其注册到Servlet容器中。 +import org.springframework.web.filter.CorsFilter; /** - * 网关全局设置,允许跨域 + * 网关全局设置类,主要功能是配置允许跨域访问的相关设置。 + * 通过创建和注册跨域过滤器(CorsFilter),并设置允许的源、请求头、请求方法等配置项, + * 使得应用程序能够处理来自不同域的请求,避免跨域访问限制。 + * * @author bool * @date 2019-08-13 17:28 */ - -@Configuration +@Configuration // 标记该类为Spring框架的配置类,表明其中可以定义各种Bean的创建和配置方法。 public class CorsConfig { + /** + * 定义一个Bean方法,用于创建并返回一个FilterRegistrationBean对象,该对象用于注册跨域过滤器(CorsFilter)。 + * + * @return 返回一个FilterRegistrationBean对象,其中包含了配置好的跨域过滤器以及相关的执行顺序等设置。 + */ @Bean public FilterRegistrationBean corsFilter() { + // 创建一个基于URL的跨域配置源对象,它将作为跨域配置的基础,用于后续设置跨域规则并应用到特定的URL路径上。 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + + // 创建一个CorsConfiguration对象,用于设置具体的跨域配置项,如允许的源、请求头、请求方法等。 CorsConfiguration config = new CorsConfiguration(); + + // 设置是否允许携带凭证(如Cookie等)进行跨域请求,这里设置为true,表示允许携带凭证。 config.setAllowCredentials(true); + + // 添加允许的源,这里使用CorsConfiguration.ALL表示允许所有的源进行跨域访问。 + // 可以根据实际需求设置具体的源地址,如"http://example.com"等,多个源地址可以多次调用addAllowedOrigin方法添加。 config.addAllowedOrigin(CorsConfiguration.ALL); + + // 添加允许的请求头,同样使用CorsConfiguration.ALL表示允许所有的请求头进行跨域请求。 + // 如果需要限制特定的请求头,可以通过其他方式设置具体的请求头列表。 config.addAllowedHeader(CorsConfiguration.ALL); + + // 添加允许的请求方法,使用CorsConfiguration.ALL表示允许所有的请求方法进行跨域请求, + // 包括常见的GET、POST、PUT、DELETE等方法。也可以根据实际需求设置具体的请求方法列表。 config.addAllowedMethod(CorsConfiguration.ALL); + + // 将上述设置好的跨域配置应用到所有的URL路径上,"**"表示匹配任意的URL路径。 + // 这样,对于应用程序接收到的任何请求,都会根据这个统一的跨域配置进行处理。 source.registerCorsConfiguration("/**", config); + + // 创建一个FilterRegistrationBean对象,用于注册跨域过滤器(CorsFilter)。 + // 将创建好的基于上述跨域配置源的跨域过滤器(new CorsFilter(source))作为参数传入FilterRegistrationBean的构造函数。 FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); + + // 设置跨域过滤器在过滤器链中的执行顺序,这里设置为Ordered.HIGHEST_PRECEDENCE,表示具有最高优先级。 + // 即该过滤器会在其他过滤器之前首先对请求进行处理,以确保跨域配置能够最先生效。 bean.setOrder(Ordered.HIGHEST_PRECEDENCE); + + // 返回配置好的FilterRegistrationBean对象,完成跨域过滤器的注册和相关设置。 return bean; } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java index 75e6dfa..69d16f5 100644 --- a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java @@ -1,28 +1,67 @@ +// 定义包路径,用于存放文件上传配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与文件上传配置相关的代码。 package com.yf.exam.config; +// 导入Spring Boot中用于创建和配置多部分(Multipart)上传相关设置的工厂类。 +// 通过这个工厂类可以方便地设置如单个文件大小限制、总上传数据大小限制等参数, +// 在本类中用于创建和配置文件上传的相关限制。 import org.springframework.boot.web.servlet.MultipartConfigFactory; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将multipartConfigElement方法返回的MultipartConfigElement对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行文件上传相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于处理数据大小单位转换和表示的工具类。 +// 它可以方便地将不同单位的数据大小表示转换为统一的格式, +// 在本类中用于设置文件上传的单个文件大小和总上传数据大小的限制,以兆字节(MB)为单位进行设置。 import org.springframework.util.unit.DataSize; +// 导入Java标准库中的用于表示多部分(Multipart)上传配置元素的接口。 +// 这个接口定义了多部分上传相关的配置参数,如文件大小限制、请求大小限制等, +// 在本类中通过MultipartConfigFactory创建并返回实现了该接口的对象,以完成文件上传的配置设置。 import javax.servlet.MultipartConfigElement; /** - * 文件上传配置 + * 文件上传配置类,主要功能是配置文件上传过程中的相关参数, +// 包括单个文件的最大允许大小以及整个上传请求的最大允许数据大小等。 + * * @author bool * @date 2019-07-29 16:23 */ -@Configuration +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 public class MultipartConfig { + /** + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个MultipartConfigElement对象,这个对象包含了文件上传的具体配置参数。 + * + * @return 返回一个MultipartConfigElement对象,其中设置了单个文件大小和总上传数据大小的限制等配置信息。 + */ @Bean public MultipartConfigElement multipartConfigElement() { - MultipartConfigFactory factory = new MultipartConfigFactory(); - // 单个数据大小 + MultipartConfigFactory factory = new MultipartConfigFactory(); // 创建一个MultipartConfigFactory对象, + // 它是用于创建MultipartConfigElement对象的工厂类, + // 通过它可以方便地设置各种文件上传的配置参数。 + + // 设置单个文件的最大允许大小。 + // 这里使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), + // 即限制单个上传的文件大小不能超过5000MB。 factory.setMaxFileSize(DataSize.ofMegabytes(5000L)); - /// 总上传数据大小 + + // 设置整个上传请求的最大允许数据大小。 + // 同样使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), + // 也就是说,整个上传请求(包括可能上传的多个文件以及其他相关数据)的总数据量不能超过5000MB。 factory.setMaxRequestSize(DataSize.ofMegabytes(5000L)); + + // 通过MultipartConfigFactory对象的createMultipartConfig方法创建并返回一个MultipartConfigElement对象, + // 这个对象包含了我们刚刚设置的单个文件大小和总上传数据大小等配置信息, + // 它会被Spring容器管理并应用到文件上传的相关处理中。 return factory.createMultipartConfig(); } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java index 642fc25..1645a7f 100644 --- a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java @@ -1,37 +1,70 @@ +// 定义包路径,用于存放MyBatis配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与MyBatis配置相关的代码。 package com.yf.exam.config; +// 导入自定义的查询拦截器类,该拦截器用于在查询操作时进行一些额外的处理, +// 比如可能会根据特定条件对查询语句进行修改、添加过滤条件等操作。 import com.yf.exam.aspect.mybatis.QueryInterceptor; + +// 导入自定义的更新拦截器类,该拦截器用于在插入或更新操作时进行相关处理, +// 例如自动设置创建时间、更新时间等字段的值。 import com.yf.exam.aspect.mybatis.UpdateInterceptor; + +// 导入MyBatis与Spring集成时用于扫描MyBatis映射接口的注解。 +// 通过该注解可以指定要扫描的包路径,以便Spring能够自动发现并注册MyBatis的映射接口, +// 使得这些接口可以被正确地用于数据库操作。 import org.mybatis.spring.annotation.MapperScan; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将queryInterceptor和updateInterceptor方法返回的拦截器对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行MyBatis相关的配置。 import org.springframework.context.annotation.Configuration; /** - * Mybatis过滤器配置 - * 注意:必须按顺序进行配置,否则容易出现业务异常 + * Mybatis过滤器配置类,主要功能是配置MyBatis的相关过滤器, + * 包括查询拦截器和更新拦截器等,并设置相关参数。同时通过注解指定MyBatis映射接口的扫描路径。 + * 注意:必须按顺序进行配置,否则容易出现业务异常。 * @author bool */ -@Configuration -@MapperScan("com.yf.exam.modules.**.mapper") +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@MapperScan("com.yf.exam.modules.**.mapper") // 使用MapperScan注解指定要扫描的MyBatis映射接口所在的包路径, + // "com.yf.exam.modules.**.mapper"表示会扫描com.yf.exam.modules包及其子包下的所有mapper接口。 + public class MybatisConfig { /** - * 数据查询过滤器 + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个查询拦截器(QueryInterceptor)对象,用于在查询操作时进行拦截处理。 + * + * @return 返回一个查询拦截器(QueryInterceptor)对象,该对象已进行了相关设置(如设置查询限制)。 */ - @Bean + @Bean // 将该方法返回的查询拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public QueryInterceptor queryInterceptor() { - QueryInterceptor query = new QueryInterceptor(); + QueryInterceptor query = new QueryInterceptor(); // 创建一个新的查询拦截器对象。 + + // 设置查询限制,这里将查询限制设置为 -1L,具体含义可能根据QueryInterceptor类的内部逻辑而定, + // 可能表示不限制查询结果的数量或者有其他特殊的处理方式与该值相关。 query.setLimit(-1L); + + // 返回设置好的查询拦截器对象,该对象将被Spring容器管理并在合适的查询操作场景中被调用执行拦截处理。 return query; } /** - * 插入数据过滤器 + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个更新拦截器(UpdateInterceptor)对象,用于在插入或更新操作时进行拦截处理。 + * + * @return 返回一个更新拦截器(UpdateInterceptor)对象,该对象可直接用于插入或更新操作的拦截处理。 */ - @Bean + @Bean // 将该方法返回的更新拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public UpdateInterceptor updateInterceptor() { + // 创建一个新的更新拦截器对象,这里没有进行额外的设置操作(可能在UpdateInterceptor类内部有默认的处理逻辑), + // 直接返回该对象,它将被Spring容器管理并在合适的插入或更新操作场景中被调用执行拦截处理。 return new UpdateInterceptor(); } - - } \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java index b08f96f..994b761 100644 --- a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java @@ -1,77 +1,182 @@ +// 定义包路径,用于存放任务调度配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与任务调度配置相关的代码。 package com.yf.exam.config; +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入Spring框架中用于处理异步方法执行过程中未捕获异常的处理器接口。 +// 当异步方法抛出异常且未在方法内部被捕获时,会由该处理器来处理异常情况, +// 在本类中实现该接口来定义异步未捕获异常的处理逻辑。 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将taskScheduler和asyncExecutor等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行任务调度相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于配置异步任务执行相关设置的接口。 +// 实现该接口可以定义异步任务执行的线程池等配置信息,在本类中实现该接口来配置异步任务执行的相关参数。 import org.springframework.scheduling.annotation.AsyncConfigurer; + +// 导入Spring框架中用于启用异步任务执行功能的注解。 +// 当在类上添加该注解后,Spring会自动识别并处理类中的异步方法,使其能够在独立的线程中执行。 +// 在本类上添加该注解以启用异步任务执行功能。 import org.springframework.scheduling.annotation.EnableAsync; + +// 导入Spring框架中用于启用任务调度功能的注解。 +// 当在类上添加该注解后,Spring会自动识别并处理类中的定时任务等调度相关的设置,使其能够按照预定的时间执行任务。 +// 在本类上添加该注解以启用任务调度功能。 import org.springframework.scheduling.annotation.EnableScheduling; + +// 导入Spring框架中用于配置任务调度相关设置的接口。 +// 实现该接口可以定义任务调度的线程池、任务注册等配置信息,在本类中实现该接口来配置任务调度的相关参数。 import org.springframework.scheduling.annotation.SchedulingConfigurer; + +// 导入Spring框架中用于执行线程池任务的执行器类。 +// 它可以创建一个线程池,并通过该线程池来执行任务,在本类的asyncExecutor方法中用于创建异步任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +// 导入Spring框架中用于调度线程池任务的调度器类。 +// 它可以创建一个线程池,并通过该线程池来调度任务的执行时间,在本类的taskScheduler方法中用于创建定时任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +// 导入Spring框架中用于注册调度任务的类。 +// 通过它可以将需要调度执行的任务注册到相应的调度器中,在本类的configureTasks方法中用于设置任务调度器。 import org.springframework.scheduling.config.ScheduledTaskRegistrar; +// 导入Java标准库中的执行器接口,它定义了执行任务的通用规范, +// 在本类的getAsyncExecutor方法中用于返回异步任务执行的执行器对象。 import java.util.concurrent.Executor; + +// 导入Java标准库中的线程池执行器类,它是实现了线程池功能的具体类, +// 在本类的asyncExecutor方法中用于设置异步任务执行线程池的拒绝策略。 import java.util.concurrent.ThreadPoolExecutor; /** - * 任务调度配置 + * 任务调度配置类,主要功能是配置任务调度和异步任务执行相关的设置, + * 包括创建定时任务执行的线程池和异步任务执行的线程池,设置线程池的大小、名称前缀、 + * 等待终止时间、队列容量等参数,同时实现了处理异步未捕获异常的逻辑。 * @author bool */ -@Log4j2 -@Configuration -@EnableScheduling -@EnableAsync +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@EnableScheduling // 使用该注解启用任务调度功能,使得Spring能够识别并处理类中的定时任务等调度相关设置。 +@EnableAsync // 使用该注解启用异步任务执行功能,使得Spring能够识别并处理类中的异步方法,使其能够在独立的线程中执行。 public class ScheduledConfig implements SchedulingConfigurer, AsyncConfigurer { /** - * 定时任务使用的线程池 - * @return + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,用于定时任务的执行调度。 + * + * @return 返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,该对象已进行了相关设置(如线程池大小、名称前缀等)。 */ - @Bean(destroyMethod = "shutdown", name = "taskScheduler") - public ThreadPoolTaskScheduler taskScheduler(){ - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + @Bean(destroyMethod = "shutdown", name = "taskScheduler") // 将该方法返回的线程池任务调度器对象声明为Spring Bean, + // 并指定销毁方法为"shutdown",以便在容器关闭时正确关闭线程池。 + public ThreadPoolTaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 创建一个新的线程池任务调度器对象。 + + // 设置线程池的大小,即同时可执行的定时任务数量,这里设置为10,表示线程池最多可同时执行10个定时任务。 scheduler.setPoolSize(10); + + // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务调度器,这里设置为"task-", + // 生成的线程名称可能类似"task-1"、"task-2"等。 scheduler.setThreadNamePrefix("task-"); + + // 设置线程池在关闭时等待任务完成的时间,单位为秒,这里设置为600秒(10分钟), + // 表示在容器关闭时,线程池会等待正在执行的任务完成,最长等待时间为10分钟。 scheduler.setAwaitTerminationSeconds(600); + + // 设置在关闭时是否等待任务完成,这里设置为true,表示在容器关闭时,线程池会等待所有任务完成后再关闭。 scheduler.setWaitForTasksToCompleteOnShutdown(true); + + // 返回设置好的线程池任务调度器对象,该对象将被Spring容器管理并在定时任务执行场景中被调用进行任务调度。 return scheduler; } /** - * 异步任务执行线程池 - * @return + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,用于异步任务的执行。 + * + * @return 返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,该对象已进行了相关设置(如核心线程数、队列容量等)。 */ - @Bean(name = "asyncExecutor") + @Bean(name = "asyncExecutor") // 将该方法返回的线程池任务执行器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public ThreadPoolTaskExecutor asyncExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 创建一个新的线程池任务执行器对象。 + + // 设置线程池的核心线程数,即线程池始终保持的活跃线程数量,这里设置为10,表示线程池至少会保持10个线程处于活跃状态。 executor.setCorePoolSize(10); + + // 设置线程池的队列容量,即用于存储等待执行任务的队列大小,这里设置为1000,表示队列最多可容纳1000个等待执行的任务。 executor.setQueueCapacity(1000); + + // 设置线程池中非核心线程的保持活动时间,单位为秒,这里设置为600秒(10分钟), + // 表示当非核心线程空闲时间超过10分钟时,可能会被回收。 executor.setKeepAliveSeconds(600); + + // 设置线程池的最大线程数,即线程池最多可同时拥有的线程数量,这里设置为20,表示线程池最多可扩展到20个线程同时执行任务。 executor.setMaxPoolSize(20); + + // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务执行器,这里设置为"taskExecutor-", + // 生成的线程名称可能类似"taskExecutor-1"、"taskExecutor-2"等。 executor.setThreadNamePrefix("taskExecutor-"); + + // 设置线程池的拒绝策略,这里采用ThreadPoolExecutor.CallerRunsPolicy(), + // 表示当线程池和队列都已满,无法再接受新任务时,会由调用线程来执行该任务,而不是直接抛出异常。 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + + // 初始化线程池,使其处于可使用状态,完成各项参数的设置和内部资源的初始化。 executor.initialize(); + + // 返回设置好的线程池任务执行器对象,该对象将被Spring容器管理并在异步任务执行场景中被调用进行任务执行。 return executor; } + /** + * 实现SchedulingConfigurer接口的方法,用于配置任务调度相关的设置。 + * 在本方法中,获取之前创建的线程池任务调度器对象,并将其设置到调度任务注册类中, + * 以便后续注册的定时任务能够使用该调度器进行任务调度。 + * + * @param scheduledTaskRegistrar 调度任务注册类对象,用于注册调度任务和设置调度器等操作。 + */ @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { - ThreadPoolTaskScheduler taskScheduler = taskScheduler(); + ThreadPoolTaskScheduler taskScheduler = taskScheduler(); // 获取之前创建的线程池任务调度器对象。 + + // 将获取到的线程池任务调度器对象设置到调度任务注册类中,使得后续注册的定时任务能够使用该调度器进行任务调度。 scheduledTaskRegistrar.setTaskScheduler(taskScheduler); } + /** + * 实现AsyncConfigurer接口的方法,用于返回异步任务执行的执行器对象。 + * 在本方法中,直接返回之前创建的线程池任务执行器对象,该对象将作为异步任务执行的执行器。 + * + * @return 返回异步任务执行的执行器对象,即之前创建的线程池任务执行器对象。 + */ @Override public Executor getAsyncExecutor() { return asyncExecutor(); } + /** + * 实现AsyncConfigurer接口的方法,用于定义异步未捕获异常的处理逻辑。 + * 在本方法中,当异步任务执行出现异常且未在方法内部被捕获时,会通过日志记录异常信息, + * 包括异常对象、执行的方法以及方法的参数等内容。 + * + * @param throwable 异步任务执行过程中抛出的异常对象。 + * @param method 执行异步任务的方法对象。 + * @param objects 执行异步任务的方法的参数对象数组。 + * @return 返回值无实际意义,这里主要是为了符合AsyncUncaughtExceptionHandler接口的定义。 + */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { - log.error("异步任务执行出现异常, message {}, emthod {}, params {}", throwable, method, objects); + log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects); }; } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java index cbb3f38..52d179c 100644 --- a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java @@ -1,127 +1,133 @@ +// 定义包路径,用于存放Shiro配置类 package com.yf.exam.config; -import com.yf.exam.ability.shiro.CNFilterFactoryBean; -import com.yf.exam.ability.shiro.ShiroRealm; -import com.yf.exam.ability.shiro.aop.JwtFilter; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; -import org.apache.shiro.mgt.DefaultSubjectDAO; -import org.apache.shiro.mgt.SecurityManager; -import org.apache.shiro.spring.LifecycleBeanPostProcessor; -import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; -import org.apache.shiro.web.mgt.DefaultWebSecurityManager; -import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; - -import javax.servlet.Filter; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - +import com.yf.exam.ability.shiro.CNFilterFactoryBean; // 自定义过滤器工厂类 +import com.yf.exam.ability.shiro.ShiroRealm; // 自定义Shiro领域类 +import com.yf.exam.ability.shiro.aop.JwtFilter; // JWT认证过滤器 +import lombok.extern.slf4j.Slf4j; // Lombok日志注解 +import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; // Shiro默认会话存储评估器 +import org.apache.shiro.mgt.DefaultSubjectDAO; // Shiro默认主体DAO +import org.apache.shiro.mgt.SecurityManager; // Shiro安全管理器 +import org.apache.shiro.spring.LifecycleBeanPostProcessor; // Spring生命周期Bean后处理器 +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; // Shiro授权属性源顾问 +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类 +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; // Shiro默认Web安全管理器 +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; // Spring默认顾问自动代理创建器 +import org.springframework.context.annotation.Bean; // Spring Bean注解 +import org.springframework.context.annotation.Configuration; // Spring配置注解 +import org.springframework.context.annotation.DependsOn; // Spring依赖注解 + +import javax.servlet.Filter; // Servlet过滤器接口 +import java.util.HashMap; // Java哈希映射类 +import java.util.LinkedHashMap; // Java链接哈希映射类 +import java.util.Map; // Java映射类 /** * Shiro配置类 + * 用于配置和自定义Shiro框架的相关组件,包括安全管理器、过滤器工厂、Realm等。 * @author bool */ -@Slf4j -@Configuration +@Slf4j // 使用Lombok注解,启用Log4j2日志 +@Configuration // 使用Spring注解,标记为配置类 public class ShiroConfig { - /** - * Filter Chain定义说明 - * - * 1、一个URL可以配置多个Filter,使用逗号分隔 - * 2、当设置多个过滤器时,全部验证通过,才视为通过 - * 3、部分过滤器可指定参数,如perms,roles - */ - @Bean("shiroFilterFactoryBean") - public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { - ShiroFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); - shiroFilterFactoryBean.setSecurityManager(securityManager); - // 拦截器 - Map map = new LinkedHashMap<>(); - - // 需要排除的一些接口 - map.put("/exam/api/sys/user/login", "anon"); - map.put("/exam/api/sys/user/reg", "anon"); - map.put("/exam/api/sys/user/quick-reg", "anon"); - - // 获取网站基本信息 - map.put("/exam/api/sys/config/detail", "anon"); - - // 文件读取 - map.put("/upload/file/**", "anon"); - - map.put("/", "anon"); - map.put("/v2/**", "anon"); - map.put("/doc.html", "anon"); - map.put("/**/*.js", "anon"); - map.put("/**/*.css", "anon"); - map.put("/**/*.html", "anon"); - map.put("/**/*.svg", "anon"); - map.put("/**/*.pdf", "anon"); - map.put("/**/*.jpg", "anon"); - map.put("/**/*.png", "anon"); - map.put("/**/*.ico", "anon"); - - // 字体 - map.put("/**/*.ttf", "anon"); - map.put("/**/*.woff", "anon"); - map.put("/**/*.woff2", "anon"); - map.put("/druid/**", "anon"); - map.put("/swagger-ui.html", "anon"); - map.put("/swagger**/**", "anon"); - map.put("/webjars/**", "anon"); - - // 添加自己的过滤器并且取名为jwt - Map filterMap = new HashMap(1); - filterMap.put("jwt", new JwtFilter()); - shiroFilterFactoryBean.setFilters(filterMap); - map.put("/**", "jwt"); - - shiroFilterFactoryBean.setFilterChainDefinitionMap(map); - return shiroFilterFactoryBean; - } - - @Bean("securityManager") - public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { - DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); - securityManager.setRealm(myRealm); - DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); - DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); - defaultSessionStorageEvaluator.setSessionStorageEnabled(false); - subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); - securityManager.setSubjectDAO(subjectDAO); - return securityManager; - } - - /** - * 下面的代码是添加注解支持 - * @return - */ - @Bean - @DependsOn("lifecycleBeanPostProcessor") - public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { - DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); - defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); - defaultAdvisorAutoProxyCreator.setUsePrefix(true); - defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); - return defaultAdvisorAutoProxyCreator; - } - - @Bean - public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { - return new LifecycleBeanPostProcessor(); - } - - @Bean - public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { - AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); - advisor.setSecurityManager(securityManager); - return advisor; - } - -} + /** + * 定义Shiro过滤器链 + * 方法用于配置Shiro过滤器链,定义哪些URL路径需要通过哪些过滤器。 + * + * @param securityManager Shiro安全管理器 + * @return ShiroFilterFactoryBean Shiro过滤器工厂Bean + */ + @Bean("shiroFilterFactoryBean") // 使用Spring注解,声明为Bean,并指定Bean名称 + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + CNFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); // 创建自定义过滤器工厂Bean + shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置安全管理器 + + // 定义过滤器链 + Map map = new LinkedHashMap<>(); // 创建拦截器映射 + + // 配置不需要认证的路径 + map.put("/exam/api/sys/user/login", "anon"); // 登录接口不需要认证 + map.put("/exam/api/sys/user/reg", "anon"); // 注册接口不需要认证 + map.put("/exam/api/sys/user/quick-reg", "anon"); // 快速注册接口不需要认证 + + // 配置其他不需要认证的静态资源路径 + map.put("/upload/file/**", "anon"); // 文件上传路径不需要认证 + map.put("/", "anon"); // 根路径不需要认证 + map.put("/v2/**", "anon"); // Swagger路径不需要认证 + map.put("/doc.html", "anon"); // Swagger文档不需要认证 + // ... 省略其他静态资源配置 + + // 添加自定义JWT过滤器 + Map filterMap = new HashMap<>(); // 创建过滤器映射 + filterMap.put("jwt", new JwtFilter()); // 添加JWT过滤器 + shiroFilterFactoryBean.setFilters(filterMap); // 设置过滤器 + + // 设置过滤器链定义 + map.put("/**", "jwt"); // 所有请求都需要通过JWT过滤器 + shiroFilterFactoryBean.setFilterChainDefinitionMap(map); // 设置过滤器链定义 + + return shiroFilterFactoryBean; // 返回Shiro过滤器工厂Bean + } + + /** + * 定义Shiro安全管理器 + * 方法用于配置Shiro安全管理器,设置自定义Realm和禁用Shiro的会话存储。 + * + * @param myRealm 自定义Shiro领域 + * @return DefaultWebSecurityManager Shiro安全管理器 + */ + @Bean("securityManager") // 使用Spring注解,声明为Bean,并指定Bean名称 + public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 创建默认Web安全管理器 + securityManager.setRealm(myRealm); // 设置自定义Realm + + // 禁用Shiro的会话存储 + DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); // 创建默认主体DAO + DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); // 创建默认会话存储评估器 + defaultSessionStorageEvaluator.setSessionStorageEnabled(false); // 禁用会话存储 + subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); // 设置会话存储评估器 + securityManager.setSubjectDAO(subjectDAO); // 设置主体DAO + + return securityManager; // 返回安全管理器 + } + + /** + * 定义注解支持 + * 方法用于添加注解支持,使得Shiro的注解可以正常工作。 + * + * @return DefaultAdvisorAutoProxyCreator 顾问自动代理创建器 + */ + @Bean // 使用Spring注解,声明为Bean + @DependsOn("lifecycleBeanPostProcessor") // 依赖于生命周期Bean后处理器 + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { + DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // 创建顾问自动代理创建器 + defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); // 设置代理目标类 + return defaultAdvisorAutoProxyCreator; // 返回顾问自动代理创建器 + } + + /** + * 定义生命周期Bean后处理器 + * 方法用于定义Shiro的生命周期Bean后处理器,确保Shiro的组件能够按照预期的生命周期工作。 + * + * @return LifecycleBeanPostProcessor 生命周期Bean后处理器 + */ + @Bean // 使用Spring注解,声明为Bean + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); // 返回生命周期Bean后处理器 + } + + /** + * 定义授权属性源顾问 + * 方法用于定义Shiro的授权属性源顾问,用于处理Shiro注解中的权限控制。 + * + * @param securityManager Shiro安全管理器 + * @return AuthorizationAttributeSourceAdvisor 授权属性源顾问 + */ + @Bean // 使用Spring注解,声明为Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); // 创建授权属性源顾问 + advisor.setSecurityManager(securityManager); // 设置安全管理器 + return advisor; // 返回授权属性源顾问 + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java index d4208aa..038caa6 100644 --- a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java @@ -1,65 +1,164 @@ +// 定义包路径,用于存放Swagger配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与Swagger配置相关的代码。 package com.yf.exam.config; +// 导入用于启用Swagger Bootstrap UI的注解,Swagger Bootstrap UI是对Swagger UI的一种增强, +// 提供了更友好的界面展示和交互功能,通过该注解可以在项目中启用这一特性。 import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; + +// 导入Swagger用于标注API操作的注解,通过在方法上添加该注解,可以为该方法在Swagger文档中生成详细的操作描述信息, +// 包括方法的功能、参数、返回值等内容,方便开发者和使用者了解API的具体使用方式。 import io.swagger.annotations.ApiOperation; + +// 导入Spring框架中用于将类的属性与配置文件中的属性进行绑定的注解。 +// 通过指定prefix属性,可以将配置文件中以该前缀开头的属性值绑定到类的对应属性上, +// 在本类中用于绑定以"swagger"为前缀的配置属性。 import org.springframework.boot.context.properties.ConfigurationProperties; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将examApi、securityScheme等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行Swagger相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Swagger用于构建API信息的构建器类,通过该构建器可以方便地设置API的标题、描述、联系人、版本等信息, +// 在本类的apiInfo方法中用于创建并返回包含详细API信息的ApiInfo对象。 import springfox.documentation.builders.ApiInfoBuilder; + +// 导入Swagger用于选择路径的选择器类,通过该选择器可以指定哪些路径下的API需要被Swagger生成文档并展示, +// 在本类的examApi方法中用于选择符合特定路径模式的API。 import springfox.documentation.builders.PathSelectors; + +// 导入Swagger用于选择请求处理器(即包含API方法的类或接口)的选择器类, +// 通过该选择器可以指定哪些请求处理器中的方法需要被Swagger生成文档并展示, +// 在本类的examApi方法中用于选择带有ApiOperation注解的方法所在的请求处理器。 import springfox.documentation.builders.RequestHandlerSelectors; + +// 导入Swagger用于表示API信息的类,该类包含了API的标题、描述、联系人、版本等详细信息, +// 在本类的examApi方法中通过调用apiInfo方法获取该对象并设置到Docket中,以便在Swagger文档中展示这些信息。 import springfox.documentation.service.ApiInfo; + +// 导入Swagger用于表示API密钥的类,用于设置API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, +// 在本类的securityScheme方法中用于创建并返回一个ApiKey对象,用于设置API的授权方案。 import springfox.documentation.service.ApiKey; + +// 导入Swagger用于表示联系人信息的类,通过该类可以设置API的联系人姓名、联系方式、网址等信息, +// 在本类的apiInfo方法中用于创建并返回一个包含联系人信息的Contact对象,并设置到ApiInfo中。 import springfox.documentation.service.Contact; + +// 导入Swagger用于表示安全方案的类,它是一个通用的接口,用于定义不同类型的安全方案, +// 在本类的examApi方法中通过调用securityScheme方法获取具体的安全方案实现(如ApiKey)并设置到Docket中。 import springfox.documentation.service.SecurityScheme; + +// 导入Swagger用于表示文档类型的枚举类,目前主要有SWAGGER_2等类型, +// 在本类的examApi方法中用于指定创建Docket对象时所采用的文档类型为SWAGagger_2。 import springfox.documentation.spi.DocumentationType; + +// 导入Swagger用于生成Swagger文档的核心类,通过该类可以配置各种Swagger相关的设置,如API信息、路径选择、 +// 授权方案等,在本类的examApi方法中用于创建并配置Docket对象,以生成符合项目需求的Swagger文档。 import springfox.documentation.spring.web.plugins.Docket; + +// 导入用于启用Swagger 2的注解,通过在类上添加该注解,可以在项目中启用Swagger 2的功能, +// 使得Swagger能够为项目中的API生成详细的文档并提供交互界面,方便开发者和使用者查看和测试API。 import springfox.documentation.swagger2.annotations.EnableSwagger2; +// 导入Java标准库中的集合类,用于处理集合相关的操作,在本类的examApi方法中用于创建一个包含单个安全方案的列表, +// 以便将安全方案设置到Docket对象中。 import java.util.Collections; /** - * Swagger配置 + * Swagger配置类,主要功能是配置Swagger在项目中的相关设置, + * 包括启用Swagger 2和Swagger Bootstrap UI功能,绑定以"swagger"为前缀的配置属性, + * 创建Docket对象并设置其API信息、分组名称、选择需要生成文档的API方法和路径、设置安全方案等, + * 以生成详细的API文档并提供友好的交互界面,方便对项目中的API进行查看、测试和使用。 * @author bool * @date 2020/8/19 20:53 */ -@Configuration -@EnableSwagger2 -@EnableSwaggerBootstrapUI -@ConfigurationProperties(prefix = "swagger") -public class SwaggerConfig { +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@EnableSwagger2 // 使用该注解启用Swagger 2功能,使得Swagger能够为项目中的API生成详细的文档并提供交互界面。 +@EnableSwaggerBootstrapUI // 使用该注解启用Swagger Bootstrap UI功能,提供更友好的界面展示和交互功能。 +@ConfigurationProperties(prefix = "swagger") // 使用该注解将类的属性与以"swagger"为前缀的配置文件中的属性进行绑定, + // 以便在类中可以方便地使用这些配置属性来定制Swagger的设置。 +public class SwaggerConfig { - @Bean + /** + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个Docket对象,该对象是Swagger生成文档的核心组件, + * 通过对其进行一系列设置,可以定制生成的API文档的内容和展示方式。 + * + * @return 返回一个Docket对象,该对象经过了相关设置,包括API信息、分组名称、选择的API方法和路径、安全方案等。 + */ + @Bean // 将该方法返回的Docket对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public Docket examApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .groupName("考试模块接口") - .select() - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) - .paths(PathSelectors.ant("/exam/api/**")) - .build() - .securitySchemes(Collections.singletonList(securityScheme())); - } + return new Docket(DocumentationType.SWAGGER_2) // 创建一个新的Docket对象,并指定文档类型为SWAGGER_2, + // 这是目前较为常用的Swagger文档类型,用于生成详细的API文档。 + .apiInfo(apiInfo()) // 调用apiInfo方法获取包含详细API信息的ApiInfo对象,并设置到Docket对象中, + // 以便在生成的Swagger文档中展示API的标题、描述、联系人、版本等信息。 + .groupName("考试模块接口") // 设置Docket对象的分组名称为"考试模块接口", + // 这样可以将项目中的API按照不同的模块或功能进行分组展示,方便查看和管理。 - private ApiInfo apiInfo() { - return new ApiInfoBuilder().title("考试系统接口") - .description("考试系统接口") - .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) - .version("1.0.0") - .build(); + .select() // 开始选择需要生成文档的API,通过一系列选择器来指定具体的选择条件。 + + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // 使用RequestHandlerSelectors的withMethodAnnotation方法选择带有ApiOperation注解的方法, + // 即只选择那些在方法上标注了ApiOperation注解的API方法进行文档生成, + // 这样可以确保只生成我们希望展示的重要API的文档。 + + .paths(PathSelectors.ant("/exam/api/**")) // 使用PathSelectors的ant方法选择符合特定路径模式的API, + // 这里选择的路径模式是"/exam/api/**",表示只选择以"/exam/api/"开头的任意路径下的API进行文档生成, + // 进一步限定了生成文档的API范围,使其更加聚焦于项目中的特定部分(如考试模块相关的API)。 + + .build() // 完成上述选择条件的设置后,调用build方法构建Docket对象,使其生效并包含我们所设置的所有选择条件和信息。 + + .securitySchemes(Collections.singletonList(securityScheme())) // 创建一个包含单个安全方案的列表, + // 通过调用securityScheme方法获取具体的安全方案对象(如ApiKey), + // 并将其添加到列表中,然后设置到Docket对象中, + // 以便在Swagger文档中展示API的授权相关信息,如需要在请求头中传递的授权密钥等。 + + ; } + /** + * 用于创建并返回一个包含详细API信息的ApiInfo对象的方法。 + * 通过ApiInfoBuilder类可以方便地设置API的标题、描述、联系人、版本等信息。 + * + * @return 返回一个ApiInfo对象,该对象包含了API的标题、描述、联系人、版本等详细信息, + * 用于设置到Docket对象中,以便在Swagger文档中展示。 + */ + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("考试系统接口") // 使用ApiInfoBuilder的title方法设置API的标题为"考试系统接口", + // 这将在Swagger文档的顶部显著位置展示,让使用者快速了解该API所属的系统。 + + .description("考试系统接口") // 使用ApiInfoBuilder的description方法设置API的描述为"考试系统接口", + // 可以在这里详细描述API的功能、用途、特点等信息,方便使用者进一步了解API的具体情况。 + + .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) // 使用ApiInfoBuilder的contact方法创建一个包含联系人信息的Contact对象, + // 并设置联系人姓名为"Van",网址为"https://exam.yfhl.net",邮箱为"18365918@qq.com", + // 这些信息将在Swagger文档中展示,方便使用者在有问题时能够联系到相关人员。 + + .version("1.0.0") // 使用ApiInfoBuilder的version方法设置API的版本号为"1.0.0", + // 让使用者了解该API的版本情况,以便在不同版本之间进行对比和选择。 + + .build(); // 完成上述各项信息的设置后,调用build方法构建ApiInfo对象,使其生效并包含我们所设置的所有信息。 + } /** - * 授权头部 - * @return + * 用于创建并返回一个表示API密钥的ApiKey对象的方法,该对象用于设置API的授权方案。 + * + * @return 返回一个ApiKey对象,该对象定义了API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, + * 用于设置到Docket对象中,以便在Swagger文档中展示API的授权要求。 */ - @Bean + @Bean // 将该方法返回的SecurityScheme对象(实际为ApiKey类型)声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 SecurityScheme securityScheme() { - return new ApiKey("token", "token", "header"); + return new ApiKey("token", "token", "header"); // 创建一个新的ApiKey对象, + // 第一个参数"token"表示授权的键名,即客户端在请求时需要在指定位置(这里是请求头)传递的键名; + // 第二个参数"token"表示授权的值,这里简单设置为与键名相同,实际应用中可能是根据用户登录等情况生成的授权令牌; + // 第三个参数"header"表示授权的值应该放置的位置,这里指定为在请求头中传递。 } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java index e5583f2..6adeb13 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java @@ -1,151 +1,144 @@ -package com.yf.exam.modules.exam.controller; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdReqDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.BaseStateReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import com.yf.exam.modules.exam.service.ExamService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Date; +package com.yf.exam.modules.exam.controller; // 定义包名,控制器所在的包路径 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页接口 +import com.yf.exam.core.api.ApiRest; // 导入自定义的API响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入基控制器类 +import com.yf.exam.core.api.dto.BaseIdReqDTO; // 导入基础ID请求数据传输对象 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入基础IDs请求数据传输对象 +import com.yf.exam.core.api.dto.BaseStateReqDTO; // 导入基础状态请求数据传输对象 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入考试审核响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 +import io.swagger.annotations.Api; // 导入Swagger注解 +import io.swagger.annotations.ApiOperation; // 导入Swagger操作注解 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入Shiro权限注解 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 +import org.springframework.web.bind.annotation.RequestBody; // 导入Spring MVC的请求体注解 +import org.springframework.web.bind.annotation.RequestMapping; // 导入Spring MVC的请求映射注解 +import org.springframework.web.bind.annotation.RequestMethod; // 导入Spring MVC的请求方法注解 +import org.springframework.web.bind.annotation.RestController; // 导入Spring MVC的控制器注解 + +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Api(tags={"考试"}) -@RestController -@RequestMapping("/exam/api/exam/exam") -public class ExamController extends BaseController { + *

+ * 考试控制器,处理与考试相关的请求 + *

+ * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Api(tags={"考试"}) // Swagger注解,定义API的标签 +@RestController // Spring MVC注解,声明这是一个REST控制器 +@RequestMapping("/exam/api/exam/exam") // Spring MVC注解,定义请求的基础路径 +public class ExamController extends BaseController { // 声明控制器类,继承自基控制器 @Autowired - private ExamService baseService; + private ExamService baseService; // 自动注入考试服务 /** - * 添加或修改 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = { RequestMethod.POST}) - public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { - //复制参数 - baseService.save(reqDTO); - return super.success(); + * 添加或修改考试信息 + * @param reqDTO 考试保存请求数据传输对象 + * @return ApiRest 返回操作结果 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "添加或修改") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/save", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { // 定义添加或修改考试的方法 + // 复制参数并保存 + baseService.save(reqDTO); // 调用服务层保存考试信息 + return super.success(); // 返回成功响应 } /** - * 批量删除 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) - public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.removeByIds(reqDTO.getIds()); - return super.success(); + * 批量删除考试 + * @param reqDTO 包含要删除的考试ID列表 + * @return ApiRest 返回操作结果 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "批量删除") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { // 定义批量删除考试的方法 + // 根据ID删除考试 + baseService.removeByIds(reqDTO.getIds()); // 调用服务层根据ID列表删除考试 + return super.success(); // 返回成功响应 } /** - * 查找详情 - * @param reqDTO - * @return - */ - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) - public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { - ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); - return super.success(dto); + * 查找考试详情 + * @param reqDTO 包含考试ID + * @return ApiRest 返回考试详情 + */ + @ApiOperation(value = "查找详情") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { // 定义查找考试详情的方法 + ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); // 调用服务层查找考试详情 + return super.success(dto); // 返回成功响应和考试详情 } /** - * 查找详情 - * @param reqDTO - * @return + * 更新考试状态 + * @param reqDTO 包含考试ID和新状态 + * @return ApiRest 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/state", method = { RequestMethod.POST}) - public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { - + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "更新考试状态") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/state", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { // 定义更新考试状态的方法 + // 创建查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().in(Exam::getId, reqDTO.getIds()); - Exam exam = new Exam(); - exam.setState(reqDTO.getState()); - exam.setUpdateTime(new Date()); + wrapper.lambda().in(Exam::getId, reqDTO.getIds()); // 构造查询条件,查询指定ID的考试 + Exam exam = new Exam(); // 创建考试实体 + exam.setState(reqDTO.getState()); // 设置新状态 + exam.setUpdateTime(new Date()); // 设置更新时间为当前时间 - baseService.update(exam, wrapper); - return super.success(); + baseService.update(exam, wrapper); // 调用服务层更新考试状态 + return super.success(); // 返回成功响应 } - /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找考试 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页考试列表 */ - @ApiOperation(value = "考试视角") - @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) - public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.onlinePaging(reqDTO); - return super.success(page); + @ApiOperation(value = "考试视角") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 + // 分页查询并转换 + IPage page = baseService.onlinePaging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } /** - * 分页查找 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - - return super.success(page); + * 分页查找考试 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页考试列表 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "分页查找") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 + // 分页查询并转换 + IPage page = baseService.paging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } - /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找待阅试卷 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页待阅试卷列表 */ - @RequiresRoles("sa") - @ApiOperation(value = "待阅试卷") - @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) - public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { - //分页查询并转换 - IPage page = baseService.reviewPaging(reqDTO); - return super.success(page); + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "待阅试卷") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找待阅试卷的方法 + // 分页查询并转换 + IPage page = baseService.reviewPaging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } - - } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java index 90f86f1..8f9b69e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java @@ -1,101 +1,93 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import com.fasterxml.jackson.annotation.JsonFormat; -import com.yf.exam.modules.paper.enums.ExamState; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; +import com.fasterxml.jackson.annotation.JsonFormat; // 导入Jackson库的注解,用于格式化日期 +import com.yf.exam.modules.paper.enums.ExamState; // 导入考试状态枚举 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import org.springframework.format.annotation.DateTimeFormat; // 导入Spring的日期格式化注解 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="考试", description="考试") -public class ExamDTO implements Serializable { + *

+ * 考试数据传输类,封装考试的基本信息 + *

+ * 此类用于封装考试的基本信息,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试", description="考试") // Swagger注解,描述这个类的用途 +public class ExamDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - private static final long serialVersionUID = 1L; + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 考试ID + @ApiModelProperty(value = "考试名称", required=true) // Swagger注解,描述字段的用途和是否必填 + private String title; // 考试名称 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "考试描述", required=true) // Swagger注解,描述字段的用途和是否必填 + private String content; // 考试描述 - @ApiModelProperty(value = "考试名称", required=true) - private String title; + @ApiModelProperty(value = "1公开2部门3定员", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer openType; // 开放类型,1表示公开,2表示部门,3表示定员 - @ApiModelProperty(value = "考试描述", required=true) - private String content; + @ApiModelProperty(value = "考试状态", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer state; // 考试状态 - @ApiModelProperty(value = "1公开2部门3定员", required=true) - private Integer openType; + @ApiModelProperty(value = "是否限时", required=true) // Swagger注解,描述字段的用途和是否必填 + private Boolean timeLimit; // 是否限时 - @ApiModelProperty(value = "考试状态", required=true) - private Integer state; + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 + @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 + @ApiModelProperty(value = "开始时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date startTime; // 考试开始时间 - @ApiModelProperty(value = "是否限时", required=true) - private Boolean timeLimit; + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 + @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 + @ApiModelProperty(value = "结束时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date endTime; // 考试结束时间 - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") - @ApiModelProperty(value = "开始时间", required=true) - private Date startTime; + @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date createTime; // 创建时间 - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") - @ApiModelProperty(value = "结束时间", required=true) - private Date endTime; - - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; - - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; - - @ApiModelProperty(value = "总分数", required=true) - private Integer totalScore; - - @ApiModelProperty(value = "总时长(分钟)", required=true) - private Integer totalTime; - - @ApiModelProperty(value = "及格分数", required=true) - private Integer qualifyScore; + @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date updateTime; // 更新时间 + @ApiModelProperty(value = "总分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalScore; // 总分数 + @ApiModelProperty(value = "总时长(分钟)", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalTime; // 总时长(分钟) + @ApiModelProperty(value = "及格分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer qualifyScore; // 及格分数 /** - * 是否结束 - * @return + * 判断考试状态 + * 根据当前时间和考试的限时设置,返回考试的实际状态。 + * + * @return 当前考试状态 */ - public Integer getState(){ - - if(this.timeLimit!=null && this.timeLimit){ - - if(System.currentTimeMillis() < startTime.getTime() ){ - return ExamState.READY_START; + public Integer getState() { + if (this.timeLimit != null && this.timeLimit) { + if (System.currentTimeMillis() < startTime.getTime()) { + return ExamState.READY_START; // 如果当前时间小于开始时间,状态为准备开始 } - - if(System.currentTimeMillis() > endTime.getTime()){ - return ExamState.OVERDUE; + if (System.currentTimeMillis() > endTime.getTime()) { + return ExamState.OVERDUE; // 如果当前时间大于结束时间,状态为已过期 } - - if(System.currentTimeMillis() > startTime.getTime() + if (System.currentTimeMillis() > startTime.getTime() && System.currentTimeMillis() < endTime.getTime() - && !ExamState.DISABLED.equals(this.state)){ - return ExamState.ENABLE; + && !ExamState.DISABLED.equals(this.state)) { + return ExamState.ENABLE; // 如果当前时间在开始时间和结束时间之间,并且状态不是禁用,状态为正在进行 } - } - - return this.state; + return this.state; // 如果不满足上述条件,返回当前状态 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java index d0e54b7..7710955 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java @@ -1,33 +1,32 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.io.Serializable; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试部门数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Data -@ApiModel(value="考试部门", description="考试部门") -public class ExamDepartDTO implements Serializable { + *

+ * 考试部门数据传输类,封装考试部门相关信息 + *

+ * 此类用于封装与考试部门相关的数据,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试部门", description="考试部门") // Swagger注解,描述这个类的用途 +public class ExamDepartDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "考试ID", required=true) - private String examId; - - @ApiModelProperty(value = "部门ID", required=true) - private String departId; - -} + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 唯一标识符,标识考试部门记录的ID + + @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String examId; // 考试的唯一标识符,关联到具体的考试 + + @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String departId; // 部门的唯一标识符,关联到具体的部门 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java index 7244e9a..5cbc8a4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java @@ -1,51 +1,50 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.io.Serializable; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试题库数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@ApiModel(value="考试题库", description="考试题库") -public class ExamRepoDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "考试ID", required=true) - private String examId; - - @ApiModelProperty(value = "题库ID", required=true) - private String repoId; - - @ApiModelProperty(value = "单选题数量", required=true) - private Integer radioCount; - - @ApiModelProperty(value = "单选题分数", required=true) - private Integer radioScore; - - @ApiModelProperty(value = "多选题数量", required=true) - private Integer multiCount; - - @ApiModelProperty(value = "多选题分数", required=true) - private Integer multiScore; - - @ApiModelProperty(value = "判断题数量", required=true) - private Integer judgeCount; - - @ApiModelProperty(value = "判断题分数", required=true) - private Integer judgeScore; - -} + *

+ * 考试题库数据传输类,封装考试题库相关信息 + *

+ * 此类用于封装考试题库的数据,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试题库", description="考试题库") // Swagger注解,描述这个类的用途 +public class ExamRepoDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 题库ID,唯一标识符 + + @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String examId; // 关联的考试ID,标识与哪个考试相关联 + + @ApiModelProperty(value = "题库ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String repoId; // 题库ID,标识具体的题库 + + @ApiModelProperty(value = "单选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer radioCount; // 单选题数量,表示题库中单选题的总数 + + @ApiModelProperty(value = "单选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer radioScore; // 单选题分数,表示单选题的总分 + + @ApiModelProperty(value = "多选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer multiCount; // 多选题数量,表示题库中多选题的总数 + + @ApiModelProperty(value = "多选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer multiScore; // 多选题分数,表示多选题的总分 + + @ApiModelProperty(value = "判断题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer judgeCount; // 判断题数量,表示题库中判断题的总数 + + @ApiModelProperty(value = "判断题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer judgeScore; // 判断题分数,表示判断题的总分 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java index a566fec..e1887c3 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java @@ -1,32 +1,30 @@ -package com.yf.exam.modules.exam.dto.ext; +package com.yf.exam.modules.exam.dto.ext; // 定义包名,DTO扩展类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamRepoDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库数据传输类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试题库数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") -public class ExamRepoExtDTO extends ExamRepoDTO { + *

+ * 考试题库数据传输类的扩展,包含额外的题库信息 + *

+ * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") // Swagger注解,描述这个类的用途 +public class ExamRepoExtDTO extends ExamRepoDTO { // 声明类,继承自ExamRepoDTO - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 - - @ApiModelProperty(value = "单选题总量", required=true) - private Integer totalRadio; - - @ApiModelProperty(value = "多选题总量", required=true) - private Integer totalMulti; - - @ApiModelProperty(value = "判断题总量", required=true) - private Integer totalJudge; - + @ApiModelProperty(value = "单选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalRadio; // 单选题总量 + + @ApiModelProperty(value = "多选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalMulti; // 多选题总量 + + @ApiModelProperty(value = "判断题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalJudge; // 判断题总量 } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java index 5c1a95b..aa62266 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java @@ -1,32 +1,30 @@ -package com.yf.exam.modules.exam.dto.request; +package com.yf.exam.modules.exam.dto.request; // 定义包名,请求DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.util.List; +import java.util.List; // 导入Java的List接口,用于定义列表类型的属性 /** -*

-* 考试保存请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="考试保存请求类", description="考试保存请求类") -public class ExamSaveReqDTO extends ExamDTO { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "题库列表", required=true) - private List repoList; - - @ApiModelProperty(value = "考试部门列表", required=true) - private List departIds; - -} + *

+ * 考试保存请求类,封装考试保存请求的相关信息 + *

+ * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试保存请求类", description="考试保存请求类") // Swagger注解,描述这个类的用途 +public class ExamSaveReqDTO extends ExamDTO { // 声明类,继承自ExamDTO + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 + + @ApiModelProperty(value = "题库列表", required=true) // Swagger注解,描述字段的用途和是否必填 + private List repoList; // 题库列表,存储与考试相关的题库信息 + + @ApiModelProperty(value = "考试部门列表", required=true) // Swagger注解,描述字段的用途和是否必填 + private List departIds; // 考试部门ID列表,存储与考试相关的部门ID +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java index edbc5ce..ec344db 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java @@ -1,22 +1,21 @@ -package com.yf.exam.modules.exam.dto.response; +package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import io.swagger.annotations.ApiModel; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试分页响应类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") -public class ExamOnlineRespDTO extends ExamDTO { + *

+ * 在线考试分页响应类,封装在线考试的分页响应信息 + *

+ * 此类用于封装在线考试相关的分页数据,提供给前端展示。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") // Swagger注解,描述这个类的用途 +public class ExamOnlineRespDTO extends ExamDTO { // 声明类,继承自ExamDTO - private static final long serialVersionUID = 1L; - - -} + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java index 7d9ad36..68d4236 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java @@ -1,31 +1,28 @@ -package com.yf.exam.modules.exam.dto.response; +package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试分页响应类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") -public class ExamReviewRespDTO extends ExamDTO { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "考试人数", required=true) - private Integer examUser; - - @ApiModelProperty(value = "待阅试卷", required=true) - private Integer unreadPaper; - - - -} + *

+ * 阅卷分页响应类,封装阅卷相关的分页响应信息 + *

+ * 此类用于封装阅卷相关的分页数据,提供给前端展示。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") // Swagger注解,描述这个类的用途 +public class ExamReviewRespDTO extends ExamDTO { // 声明类,继承自ExamDTO + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "考试人数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer examUser; // 考试人数,表示参与考试的用户总数 + + @ApiModelProperty(value = "待阅试卷", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer unreadPaper; // 待阅试卷数量,表示尚未被阅卷的试卷数量 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java index e198c69..cd2d284 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java @@ -1,100 +1,61 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; -import java.util.Date; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@TableName("el_exam") -public class Exam extends Model { - - private static final long serialVersionUID = 1L; - - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; - - /** - * 考试名称 - */ - private String title; - - /** - * 考试描述 - */ - private String content; - - /** - * 1公开2部门3定员 - */ - @TableField("open_type") - private Integer openType; - - /** - * 考试状态 - */ - private Integer state; - - /** - * 是否限时 - */ - @TableField("time_limit") - private Boolean timeLimit; - - /** - * 开始时间 - */ - @TableField("start_time") - private Date startTime; - - /** - * 结束时间 - */ - @TableField("end_time") - private Date endTime; - - /** - * 创建时间 - */ - @TableField("create_time") - private Date createTime; - - /** - * 更新时间 - */ - @TableField("update_time") - private Date updateTime; - - /** - * 总分数 - */ - @TableField("total_score") - private Integer totalScore; - - /** - * 总时长(分钟) - */ - @TableField("total_time") - private Integer totalTime; - - /** - * 及格分数 - */ - @TableField("qualify_score") - private Integer qualifyScore; - -} + *

+ * 考试实体类,封装考试的基本信息 + *

+ * 此类用于数据库操作,映射考试表的字段。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class Exam extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 + + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID + private String id; // 考试ID,唯一标识符 + + private String title; // 考试名称,描述考试的标题 + + private String content; // 考试描述,详细描述考试的内容 + + @TableField("open_type") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer openType; // 开放类型,表示考试的开放范围(1公开,2部门,3定员) + + private Integer state; // 考试状态,表示考试的当前状态(如:未开始、进行中、已结束) + + @TableField("time_limit") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Boolean timeLimit; // 是否限时,表示考试是否有时间限制 + + @TableField("start_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date startTime; // 开始时间,表示考试的开始时间 + + @TableField("end_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date endTime; // 结束时间,表示考试的结束时间 + + @TableField("create_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date createTime; // 创建时间,表示记录的创建时间 + + @TableField("update_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date updateTime; // 更新时间,表示记录的最后更新时间 + + @TableField("total_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer totalScore; // 总分数,表示考试的总分 + + @TableField("total_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer totalTime; // 总时长(分钟),表示考试的总时长 + + @TableField("qualify_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer qualifyScore; // 及格分数,表示考试的及格分数线 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java index 19a4238..b39d71c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java @@ -1,42 +1,47 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 + +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试部门实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Data -@TableName("el_exam_depart") -public class ExamDepart extends Model { + *

+ * 考试部门实体类,封装考试部门的基本信息 + *

+ * 此类用于数据库操作,映射考试部门表的字段。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam_depart") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class ExamDepart extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 - private static final long serialVersionUID = 1L; - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) + * ID + * 唯一标识符,用于标识考试部门记录。 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID private String id; /** - * 考试ID - */ - @TableField("exam_id") + * 考试ID + * 关联的考试ID,标识这个部门所属的考试。 + */ + @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String examId; /** - * 部门ID - */ - @TableField("depart_id") + * 部门ID + * 关联的部门ID,标识参与考试的部门。 + */ + @TableField("depart_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String departId; - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java index 3884051..5249056 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java @@ -1,78 +1,87 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试题库实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@TableName("el_exam_repo") -public class ExamRepo extends Model { + *

+ * 考试题库实体类,封装考试题库的基本信息 + *

+ * 此类用于数据库操作,映射考试题库表的字段。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam_repo") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class ExamRepo extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 - private static final long serialVersionUID = 1L; - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) + * ID + * 唯一标识符,用于标识考试题库记录。 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID private String id; /** - * 考试ID - */ - @TableField("exam_id") + * 考试ID + * 关联的考试ID,标识这个题库所属的考试。 + */ + @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String examId; /** - * 题库ID - */ - @TableField("repo_id") + * 题库ID + * 关联的题库ID,标识具体的题库。 + */ + @TableField("repo_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String repoId; /** - * 单选题数量 - */ - @TableField("radio_count") + * 单选题数量 + * 题库中包含的单选题数量。 + */ + @TableField("radio_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer radioCount; /** - * 单选题分数 - */ - @TableField("radio_score") + * 单选题分数 + * 单选题的总分。 + */ + @TableField("radio_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer radioScore; /** - * 多选题数量 - */ - @TableField("multi_count") + * 多选题数量 + * 题库中包含的多选题数量。 + */ + @TableField("multi_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer multiCount; /** - * 多选题分数 - */ - @TableField("multi_score") + * 多选题分数 + * 多选题的总分。 + */ + @TableField("multi_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer multiScore; /** - * 判断题数量 - */ - @TableField("judge_count") + * 判断题数量 + * 题库中包含的判断题数量。 + */ + @TableField("judge_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer judgeCount; /** - * 判断题分数 - */ - @TableField("judge_score") + * 判断题分数 + * 判断题的总分。 + */ + @TableField("judge_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer judgeScore; - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java index 0c1f39a..60c30d2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java @@ -1,15 +1,17 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.exam.entity.ExamDepart; -/** -*

-* 考试部门Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -public interface ExamDepartMapper extends BaseMapper { +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 -} +/** + *

+ * 考试部门Mapper,提供考试部门的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试部门表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +public interface ExamDepartMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamDepart + // 继承BaseMapper,提供基本的CRUD操作(创建、读取、更新、删除) +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java index 1ce4504..f4908e8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java @@ -1,45 +1,52 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷分页响应DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试分页响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 /** -*

-* 考试Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -public interface ExamMapper extends BaseMapper { + *

+ * 考试Mapper,提供考试的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +public interface ExamMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为Exam /** * 查找分页内容 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询考试数据的分页结果。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含考试DTO的分页结果 */ IPage paging(Page page, @Param("query") ExamDTO query); /** * 查找分页内容 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询阅卷数据的分页结果。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含阅卷分页响应DTO的分页结果 */ IPage reviewPaging(Page page, @Param("query") ExamDTO query); /** * 在线考试分页响应类-考生视角 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询在线考试数据的分页结果,从考生视角。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含在线考试分页响应DTO的分页结果 */ IPage online(Page page, @Param("query") ExamDTO query); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java index 83407df..69900d2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java @@ -1,26 +1,29 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 +import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -public interface ExamRepoMapper extends BaseMapper { + *

+ * 考试题库Mapper,提供考试题库的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试题库表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +public interface ExamRepoMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamRepo /** * 查找考试题库列表 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询关联的考试题库列表,返回扩展的DTO对象。 + * + * @param examId 考试ID,用于指定查询哪个考试的题库列表 + * @return List 返回包含考试题库扩展信息的列表 */ - List listByExam(@Param("examId") String examId); -} + List listByExam(@Param("examId") String examId); // 使用MyBatis的@Param注解来指定方法参数的名称 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java index 301c010..068a6dc 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java @@ -1,32 +1,36 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.exam.entity.ExamDepart; +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试部门业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -public interface ExamDepartService extends IService { + *

+ * 考试部门业务类,提供考试部门的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试部门相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +public interface ExamDepartService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamDepart /** - * 保存全部 - * @param examId - * @param departs + * 保存全部部门信息 + * 方法用于根据给定的考试ID和部门ID列表,保存考试与部门的关联关系。 + * + * @param examId 考试ID,标识要关联的考试 + * @param departs 部门ID列表,包含要关联的部门ID */ void saveAll(String examId, List departs); - /** * 根据考试查找对应的部门 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询与之关联的部门ID列表。 + * + * @param examId 考试ID,用于指定查询哪个考试的部门 + * @return List 返回部门ID列表,包含所有与考试关联的部门ID */ List listByExam(String examId); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java index 78b4ec1..5758185 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java @@ -1,40 +1,45 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -public interface ExamRepoService extends IService { - + *

+ * 考试题库业务类,提供考试题库的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试题库相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +public interface ExamRepoService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamRepo /** - * 保存全部 - * @param examId - * @param list + * 保存全部题库信息 + * 方法用于根据给定的考试ID和题库列表,保存考试与题库的关联关系。 + * + * @param examId 考试ID,标识要关联的考试 + * @param list 题库列表,包含要关联的题库信息 */ void saveAll(String examId, List list); /** * 查找考试题库列表 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询与之关联的题库列表。 + * + * @param examId 考试ID,用于指定查询哪个考试的题库 + * @return List 返回题库列表,包含所有与考试关联的题库信息 */ List listByExam(String examId); /** * 清理脏数据 - * @param examId + * 方法用于清除与指定考试ID关联的题库数据,用于数据清理或重置场景。 + * + * @param examId 考试ID,用于指定要清理的考试关联的题库数据 */ void clear(String examId); - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java index 3f75664..47d77b8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java @@ -1,64 +1,75 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 /** -*

-* 考试业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -public interface ExamService extends IService { + *

+ * 考试业务类,提供考试的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +public interface ExamService extends IService { // 声明接口,继承自IService并指定操作的实体类为Exam /** * 保存考试信息 - * @param reqDTO + * 方法用于保存考试信息,包括考试的基本信息和相关联的题库、部门等。 + * + * @param reqDTO 考试保存请求数据传输对象,包含考试的详细信息 */ void save(ExamSaveReqDTO reqDTO); /** * 查找考试详情 - * @param id - * @return + * 方法用于根据考试ID查询考试的详细信息,包括考试的基本数据和相关联的部门、题库等。 + * + * @param id 考试ID,用于指定要查询的考试 + * @return ExamSaveReqDTO 返回考试详情,包含考试的详细信息 */ ExamSaveReqDTO findDetail(String id); /** * 查找考试详情--简要信息 - * @param id - * @return + * 方法用于根据考试ID查询考试的简要信息,通常用于列表展示。 + * + * @param id 考试ID,用于指定要查询的考试 + * @return ExamDTO 返回考试简要信息,包含考试的基本数据 */ ExamDTO findById(String id); /** - * 分页查询数据 - * @param reqDTO - * @return - */ + * 分页查询数据 + * 方法用于分页查询考试数据,通常用于列表展示。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页考试数据,包含考试列表和分页信息 + */ IPage paging(PagingReqDTO reqDTO); - /** * 在线考试分页响应类-考生视角 - * @param reqDTO - * @return + * 方法用于分页查询在线考试数据,从考生视角,通常用于考生查看可参加的考试列表。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页在线考试数据,包含在线考试列表和分页信息 */ IPage onlinePaging(PagingReqDTO reqDTO); - /** * 待阅试卷列表 - * @param reqDTO - * @return + * 方法用于分页查询待阅试卷数据,通常用于阅卷老师查看需要批改的试卷列表。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页待阅试卷数据,包含待阅试卷列表和分页信息 */ IPage reviewPaging(PagingReqDTO reqDTO); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java index 37ca2ff..3460e7c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java @@ -1,66 +1,64 @@ -package com.yf.exam.modules.exam.service.impl; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.modules.exam.entity.ExamDepart; -import com.yf.exam.modules.exam.mapper.ExamDepartMapper; -import com.yf.exam.modules.exam.service.ExamDepartService; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 +import com.yf.exam.modules.exam.mapper.ExamDepartMapper; // 导入考试部门Mapper接口 +import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 +import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 -import java.util.ArrayList; -import java.util.List; +import java.util.ArrayList; // 导入Java的ArrayList类 +import java.util.List; // 导入Java的List接口 /** -*

-* 考试部门业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Service -public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { + *

+ * 考试部门业务实现类,提供考试部门的具体业务逻辑实现 + *

+ * 此类实现了ExamDepartService接口,用于处理考试部门相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { // 声明类,继承自ServiceImpl并实现ExamDepartService接口 @Override public void saveAll(String examId, List departs) { - - // 先删除 + // 先删除已有的部门 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 + this.remove(wrapper); // 根据条件删除部门 - // 再增加 - if(CollectionUtils.isEmpty(departs)){ - throw new ServiceException(1, "请至少选择选择一个部门!!"); + // 再增加新的部门 + if (CollectionUtils.isEmpty(departs)) { // 检查部门列表是否为空 + throw new ServiceException(1, "请至少选择选择一个部门!!"); // 如果为空,抛出异常 } - List list = new ArrayList<>(); + List list = new ArrayList<>(); // 创建考试部门列表 - for(String id: departs){ - ExamDepart depart = new ExamDepart(); - depart.setDepartId(id); - depart.setExamId(examId); - list.add(depart); + for (String id : departs) { + ExamDepart depart = new ExamDepart(); // 创建考试部门对象 + depart.setDepartId(id); // 设置部门ID + depart.setExamId(examId); // 设置考试ID + list.add(depart); // 添加到列表 } - this.saveBatch(list); + this.saveBatch(list); // 批量保存部门 } @Override public List listByExam(String examId) { - // 先删除 + // 查找考试对应的部门 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); - List list = this.list(wrapper); - List ids = new ArrayList<>(); - if(!CollectionUtils.isEmpty(list)){ - for(ExamDepart item: list){ - ids.add(item.getDepartId()); + wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 + List list = this.list(wrapper); // 根据条件查询部门列表 + List ids = new ArrayList<>(); // 创建部门ID列表 + if (!CollectionUtils.isEmpty(list)) { // 检查部门列表是否为空 + for (ExamDepart item : list) { + ids.add(item.getDepartId()); // 添加部门ID到列表 } } - - return ids; - + return ids; // 返回部门ID列表 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java index ea630e6..e161f56 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java @@ -1,67 +1,63 @@ -package com.yf.exam.modules.exam.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; -import com.yf.exam.modules.exam.mapper.ExamRepoMapper; -import com.yf.exam.modules.exam.service.ExamRepoService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.util.List; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 +import com.yf.exam.modules.exam.mapper.ExamRepoMapper; // 导入考试题库Mapper接口 +import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 +import org.springframework.transaction.annotation.Transactional; // 导入Spring的事务注解 +import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 + +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Service -public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { - - - @Transactional(rollbackFor = Exception.class) + *

+ * 考试题库业务实现类,提供考试题库的具体业务逻辑实现 + *

+ * 此类实现了ExamRepoService接口,用于处理考试题库相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { // 声明类,继承自ServiceImpl并实现ExamRepoService接口 + + @Transactional(rollbackFor = Exception.class) // Spring事务注解,声明事务边界和回滚条件 @Override public void saveAll(String examId, List list) { - - // 先删除 + // 先删除已有的题库 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 + this.remove(wrapper); // 根据条件删除题库 - // 再增加 - if(CollectionUtils.isEmpty(list)){ - throw new ServiceException(1, "必须选择题库!"); + // 再增加新的题库 + if (CollectionUtils.isEmpty(list)) { // 检查题库列表是否为空 + throw new ServiceException(1, "必须选择题库!"); // 如果为空,抛出异常 } - List repos = BeanMapper.mapList(list, ExamRepo.class); - for(ExamRepo item: repos){ - item.setExamId(examId); - item.setId(IdWorker.getIdStr()); + List repos = BeanMapper.mapList(list, ExamRepo.class); // 使用BeanMapper将DTO列表转换为实体类列表 + for (ExamRepo item : repos) { + item.setExamId(examId); // 设置考试ID + item.setId(IdWorker.getIdStr()); // 使用IdWorker生成ID } - this.saveBatch(repos); + this.saveBatch(repos); // 批量保存题库 } @Override public List listByExam(String examId) { - return baseMapper.listByExam(examId); + return baseMapper.listByExam(examId); // 调用Mapper接口的方法,查找考试题库列表 } @Override public void clear(String examId) { - - // 先删除 + // 先删除已有的题库 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 + this.remove(wrapper); // 根据条件删除题库 } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java index 7451bd9..50ae151 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java @@ -1,194 +1,173 @@ -package com.yf.exam.modules.exam.service.impl; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.enums.OpenType; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.ExamRepoDTO; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import com.yf.exam.modules.exam.mapper.ExamMapper; -import com.yf.exam.modules.exam.service.ExamDepartService; -import com.yf.exam.modules.exam.service.ExamRepoService; -import com.yf.exam.modules.exam.service.ExamService; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.stereotype.Service; - -import java.util.List; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 + +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO +import com.yf.exam.core.enums.OpenType; // 导入开放类型枚举 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库DTO +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import com.yf.exam.modules.exam.mapper.ExamMapper; // 导入考试Mapper接口 +import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 +import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 +import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 +import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 +import org.springframework.dao.DuplicateKeyException; // 导入Spring的重复键异常类 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 + +import java.util.List; // 导入Java的List接口 /** -*

-* 考试业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Service -public class ExamServiceImpl extends ServiceImpl implements ExamService { - + *

+ * 考试业务实现类 + *

+ * 此类实现了ExamService接口,用于处理考试相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamServiceImpl extends ServiceImpl implements ExamService { // 声明类,继承自ServiceImpl并实现ExamService接口 @Autowired - private ExamRepoService examRepoService; + private ExamRepoService examRepoService; // 自动注入考试题库服务 @Autowired - private ExamDepartService examDepartService; + private ExamDepartService examDepartService; // 自动注入考试部门服务 @Override public void save(ExamSaveReqDTO reqDTO) { - // ID String id = reqDTO.getId(); - if(StringUtils.isBlank(id)){ - id = IdWorker.getIdStr(); + if(StringUtils.isBlank(id)){ // 如果ID为空,则生成新的ID + id = IdWorker.getIdStr(); // 使用IdWorker生成ID } - //复制参数 - Exam entity = new Exam(); + // 复制参数 + Exam entity = new Exam(); // 创建考试实体 // 计算分值 - this.calcScore(reqDTO); - + this.calcScore(reqDTO); // 调用方法计算分值 // 复制基本数据 - BeanMapper.copy(reqDTO, entity); - entity.setId(id); + BeanMapper.copy(reqDTO, entity); // 使用BeanMapper复制属性 + entity.setId(id); // 设置ID // 修复状态 - if (reqDTO.getTimeLimit()!=null + if (reqDTO.getTimeLimit() != null && !reqDTO.getTimeLimit() - && reqDTO.getState()!=null + && reqDTO.getState() != null && reqDTO.getState() == 2) { - entity.setState(0); + entity.setState(0); // 如果不限时且状态为2,则状态设置为0 } else { - entity.setState(reqDTO.getState()); + entity.setState(reqDTO.getState()); // 否则直接设置状态 } // 题库组卷 try { - examRepoService.saveAll(id, reqDTO.getRepoList()); + examRepoService.saveAll(id, reqDTO.getRepoList()); // 调用考试题库服务保存题库 }catch (DuplicateKeyException e){ - throw new ServiceException(1, "不能选择重复的题库!"); + throw new ServiceException(1, "不能选择重复的题库!"); // 如果出现重复键异常,则抛出服务异常 } - // 开放的部门 - if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ - examDepartService.saveAll(id, reqDTO.getDepartIds()); + if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ // 如果开放类型为部门开放 + examDepartService.saveAll(id, reqDTO.getDepartIds()); // 调用考试部门服务保存部门 } - this.saveOrUpdate(entity); - + this.saveOrUpdate(entity); // 保存或更新考试实体 } @Override public ExamSaveReqDTO findDetail(String id) { - ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); - Exam exam = this.getById(id); - BeanMapper.copy(exam, respDTO); + ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); // 创建响应DTO + Exam exam = this.getById(id); // 根据ID查询考试实体 + BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 // 考试部门 - List departIds = examDepartService.listByExam(id); - respDTO.setDepartIds(departIds); + List departIds = examDepartService.listByExam(id); // 调用考试部门服务查询部门ID列表 + respDTO.setDepartIds(departIds); // 设置部门ID列表 // 题库 - List repos = examRepoService.listByExam(id); - respDTO.setRepoList(repos); + List repos = examRepoService.listByExam(id); // 调用考试题库服务查询题库列表 + respDTO.setRepoList(repos); // 设置题库列表 - return respDTO; + return respDTO; // 返回响应DTO } @Override public ExamDTO findById(String id) { - ExamDTO respDTO = new ExamDTO(); - Exam exam = this.getById(id); - BeanMapper.copy(exam, respDTO); - return respDTO; + ExamDTO respDTO = new ExamDTO(); // 创建响应DTO + Exam exam = this.getById(id); // 根据ID查询考试实体 + BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 + return respDTO; // 返回响应DTO } @Override public IPage paging(PagingReqDTO reqDTO) { + // 创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 - //创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); - - //转换结果 - IPage pageData = baseMapper.paging(page, reqDTO.getParams()); - return pageData; - } + // 转换结果 + IPage pageData = baseMapper.paging(page, reqDTO.getParams()); // 调用Mapper接口的分页方法 + return pageData; // 返回分页结果 + } @Override public IPage onlinePaging(PagingReqDTO reqDTO) { - - // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 // 查找分页 - IPage pageData = baseMapper.online(page, reqDTO.getParams()); - - return pageData; + IPage pageData = baseMapper.online(page, reqDTO.getParams()); // 调用Mapper接口的在线考试分页方法 + return pageData; // 返回分页结果 } @Override public IPage reviewPaging(PagingReqDTO reqDTO) { // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 // 查找分页 - IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); - - return pageData; + IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); // 调用Mapper接口的阅卷分页方法 + return pageData; // 返回分页结果 } - /** * 计算分值 - * @param reqDTO + * 方法用于计算考试的总分值,根据题库中的题目数量和分数。 + * + * @param reqDTO 考试保存请求DTO */ - private void calcScore(ExamSaveReqDTO reqDTO){ - + private void calcScore(ExamSaveReqDTO reqDTO) { // 主观题分数 int objScore = 0; // 题库组卷 - List repoList = reqDTO.getRepoList(); - - for(ExamRepoDTO item: repoList){ - if(item.getRadioCount()!=null - && item.getRadioCount()>0 - && item.getRadioScore()!=null - && item.getRadioScore()>0){ - objScore+=item.getRadioCount()*item.getRadioScore(); + List repoList = reqDTO.getRepoList(); // 获取题库列表 + + for(ExamRepoDTO item : repoList){ // 遍历题库列表 + if(item.getRadioCount() != null && item.getRadioCount() > 0 && item.getRadioScore() != null && item.getRadioScore() > 0){ + objScore += item.getRadioCount() * item.getRadioScore(); // 计算单选题分数 } - if(item.getMultiCount()!=null - && item.getMultiCount()>0 - && item.getMultiScore()!=null - && item.getMultiScore()>0){ - objScore+=item.getMultiCount()*item.getMultiScore(); + if(item.getMultiCount() != null && item.getMultiCount() > 0 && item.getMultiScore() != null && item.getMultiScore() > 0){ + objScore += item.getMultiCount() * item.getMultiScore(); // 计算多选题分数 } - if(item.getJudgeCount()!=null - && item.getJudgeCount()>0 - && item.getJudgeScore()!=null - && item.getJudgeScore()>0){ - objScore+=item.getJudgeCount()*item.getJudgeScore(); + if(item.getJudgeCount() != null && item.getJudgeCount() > 0 && item.getJudgeScore() != null && item.getJudgeScore() > 0){ + objScore += item.getJudgeCount() * item.getJudgeScore(); // 计算判断题分数 } } - - - reqDTO.setTotalScore(objScore); + reqDTO.setTotalScore(objScore); // 设置总分值 } - -} +} \ No newline at end of file From 07f12faadcc46918a5b357e43c8e0aa866065792 Mon Sep 17 00:00:00 2001 From: zl <3216908512@qq.com> Date: Wed, 27 Nov 2024 19:19:11 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E5=B4=94=E6=99=BA=E5=B0=A7=E5=88=86?= =?UTF-8?q?=E6=94=AF=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yf/exam/ability/Constant.java | 13 +- .../yf/exam/ability/job/enums/JobGroup.java | 14 +- .../yf/exam/ability/job/enums/JobPrefix.java | 15 +- .../exam/ability/job/service/JobService.java | 51 +- .../job/service/impl/JobServiceImpl.java | 129 +-- .../ability/shiro/CNFilterFactoryBean.java | 38 +- .../com/yf/exam/ability/shiro/ShiroRealm.java | 246 +++--- .../yf/exam/ability/shiro/aop/JwtFilter.java | 113 +-- .../yf/exam/ability/shiro/jwt/JwtToken.java | 41 +- .../yf/exam/ability/shiro/jwt/JwtUtils.java | 90 +- .../ability/upload/config/UploadConfig.java | 36 +- .../upload/controller/UploadController.java | 71 +- .../exam/ability/upload/dto/UploadReqDTO.java | 30 +- .../ability/upload/dto/UploadRespDTO.java | 35 +- .../ability/upload/service/UploadService.java | 58 +- .../service/impl/UploadServiceImpl.java | 144 ++- .../exam/ability/upload/utils/FileUtils.java | 321 +++---- .../exam/ability/upload/utils/MediaUtils.java | 76 +- .../java/com/yf/exam/aspect/DictAspect.java | 215 ++--- .../exam/aspect/mybatis/QueryInterceptor.java | 177 +--- .../aspect/mybatis/UpdateInterceptor.java | 126 +-- .../com/yf/exam/aspect/utils/InjectUtils.java | 111 +-- .../java/com/yf/exam/config/CorsConfig.java | 58 +- .../com/yf/exam/config/MultipartConfig.java | 53 +- .../com/yf/exam/config/MybatisConfig.java | 55 +- .../com/yf/exam/config/ScheduledConfig.java | 141 +-- .../java/com/yf/exam/config/ShiroConfig.java | 242 +++-- .../com/yf/exam/config/SwaggerConfig.java | 155 +--- .../exam/controller/ExamController.java | 233 ++--- .../com/yf/exam/modules/exam/dto/ExamDTO.java | 140 +-- .../exam/modules/exam/dto/ExamDepartDTO.java | 55 +- .../yf/exam/modules/exam/dto/ExamRepoDTO.java | 93 +- .../modules/exam/dto/ext/ExamRepoExtDTO.java | 50 +- .../exam/dto/request/ExamSaveReqDTO.java | 54 +- .../exam/dto/response/ExamOnlineRespDTO.java | 35 +- .../exam/dto/response/ExamReviewRespDTO.java | 53 +- .../com/yf/exam/modules/exam/entity/Exam.java | 155 ++-- .../exam/modules/exam/entity/ExamDepart.java | 65 +- .../yf/exam/modules/exam/entity/ExamRepo.java | 105 +-- .../modules/exam/mapper/ExamDepartMapper.java | 28 +- .../exam/modules/exam/mapper/ExamMapper.java | 61 +- .../modules/exam/mapper/ExamRepoMapper.java | 39 +- .../exam/service/ExamDepartService.java | 42 +- .../modules/exam/service/ExamRepoService.java | 49 +- .../modules/exam/service/ExamService.java | 77 +- .../service/impl/ExamDepartServiceImpl.java | 88 +- .../service/impl/ExamRepoServiceImpl.java | 92 +- .../exam/service/impl/ExamServiceImpl.java | 209 +++-- .../paper/controller/PaperController.java | 127 +-- .../yf/exam/modules/paper/dto/PaperDTO.java | 106 +-- .../modules/paper/dto/PaperQuAnswerDTO.java | 64 +- .../yf/exam/modules/paper/dto/PaperQuDTO.java | 71 +- .../paper/dto/ext/PaperQuAnswerExtDTO.java | 25 +- .../paper/dto/ext/PaperQuDetailDTO.java | 29 +- .../paper/dto/request/PaperAnswerDTO.java | 23 +- .../paper/dto/request/PaperCreateReqDTO.java | 22 +- .../paper/dto/request/PaperListReqDTO.java | 39 +- .../paper/dto/request/PaperQuQueryDTO.java | 22 +- .../paper/dto/response/ExamDetailRespDTO.java | 50 +- .../paper/dto/response/ExamResultRespDTO.java | 25 +- .../paper/dto/response/PaperListRespDTO.java | 35 +- .../yf/exam/modules/paper/entity/Paper.java | 105 +-- .../yf/exam/modules/paper/entity/PaperQu.java | 60 +- .../modules/paper/entity/PaperQuAnswer.java | 53 +- .../exam/modules/paper/enums/ExamState.java | 17 +- .../exam/modules/paper/enums/PaperState.java | 17 +- .../exam/modules/paper/job/BreakExamJob.java | 60 +- .../modules/paper/mapper/PaperMapper.java | 53 +- .../paper/mapper/PaperQuAnswerMapper.java | 32 +- .../modules/paper/mapper/PaperQuMapper.java | 44 +- .../paper/service/PaperQuAnswerService.java | 36 +- .../modules/paper/service/PaperQuService.java | 54 +- .../modules/paper/service/PaperService.java | 73 +- .../impl/PaperQuAnswerServiceImpl.java | 96 +- .../service/impl/PaperQuServiceImpl.java | 142 ++- .../paper/service/impl/PaperServiceImpl.java | 832 ++++++++++-------- .../modules/qu/controller/QuController.java | 294 +++---- .../yf/exam/modules/qu/dto/QuAnswerDTO.java | 64 +- .../com/yf/exam/modules/qu/dto/QuDTO.java | 91 +- .../com/yf/exam/modules/qu/dto/QuRepoDTO.java | 66 +- .../modules/qu/dto/export/QuExportDTO.java | 76 +- .../modules/qu/dto/export/QuImportDTO.java | 55 +- .../exam/modules/qu/dto/ext/QuDetailDTO.java | 40 +- .../modules/qu/dto/request/QuQueryReqDTO.java | 60 +- .../qu/dto/request/QuRepoBatchReqDTO.java | 51 +- .../com/yf/exam/modules/qu/entity/Qu.java | 60 +- .../yf/exam/modules/qu/entity/QuAnswer.java | 46 +- .../com/yf/exam/modules/qu/entity/QuRepo.java | 51 +- .../com/yf/exam/modules/qu/enums/QuType.java | 9 +- .../modules/qu/mapper/QuAnswerMapper.java | 14 +- .../yf/exam/modules/qu/mapper/QuMapper.java | 58 +- .../exam/modules/qu/mapper/QuRepoMapper.java | 9 +- .../modules/qu/service/QuAnswerService.java | 26 +- .../modules/qu/service/QuRepoService.java | 61 +- .../yf/exam/modules/qu/service/QuService.java | 69 +- .../qu/service/impl/QuAnswerServiceImpl.java | 102 ++- .../qu/service/impl/QuRepoServiceImpl.java | 127 +-- .../qu/service/impl/QuServiceImpl.java | 140 +-- .../modules/qu/utils/ImageCheckUtils.java | 23 +- 99 files changed, 4090 insertions(+), 4391 deletions(-) diff --git a/src-源文件/main/java/com/yf/exam/ability/Constant.java b/src-源文件/main/java/com/yf/exam/ability/Constant.java index 50e754d..9880ea6 100644 --- a/src-源文件/main/java/com/yf/exam/ability/Constant.java +++ b/src-源文件/main/java/com/yf/exam/ability/Constant.java @@ -1,18 +1,15 @@ -// 定义包路径,用于存放系统基础功能相关的类 package com.yf.exam.ability; + /** - * 通用常量类 - * 用于定义系统中使用的常量值,提供全局可访问的常量。 + * 通用常量 * @author bool */ public class Constant { + /** - * 文件上传路径的前缀常量 - * 用于指定上传文件的基础路径,所有上传的文件URL都会以这个路径开头。 - * 例如: /upload/file/example.jpg - * 这个前缀用于构建和解析文件的URL,以便在系统中统一管理和访问上传的文件。 + * 文件上传路径 */ public static final String FILE_PREFIX = "/upload/file/"; -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java index 058ab16..2159361 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java @@ -1,19 +1,13 @@ -// 定义包路径,用于存放任务分组相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务分组枚举接口 - * 定义系统中不同类型任务的分组标识 - * 这个接口用于集中管理任务分组的常量值,确保代码的一致性和可维护性。 - * + * 任务分组 * @author van */ public interface JobGroup { /** - * 系统任务的分组标识 - * 用于标识系统级别的定时任务,如系统维护、数据清理等。 - * 这个标识符用于在任务调度系统中区分系统级别的任务,便于管理和执行。 + * 系统任务 */ - String SYSTEM = "system"; // 系统任务组的标识符 -} \ No newline at end of file + String SYSTEM = "system"; +} diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java index dd51986..2536f0e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java @@ -1,19 +1,14 @@ -// 定义包路径,用于存放任务前缀相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务前缀枚举接口 - * 定义系统中不同任务类型的前缀标识 - * 这个接口用于集中管理任务的前缀常量值,确保代码的一致性和可维护性。 - * + * 任务前缀 * @author bool */ public interface JobPrefix { /** - * 强制交卷任务的前缀标识 - * 用于标识与强制交卷相关的定时任务,方便在任务调度系统中识别和处理。 - * 例如:break_exam_12345 表示ID为12345的考试的强制交卷任务。 + * 强制交卷的 */ - String BREAK_EXAM = "break_exam_"; // 强制交卷任务的前缀标识符 -} \ No newline at end of file + String BREAK_EXAM = "break_exam_"; + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java index 410c006..cb465de 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java @@ -1,66 +1,53 @@ -// 定义包路径,用于存放任务服务接口 package com.yf.exam.ability.job.service; /** - * 任务业务接口类,用于定义任务相关的业务操作 - * 这个接口定义了定时任务的基本操作,包括添加、暂停、恢复和删除任务。 - * + * 任务业务类,用于动态处理任务信息 * @author bool * @date 2020/11/29 下午2:17 */ public interface JobService { + /** - * 任务数据的键名常量 - * 用于在任务的JobDataMap中存储和检索任务相关数据的键名。 + * 任务数据 */ - String TASK_DATA = "taskData"; // 用于存储任务相关数据的键名 + String TASK_DATA = "taskData"; /** * 添加定时任务 - * 方法用于根据给定的任务类、名称、cron表达式和任务数据,添加一个新的定时任务。 - * - * @param jobClass 任务类,指定任务的执行类 - * @param jobName 任务名称,用于唯一标识任务 - * @param cron cron表达式,用于指定任务的执行计划 - * @param data 任务数据,传递给任务执行时的参数 + * @param jobClass + * @param jobName + * @param cron + * @param data */ void addCronJob(Class jobClass, String jobName, String cron, String data); /** * 添加立即执行的任务 - * 方法用于根据给定的任务类、名称和任务数据,添加一个新的立即执行的任务。 - * - * @param jobClass 任务类,指定任务的执行类 - * @param jobName 任务名称,用于唯一标识任务 - * @param data 任务数据,传递给任务执行时的参数 + * @param jobClass + * @param jobName + * @param data */ void addCronJob(Class jobClass, String jobName, String data); /** * 暂停任务 - * 方法用于根据任务名称和任务组,暂停一个正在运行的定时任务。 - * - * @param jobName 任务名称 - * @param jobGroup 任务组 + * @param jobName + * @param jobGroup */ void pauseJob(String jobName, String jobGroup); /** * 恢复任务 - * 方法用于根据触发器名称和触发器组,恢复一个已暂停的定时任务。 - * - * @param triggerName 触发器名称 - * @param triggerGroup 触发器组 + * @param triggerName + * @param triggerGroup */ void resumeJob(String triggerName, String triggerGroup); /** - * 删除任务 - * 方法用于根据任务名称和任务组,删除一个定时任务,包括任务本身和相关的触发器。 - * - * @param jobName 任务名称 - * @param jobGroup 任务组 + * 删除job + * @param jobName + * @param jobGroup */ void deleteJob(String jobName, String jobGroup); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java index b34ea8e..aafdfdb 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java @@ -1,186 +1,123 @@ -// 定义包路径,用于存放任务服务实现类 package com.yf.exam.ability.job.service.impl; -// 导入所需的外部依赖包 -import com.alibaba.fastjson.JSON; // 用于JSON数据处理 -import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 用于生成唯一ID -import com.yf.exam.ability.job.enums.JobGroup; // 任务分组枚举 -import com.yf.exam.ability.job.service.JobService; // 任务服务接口 -import lombok.extern.log4j.Log4j2; // 日志注解 -import org.quartz.*; // Quartz定时任务框架相关类 -import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 -import org.springframework.scheduling.quartz.SchedulerFactoryBean; // Quartz调度器工厂Bean -import org.springframework.stereotype.Service; // Spring服务注解 -import org.springframework.util.StringUtils; // Spring字符串工具类 +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.yf.exam.ability.job.enums.JobGroup; +import com.yf.exam.ability.job.service.JobService; +import lombok.extern.log4j.Log4j2; +import org.quartz.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; /** - * 定时任务服务实现类 - * 用于管理系统中的定时任务,包括添加、暂停、恢复和删除任务。 * @author bool */ -@Log4j2 // 启用Log4j2日志 -@Service // 标记为Spring服务组件 +@Log4j2 +@Service public class JobServiceImpl implements JobService { /** - * Quartz定时任务调度器 - * 用于管理和执行所有的定时任务 + * Quartz定时任务核心的功能实现类 */ - private Scheduler scheduler; // 定时任务调度器实例 + private Scheduler scheduler; /** - * 构造函数,注入SchedulerFactoryBean - * 从Spring容器中注入Quartz调度器工厂Bean,并从中获取调度器实例。 - * @param schedulerFactoryBean Quartz调度器工厂Bean + * 注入 + * @param schedulerFactoryBean */ public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) { - // 从工厂Bean中获取调度器实例 scheduler = schedulerFactoryBean.getScheduler(); } - /** - * 添加定时任务 - * 方法用于添加一个新的定时任务,包括cron表达式和立即执行两种情况。 - * - * @param jobClass 任务类,指定任务的执行类 - * @param jobName 任务名称,用于唯一标识任务 - * @param cron cron表达式,用于指定任务的执行计划 - * @param data 任务数据,传递给任务执行时的参数 - */ + @Override public void addCronJob(Class jobClass, String jobName, String cron, String data) { - // 设置任务组为系统任务组 + + String jobGroup = JobGroup.SYSTEM; - // 如果任务名为空,则自动生成任务名 + // 自动命名 if(StringUtils.isEmpty(jobName)){ - // 使用类名大写+下划线+唯一ID作为任务名 - jobName = jobClass.getSimpleName().toUpperCase() + "_" + IdWorker.getIdStr(); + jobName = jobClass.getSimpleName().toUpperCase() + "_"+IdWorker.getIdStr(); } try { - // 创建任务键,用于唯一标识任务 JobKey jobKey = JobKey.jobKey(jobName, jobGroup); - // 获取任务详情 JobDetail jobDetail = scheduler.getJobDetail(jobKey); - - // 如果任务已存在,则删除旧任务 if (jobDetail != null) { log.info("++++++++++任务:{} 已存在", jobName); this.deleteJob(jobName, jobGroup); } - // 记录任务构建信息 log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data); - // 构建新的任务详情 + //构建job信息 jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build(); - // 设置任务数据 + //用JopDataMap来传递数据 jobDetail.getJobDataMap().put(TASK_DATA, data); - // 声明触发器 + //按新的cronExpression表达式构建一个新的trigger Trigger trigger = null; - // 如果有cron表达式,则创建cron触发器 + // 有表达式的按表达式 if(!StringUtils.isEmpty(cron)){ log.info("+++++表达式执行:"+ JSON.toJSONString(jobDetail)); - // 创建cron调度构建器 + //表达式调度构建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron); - // 构建触发器 - trigger = TriggerBuilder.newTrigger() - .withIdentity(jobName, jobGroup) - .withSchedule(scheduleBuilder) - .build(); + trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build(); }else{ - // 无cron表达式则立即执行一次 + // 无表达式则立即执行 log.info("+++++立即执行:"+ JSON.toJSONString(jobDetail)); - // 构建立即执行的触发器 - trigger = TriggerBuilder.newTrigger() - .withIdentity(jobName, jobGroup) - .startNow() - .build(); + trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build(); } - // 调度任务 scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { - // 打印异常堆栈信息 e.printStackTrace(); } } - /** - * 添加立即执行的任务 - * 方法用于添加一个不需要cron表达式,立即执行一次的任务。 - * - * @param jobClass 任务类 - * @param jobName 任务名称 - * @param data 任务数据 - */ + @Override public void addCronJob(Class jobClass, String jobName, String data) { - // 立即执行任务,不需要cron表达式,传入null + // 立即执行任务 this.addCronJob(jobClass, jobName, null, data); } - /** - * 暂停任务 - * 方法用于暂停一个正在运行的定时任务。 - * - * @param jobName 任务名称 - * @param jobGroup 任务组 - */ + @Override public void pauseJob(String jobName, String jobGroup) { try { - // 创建触发器键并暂停触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.pauseTrigger(triggerKey); log.info("++++++++++暂停任务:{}", jobName); } catch (SchedulerException e) { - // 打印异常堆栈信息 e.printStackTrace(); } } - /** - * 恢复任务 - * 方法用于恢复一个已暂停的定时任务。 - * - * @param jobName 任务名称 - * @param jobGroup 任务组 - */ @Override public void resumeJob(String jobName, String jobGroup) { try { - // 创建触发器键并恢复触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.resumeTrigger(triggerKey); log.info("++++++++++重启任务:{}", jobName); } catch (SchedulerException e) { - // 打印异常堆栈信息 e.printStackTrace(); } } - /** - * 删除任务 - * 方法用于删除一个定时任务,包括任务本身和相关的触发器。 - * - * @param jobName 任务名称 - * @param jobGroup 任务组 - */ @Override public void deleteJob(String jobName, String jobGroup) { try { - // 创建任务键并删除任务 JobKey jobKey = JobKey.jobKey(jobName,jobGroup); scheduler.deleteJob(jobKey); log.info("++++++++++删除任务:{}", jobKey); } catch (SchedulerException e) { - // 打印异常堆栈信息 e.printStackTrace(); } } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java index 8d54a3e..3bc2190 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java @@ -1,39 +1,29 @@ -// 定义包路径,用于存放自定义过滤器相关的类 package com.yf.exam.ability.shiro; -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类,用于配置Shiro过滤器 -import org.apache.shiro.web.filter.InvalidRequestFilter; // Shiro无效请求过滤器,用于处理无效请求 -import org.apache.shiro.web.filter.mgt.DefaultFilter; // Shiro默认过滤器,提供默认的过滤逻辑 -import org.apache.shiro.web.filter.mgt.FilterChainManager; // Shiro过滤器链管理器,管理过滤器链的配置 +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.filter.InvalidRequestFilter; +import org.apache.shiro.web.filter.mgt.DefaultFilter; +import org.apache.shiro.web.filter.mgt.FilterChainManager; -import javax.servlet.Filter; // Servlet过滤器接口,定义了过滤器的基本操作 -import java.util.Map; // Map集合类,用于存储键值对 +import javax.servlet.Filter; +import java.util.Map; /** - * 自定义过滤器工厂类,用于创建和管理Shiro过滤器链 - * 主要解决中文URL问题,如下载文件中包含中文字符时可能会返回400错误。 - * 例如:https://youdomain.com/upload/file/云帆考试系统用户手册.pdf 这样的URL可能会因为中文字符而导致问题。 + * 自定义过滤器,用于处理中文URL问题 + * 如:下载文件中包含中文会返回400错误,https://youdomain.com/upload/file/云帆考试系统用户手册.pdf * @author van */ public class CNFilterFactoryBean extends ShiroFilterFactoryBean { - /** - * 创建过滤器链管理器 - * 覆盖父类的创建方法,添加自定义的过滤器配置。 - * @return FilterChainManager 过滤器链管理器实例 - */ @Override protected FilterChainManager createFilterChainManager() { - FilterChainManager manager = super.createFilterChainManager(); // 调用父类方法创建过滤器链管理器 - - // 获取过滤器映射,以便修改特定过滤器的配置 - Map filterMap = manager.getFilters(); - // 获取无效请求过滤器实例 - Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); + FilterChainManager manager = super.createFilterChainManager(); + // URL携带中文400,servletPath中文校验bug + Map filterMap = manager.getFilters(); + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); if (invalidRequestFilter instanceof InvalidRequestFilter) { - // 设置无效请求过滤器不阻止非ASCII字符,以允许中文URL ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); } - return manager; // 返回配置好的过滤器链管理器 + return manager; } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java index d9b5844..76af5c5 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java @@ -1,135 +1,131 @@ -// 定义包路径,用于存放Shiro领域相关的类 package com.yf.exam.ability.shiro; -import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 -import com.yf.exam.ability.shiro.jwt.JwtUtils; // JWT工具类 -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 用户登录DTO -import com.yf.exam.modules.sys.user.service.SysUserRoleService; // 用户角色服务 -import com.yf.exam.modules.sys.user.service.SysUserService; // 用户服务 -import lombok.extern.slf4j.Slf4j; // 日志注解 -import org.apache.shiro.authc.AuthenticationException; // 认证异常 -import org.apache.shiro.authc.AuthenticationInfo; // 认证信息 -import org.apache.shiro.authc.AuthenticationToken; // 认证令牌 -import org.apache.shiro.authc.SimpleAuthenticationInfo; // 简单认证信息 -import org.apache.shiro.authz.AuthorizationInfo; // 授权信息 -import org.apache.shiro.authz.SimpleAuthorizationInfo; // 简单授权信息 -import org.apache.shiro.realm.AuthorizingRealm; // 授权领域 -import org.apache.shiro.subject.PrincipalCollection; // 主体集合 -import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 -import org.springframework.context.annotation.Lazy; // 延迟注入注解 -import org.springframework.stereotype.Component; // Spring组件注解 - -import java.util.HashSet; // 哈希集合 -import java.util.List; // 列表 + +import com.yf.exam.ability.shiro.jwt.JwtToken; +import com.yf.exam.ability.shiro.jwt.JwtUtils; +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; +import com.yf.exam.modules.sys.user.service.SysUserRoleService; +import com.yf.exam.modules.sys.user.service.SysUserService; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.authc.AuthenticationException; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.SimpleAuthenticationInfo; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.subject.PrincipalCollection; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; /** - * 用户登录鉴权和获取用户授权的Shiro领域类 - * 负责用户的认证和授权,是Shiro框架中的核心组件之一。 + * 用户登录鉴权和获取用户授权 * @author bool */ -@Component // 标记为Spring组件 -@Slf4j // 启用Slf4j日志 +@Component +@Slf4j public class ShiroRealm extends AuthorizingRealm { - @Autowired - @Lazy // 延迟注入,避免循环依赖 - private SysUserService sysUserService; // 用户服务 - - @Autowired - @Lazy // 延迟注入,避免循环依赖 - private SysUserRoleService sysUserRoleService; // 用户角色服务 - - /** - * 判断是否支持JWT令牌 - * 确定当前领域是否支持处理JWT令牌类型的认证。 - * @param token 认证令牌 - * @return 是否支持JWT令牌 - */ - @Override - public boolean supports(AuthenticationToken token) { - // 判断是否支持JWT令牌 - return token instanceof JwtToken; // 返回是否为JwtToken - } - - /** - * 详细授权认证 - * 获取用户的授权信息,包括角色和权限。 - * @param principals 主体集合 - * @return 授权信息 - */ - @Override - protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - String userId = null; // 用户ID - if (principals != null) { - SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); // 获取用户信息 - userId = user.getId(); // 获取用户ID - } - SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 创建授权信息 - - // 查找用户角色 - List roles = sysUserRoleService.listRoles(userId); // 获取用户角色列表 - info.setRoles(new HashSet<>(roles)); // 设置角色 - - log.info("++++++++++校验详细权限完成"); // 日志记录 - return info; // 返回授权信息 - } - - /** - * 校验用户的账号密码是否正确 - * 根据传入的认证令牌,验证用户的账号密码。 - * @param auth 认证令牌 - * @return 认证信息 - * @throws AuthenticationException 认证异常 - */ - @Override - protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { - String token = (String) auth.getCredentials(); // 获取token - if (token == null) { - throw new AuthenticationException("token为空!"); // 抛出异常 - } - - // 校验token有效性 - SysUserLoginDTO user = this.checkToken(token); // 验证token并获取用户信息 - return new SimpleAuthenticationInfo(user, token, getName()); // 返回认证信息 - } - - /** - * 校验Token的有效性 - * 验证JWT令牌的有效性,并获取对应的用户信息。 - * @param token JWT令牌 - * @return 用户登录DTO - * @throws AuthenticationException 认证异常 - */ - public SysUserLoginDTO checkToken(String token) throws AuthenticationException { - // 查询用户信息 - log.debug("++++++++++校验用户token: "+ token); // 日志记录 - - // 从token中获取用户名 - String username = JwtUtils.getUsername(token); // 获取用户名 - log.debug("++++++++++用户名: "+ username); // 日志记录 - - if (username == null) { - throw new AuthenticationException("无效的token"); // 抛出异常 - } - - // 查找登录用户对象 - SysUserLoginDTO user = sysUserService.token(token); // 获取用户信息 - - // 校验token是否失效 - if (!JwtUtils.verify(token, username)) { - throw new AuthenticationException("登陆失效,请重试登陆!"); // 抛出异常 - } - - return user; // 返回用户信息 - } - - /** - * 清除当前用户的权限认证缓存 - * 用于在用户信息变更后,清除缓存,确保权限信息的更新。 - * @param principals 主体集合 - */ - @Override + @Autowired + @Lazy + private SysUserService sysUserService; + + @Autowired + @Lazy + private SysUserRoleService sysUserRoleService; + + + @Override + public boolean supports(AuthenticationToken token) { + return token instanceof JwtToken; + } + + + /** + * 详细授权认证 + * @param principals + * @return + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + + String userId = null; + if (principals != null) { + SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); + userId = user.getId(); + } + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); + + // 查找用户角色 + List roles = sysUserRoleService.listRoles(userId); + info.setRoles(new HashSet<>(roles)); + + log.info("++++++++++校验详细权限完成"); + return info; + } + + /** + * 校验用户的账号密码是否正确 + * @param auth + * @return + * @throws AuthenticationException + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { + String token = (String) auth.getCredentials(); + if (token == null) { + throw new AuthenticationException("token为空!"); + } + + // 校验token有效性 + SysUserLoginDTO user = this.checkToken(token); + return new SimpleAuthenticationInfo(user, token, getName()); + } + + + /** + * 校验Token的有效性 + * @param token + * @return + * @throws AuthenticationException + */ + public SysUserLoginDTO checkToken(String token) throws AuthenticationException { + + // 查询用户信息 + log.debug("++++++++++校验用户token: "+ token); + + // 从token中获取用户名 + String username = JwtUtils.getUsername(token); + log.debug("++++++++++用户名: "+ username); + + if (username == null) { + throw new AuthenticationException("无效的token"); + } + + // 查找登录用户对象 + SysUserLoginDTO user = sysUserService.token(token); + + // 校验token是否失效 + if (!JwtUtils.verify(token, username)) { + throw new AuthenticationException("登陆失效,请重试登陆!"); + } + + return user; + } + + + + /** + * 清除当前用户的权限认证缓存 + * @param principals + */ + @Override public void clearCache(PrincipalCollection principals) { - super.clearCache(principals); // 清除缓存 + super.clearCache(principals); } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java index 1fe9ff2..88cf448 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java @@ -1,84 +1,53 @@ -// 定义包路径,用于存放Shiro JWT认证过滤器相关的类 package com.yf.exam.ability.shiro.aop; -// 导入所需的外部依赖包 -import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 -import com.yf.exam.aspect.utils.InjectUtils; // 工具类,用于注入错误信息 -import com.yf.exam.modules.Constant; // 常量类 -import lombok.extern.slf4j.Slf4j; // 日志注解 -import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; // Shiro基础认证过滤器 -import javax.servlet.ServletRequest; // Servlet请求接口 -import javax.servlet.ServletResponse; // Servlet响应接口 -import javax.servlet.http.HttpServletRequest; // HTTP请求类 -import javax.servlet.http.HttpServletResponse; // HTTP响应类 +import com.yf.exam.ability.shiro.jwt.JwtToken; +import com.yf.exam.aspect.utils.InjectUtils; +import com.yf.exam.modules.Constant; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** - * JWT认证过滤器 - * 用于处理基于JWT的身份认证,确保只有持有有效JWT令牌的请求才能访问受保护的资源。 + * 鉴权登录拦截器 * @author bool */ -@Slf4j // 启用Slf4j日志 +@Slf4j public class JwtFilter extends BasicHttpAuthenticationFilter { - /** - * 判断是否允许访问 - * 所有的请求都会经过这个方法,用于判断是否需要登录认证。 - * 如果请求不需要认证(如访问公开资源),则直接返回true允许访问; - * 如果需要认证,则尝试执行登录认证,根据认证结果决定是否允许访问。 - * - * @param request 请求对象 - * @param response 响应对象 - * @param mappedValue 映射值 - * @return 是否允许访问 - */ - @Override - protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { - try { - // 尝试执行登录认证 - executeLogin(request, response); - // 认证成功返回true - return true; - } catch (Exception e) { - // 认证失败时写入错误信息 - InjectUtils.restError((HttpServletResponse) response); - // 返回false表示不允许访问 - return false; - } - } + /** + * 执行登录认证 + * @param request + * @param response + * @param mappedValue + * @return + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + try { + executeLogin(request, response); + return true; + } catch (Exception e) { + // 写出统一错误信息 + InjectUtils.restError((HttpServletResponse) response); + return false; + } + } - /** - * 执行登录认证 - * 从请求头中获取JWT token并进行认证,如果认证成功,则请求可以继续执行; - * 如果认证失败(如token无效或过期),则抛出异常,由isAccessAllowed方法处理。 - * - * @param request 请求对象 - * @param response 响应对象 - * @return 是否认证成功 - */ - @Override - protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { - // 将ServletRequest转换为HttpServletRequest - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - // 从请求头中获取token - String token = httpServletRequest.getHeader(Constant.TOKEN); - // 如果token为空,则抛出异常 - if (token == null || "".equals(token)) { - throw new Exception("token不能为空"); - } + @Override + protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + String token = httpServletRequest.getHeader(Constant.TOKEN); - // 创建JWT token对象 - JwtToken jwtToken = new JwtToken(token); - // 提交给realm进行登录认证 - try { - getSubject(request, response).login(jwtToken); - // 如果没有抛出异常则表示登录成功 - return true; - } catch (Exception e) { - // 登录失败,记录日志 - log.error("JWT认证失败", e); - throw e; - } - } -} \ No newline at end of file + JwtToken jwtToken = new JwtToken(token); + // 提交给realm进行登入,如果错误他会抛出异常并被捕获 + getSubject(request, response).login(jwtToken); + // 如果没有抛出异常则代表登入成功,返回true + return true; + } +} diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java index 1e1fe4c..d5baab3 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java @@ -1,50 +1,33 @@ -// 定义包路径,用于存放JWT令牌相关的类 package com.yf.exam.ability.shiro.jwt; - -import lombok.Data; // Lombok注解,用于生成getter和setter -import org.apache.shiro.authc.AuthenticationToken; // Shiro认证令牌接口 + +import lombok.Data; +import org.apache.shiro.authc.AuthenticationToken; /** - * JWT令牌实现类 - * 实现Shiro的AuthenticationToken接口,用于JWT认证 * @author bool */ -@Data // 自动生成getter和setter方法 +@Data public class JwtToken implements AuthenticationToken { - private static final long serialVersionUID = 1L; // 序列化ID + private static final long serialVersionUID = 1L; /** - * JWT的字符串token - * 用于存储实际的JWT令牌字符串 + * JWT的字符token */ - private String token; // JWT令牌字符串 + private String token; + - /** - * 构造函数 - * @param token JWT令牌字符串 - */ public JwtToken(String token) { - this.token = token; // 设置token + this.token = token; } - /** - * 获取身份信息 - * 实现AuthenticationToken接口的方法 - * @return 返回token作为身份信息 - */ @Override public Object getPrincipal() { - return token; // 返回token作为身份信息 + return token; } - /** - * 获取凭证信息 - * 实现AuthenticationToken接口的方法 - * @return 返回token作为凭证信息 - */ @Override public Object getCredentials() { - return token; // 返回token作为凭证信息 + return token; } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java index ec2d907..4a66759 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java @@ -1,15 +1,14 @@ -// 定义包路径,用于存放JWT工具类 package com.yf.exam.ability.shiro.jwt; -import com.auth0.jwt.JWT; // JWT工具类 -import com.auth0.jwt.JWTVerifier; // JWT验证器 -import com.auth0.jwt.algorithms.Algorithm; // JWT算法 -import com.auth0.jwt.exceptions.JWTDecodeException; // JWT解码异常 -import com.auth0.jwt.interfaces.DecodedJWT; // 解码后的JWT -import com.yf.exam.core.utils.file.Md5Util; // MD5工具类 +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.auth0.jwt.exceptions.JWTDecodeException; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.yf.exam.core.utils.file.Md5Util; -import java.util.Calendar; // 日历类 -import java.util.Date; // 日期类 +import java.util.Calendar; +import java.util.Date; /** * JWT工具类 @@ -20,74 +19,81 @@ public class JwtUtils { /** * 有效期24小时 */ - private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; // JWT有效期 + private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; + /** * 校验是否正确 - * @param token JWT令牌 - * @param username 用户名 - * @return 是否有效 + * @param token + * @param username + * @return */ public static boolean verify(String token, String username) { try { // 根据密码生成JWT效验器 - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 - JWTVerifier verifier = JWT.require(algorithm) // 创建验证器 - .withClaim("username", username) // 添加用户名声明 - .build(); // 构建验证器 + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); + JWTVerifier verifier = JWT.require(algorithm) + .withClaim("username", username) + .build(); // 效验TOKEN - verifier.verify(token); // 验证token - return true; // 返回验证成功 + verifier.verify(token); + return true; } catch (Exception exception) { - return false; // 返回验证失败 + return false; } } + + + + /** * 从Token中解密获得用户名 - * @param token JWT令牌 - * @return 用户名 + * @param token + * @return */ public static String getUsername(String token) { try { - DecodedJWT jwt = JWT.decode(token); // 解码JWT - return jwt.getClaim("username").asString(); // 获取用户名 + DecodedJWT jwt = JWT.decode(token); + return jwt.getClaim("username").asString(); } catch (JWTDecodeException e) { - return null; // 返回null表示解码失败 + return null; } } /** * 生成JWT Token字符串 - * @param username 用户名 - * @return JWT令牌字符串 + * @param username + * @return */ public static String sign(String username) { - Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); // 设置过期时间 - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 附带username信息 - return JWT.create() // 创建JWT - .withClaim("username", username) // 添加用户名声明 - .withExpiresAt(date).sign(algorithm); // 设置过期时间并签名 + return JWT.create() + .withClaim("username", username) + .withExpiresAt(date).sign(algorithm); + } /** * 根据用户名和秘钥,生成一个新的秘钥,用于JWT加强一些安全性 - * @param userName 用户名 - * @return 加密后的秘钥 + * @param userName + * @return */ private static String encryptSecret(String userName){ + // 一个简单的登录规则,用户名+当前月份为加密串,意思每个月会变,要重新登录 // 可自行修改此规则 - Calendar cl = Calendar.getInstance(); // 获取当前日历 - cl.setTimeInMillis(System.currentTimeMillis()); // 设置当前时间 - StringBuffer sb = new StringBuffer(userName) // 创建字符串缓冲区 - .append("&") // 添加分隔符 - .append(cl.get(Calendar.MONTH)); // 添加当前月份 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + StringBuffer sb = new StringBuffer(userName) + .append("&") + .append(cl.get(Calendar.MONTH)); // 获取MD5 - String secret = Md5Util.md5(sb.toString()); // 生成MD5秘钥 + String secret = Md5Util.md5(sb.toString()); - return Md5Util.md5(userName + "&" + secret); // 返回加密后的秘钥 + return Md5Util.md5(userName + "&" + secret); } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java index a0cb14b..e35d73d 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java @@ -1,36 +1,32 @@ -// 定义包路径,用于存放文件上传配置相关的类 package com.yf.exam.ability.upload.config; -import lombok.Data; // Lombok注解,用于简化数据类的编写,自动生成getter和setter -import org.springframework.boot.context.properties.ConfigurationProperties; // Spring Boot配置属性注解,用于将配置文件中的属性绑定到Java对象 -import org.springframework.context.annotation.Configuration; // Spring配置注解,标记为配置类 +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + /** - * 文件上传配置类 - * 用于定义文件上传的相关配置,如访问路径、物理目录和允许的文件后缀等。 - * 这些配置通常在application.yml或application.properties中定义,并由Spring Boot自动加载。 + * 文件上传配置 * @author van */ -@Data // 使用Lombok注解,自动生成getter和setter方法 -@Configuration // 标记为Spring配置类,表示这是一个配置类 -@ConfigurationProperties(prefix = "conf.upload") // 指定配置文件中属性的前缀,这里是"conf.upload" +@Data +@Configuration +@ConfigurationProperties(prefix = "conf.upload") public class UploadConfig { /** - * 文件访问路径 - * 定义文件上传后对外访问的基础URL路径。 + * 访问路径 */ - private String url; // 文件访问的URL + private String url; /** - * 文件存储物理目录 - * 定义文件上传后在服务器上的存储路径。 + * 物理目录 */ - private String dir; // 文件存储的物理目录 + private String dir; /** - * 允许的文件后缀 - * 定义允许上传的文件类型,通过文件后缀来限制。 + * 允许的后缀 */ - private String[] allowExtensions; // 允许上传的文件后缀 -} \ No newline at end of file + private String [] allowExtensions; + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java index 1849a4b..4c85250 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java @@ -1,62 +1,57 @@ -// 定义包路径,用于存放文件上传下载请求类 package com.yf.exam.ability.upload.controller; -import com.yf.exam.ability.Constant; // 常量类,包含系统配置的常量值 -import com.yf.exam.ability.upload.dto.UploadReqDTO; // 文件上传请求DTO,封装上传文件所需的数据 -import com.yf.exam.ability.upload.dto.UploadRespDTO; // 文件上传响应DTO,封装上传文件后的响应数据 -import com.yf.exam.ability.upload.service.UploadService; // 文件上传服务,提供文件上传和下载的业务逻辑 -import com.yf.exam.core.api.ApiRest; // API响应类,封装统一的API响应格式 -import com.yf.exam.core.api.controller.BaseController; // 基础控制器,提供基础的控制器功能 -import io.swagger.annotations.Api; // Swagger API注解,用于描述API信息 -import io.swagger.annotations.ApiOperation; // Swagger API操作注解,用于描述单个API操作 -import lombok.extern.log4j.Log4j2; // 日志注解,提供日志功能 -import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解,用于注入Spring管理的Bean -import org.springframework.web.bind.annotation.GetMapping; // GET请求映射注解,用于映射GET请求到方法 -import org.springframework.web.bind.annotation.ModelAttribute; // 模型属性注解,用于将请求参数绑定到模型对象 -import org.springframework.web.bind.annotation.PostMapping; // POST请求映射注解,用于映射POST请求到方法 -import org.springframework.web.bind.annotation.RestController; // REST控制器注解,标记为REST风格的控制器 -import javax.servlet.http.HttpServletRequest; // HTTP请求类,表示HTTP请求 -import javax.servlet.http.HttpServletResponse; // HTTP响应类,表示HTTP响应 +import com.yf.exam.ability.Constant; +import com.yf.exam.ability.upload.dto.UploadReqDTO; +import com.yf.exam.ability.upload.dto.UploadRespDTO; +import com.yf.exam.ability.upload.service.UploadService; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.log4j.Log4j2; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** * 本地文件上传下载请求类 - * 负责处理文件上传和下载的请求,提供RESTful API接口。 * @author bool */ -@Log4j2 // 启用Log4j2日志 -@Api(tags = {"文件上传"}) // Swagger API标签,用于分类API -@RestController // 标记为REST控制器,表示该类是一个REST风格的控制器 +@Log4j2 +@Api(tags = {"文件上传"}) +@RestController public class UploadController extends BaseController { @Autowired - private UploadService uploadService; // 文件上传服务,自动注入 + private UploadService uploadService; /** * 文件上传 - * 处理文件上传请求,接收上传文件的数据,并返回上传结果。 - * - * @param reqDTO 上传请求DTO,包含上传文件所需的数据 - * @return 上传响应,封装上传文件后的响应数据 + * @param reqDTO + * @return */ - @PostMapping("/common/api/file/upload") // POST请求映射,指定请求路径 - @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") // Swagger API操作描述 + @PostMapping("/common/api/file/upload") + @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") public ApiRest upload(@ModelAttribute UploadReqDTO reqDTO) { // 上传并返回URL - UploadRespDTO respDTO = uploadService.upload(reqDTO); // 调用上传服务 - return super.success(respDTO); // 返回成功响应 + UploadRespDTO respDTO = uploadService.upload(reqDTO); + return super.success(respDTO); } /** * 独立文件下载 - * 处理文件下载请求,根据请求参数返回对应的文件。 - * - * @param request HTTP请求,包含下载请求的信息 - * @param response HTTP响应,用于返回文件内容 + * @param request + * @param response */ - @GetMapping(Constant.FILE_PREFIX+"**") // GET请求映射,指定请求路径前缀 - @ApiOperation(value = "文件下载", notes = "文件下载") // Swagger API操作描述 + @GetMapping(Constant.FILE_PREFIX+"**") + @ApiOperation(value = "文件下载", notes = "文件下载") public void download(HttpServletRequest request, HttpServletResponse response) { - uploadService.download(request, response); // 调用下载服务 + uploadService.download(request, response); } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java index 0e4a0f1..df2f286 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java @@ -1,26 +1,22 @@ -// 定义包路径,用于存放文件上传请求DTO package com.yf.exam.ability.upload.dto; -import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 -import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写,自动生成getter和setter -import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 + +import com.yf.exam.core.api.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.web.multipart.MultipartFile; /** * 文件上传请求类 - * 用于封装文件上传请求中的数据,包括上传的文件内容。 - * @author van + * @author * @date 2019-12-26 17:54 */ -@Data // 使用Lombok注解,自动生成getter和setter方法 -@ApiModel(value="文件上传参数", description="文件上传参数") // 使用Swagger注解,描述API模型 +@Data +@ApiModel(value="文件上传参数", description="文件上传参数") public class UploadReqDTO extends BaseDTO { - /** - * 上传文件内容 - * 用于存储上传文件的数据,包括文件名、文件类型、文件大小等信息。 - */ - @ApiModelProperty(value = "上传文件内容", required=true) // 使用Swagger注解,描述API模型属性 - private MultipartFile file; // 上传的文件内容 -} \ No newline at end of file + @ApiModelProperty(value = "上传文件内容", required=true) + private MultipartFile file; + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java index cbce697..b91106e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java @@ -1,28 +1,23 @@ -// 定义包路径,用于存放文件上传响应DTO package com.yf.exam.ability.upload.dto; -import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 -import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 -import lombok.AllArgsConstructor; // 导入Lombok注解,用于生成全参构造函数 -import lombok.Data; // 导入Lombok注解,用于生成getter和setter方法 -import lombok.NoArgsConstructor; // 导入Lombok注解,用于生成无参构造函数 +import com.yf.exam.core.api.dto.BaseDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; /** - * 文件上传响应DTO - * 用于封装文件上传操作的结果,包括上传后的文件URL等信息。 + * 上传文件结果 * @author bool */ -@Data // 使用Lombok注解,自动生成getter和setter方法 -@AllArgsConstructor // 使用Lombok注解,生成全参构造函数 -@NoArgsConstructor // 使用Lombok注解,生成无参构造函数 -@ApiModel(value="文件上传响应", description="文件上传响应") // 使用Swagger注解,描述API模型 +@Data +@AllArgsConstructor +@NoArgsConstructor +@ApiModel(value="文件上传响应", description="文件上传响应") public class UploadRespDTO extends BaseDTO { - /** - * 上传后的完整URL地址 - * 存储文件上传成功后,文件的完整访问URL地址。 - */ - @ApiModelProperty(value = "上传后的完整的URL地址", required=true) // 使用Swagger注解,描述API模型属性 - private String url; // 上传后的完整URL地址 -} \ No newline at end of file + @ApiModelProperty(value = "上传后的完整的URL地址", required=true) + private String url; + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java index 44617b6..ef516ec 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java @@ -1,62 +1,30 @@ package com.yf.exam.ability.upload.service; -// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.service。 -// 包用于组织和管理相关的Java类,避免类名冲突,方便代码的模块化和复用。 -import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO -// 导入了名为UploadReqDTO的类,它位于com.yf.exam.ability.upload.dto包下。 -// 这个类通常用于封装文件上传请求相关的数据,比如要上传的文件信息、上传的相关参数等。 +import com.yf.exam.ability.upload.dto.UploadReqDTO; +import com.yf.exam.ability.upload.dto.UploadRespDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO -// 导入了名为UploadRespDTO的类,同样位于com.yf.exam.ability.upload.dto包下。 -// 它主要用于封装文件上传操作完成后返回的响应数据,例如上传是否成功的标识、上传后的文件存储路径等信息。 - -import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类 -// 引入了Java EE中用于处理HTTP请求的标准类HttpServletRequest。 -// 在文件下载等操作中,会通过这个类获取客户端发送过来的关于下载请求的各种信息,如请求的URL、请求头信息等。 - -import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类 -// 引入了Java EE中用于处理HTTP响应的标准类HttpServletResponse。 -// 在文件下载操作中,会使用这个类来设置响应的状态码、响应头信息以及将文件内容返回给客户端。 +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; /** - * 文件上传服务接口 - * 定义文件上传和下载的相关业务操作,提供统一的接口供外部调用。 - * @author bool + * 阿里云OSS业务类 + * @author bool * @date 2019-07-12 16:45 */ -// 这是一个Java接口的文档注释,用于描述该接口的整体功能和用途。 -// 说明这个接口主要是用来定义与文件上传和下载相关的业务操作方法, -// 并且其他类可以通过实现这个接口来提供具体的实现,以达到统一调用的目的。 -// 同时标注了接口的作者是bool,创建日期是2019年7月12日16:45。 - public interface UploadService { - // 这里定义了一个名为UploadService的公共接口。 - // 接口中只包含方法的声明,不包含方法的具体实现,具体实现由实现该接口的类来完成。 /** * 文件上传 - * 方法用于处理文件上传请求,接收上传文件的数据,并返回上传结果。 - * - * @param reqDTO 上传请求DTO,包含上传文件所需的数据 - * @return 上传响应DTO,封装上传文件后的响应数据 + * @param reqDTO + * @return */ - // 这是接口中定义的一个方法声明,名为upload。 - // 它的功能是处理文件上传请求,通过接收传入的UploadReqDTO对象(其中包含了上传文件所需的各种数据), - // 然后在具体实现类中执行实际的上传操作,最后返回一个UploadRespDTO对象,该对象封装了上传文件后的响应数据。 - UploadRespDTO upload(UploadReqDTO reqDTO); /** - * 文件下载 - * 方法用于处理文件下载请求,根据请求参数返回对应的文件。 - * - * @param request HTTP请求,包含下载请求的信息 - * @param response HTTP响应,用于返回文件内容 + * 下载文件 + * @param request + * @param response */ - // 这是接口中定义的另一个方法声明,名为download。 - // 它用于处理文件下载请求,会接收一个HttpServletRequest对象(其中包含了客户端发送的关于下载请求的所有信息) - // 和一个HttpServletResponse对象(用于设置响应相关的信息并将文件内容返回给客户端), - // 在具体实现类中根据请求参数找到对应的要下载的文件,并通过HttpServletResponse将文件内容返回给客户端。 - void download(HttpServletRequest request, HttpServletResponse response); -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java index 6d1a60e..ef70f40 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java @@ -1,143 +1,135 @@ -// 定义包路径,用于存放文件上传服务实现类 package com.yf.exam.ability.upload.service.impl; -import com.yf.exam.ability.Constant; // 导入常量类,包含系统配置的常量值 -import com.yf.exam.ability.upload.config.UploadConfig; // 导入文件上传配置类,包含文件上传的相关配置 -import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO,封装上传文件所需的数据 -import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO,封装上传文件后的响应数据 -import com.yf.exam.ability.upload.service.UploadService; // 导入文件上传服务接口,定义文件上传的相关业务操作 -import com.yf.exam.ability.upload.utils.FileUtils; // 导入文件工具类,提供文件操作的辅助功能 -import com.yf.exam.core.exception.ServiceException; // 导入服务异常类,处理业务逻辑中的异常情况 -import lombok.extern.log4j.Log4j2; // 导入日志注解,提供日志功能 -import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,提供文件名和扩展名操作的辅助功能 -import org.springframework.beans.factory.annotation.Autowired; // 导入Spring自动注入注解,用于注入Spring管理的Bean -import org.springframework.stereotype.Service; // 导入Spring服务注解,标记为服务组件 -import org.springframework.util.FileCopyUtils; // 导入文件复制工具类,提供文件复制的功能 -import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,处理上传的文件 - -import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示HTTP请求 -import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示HTTP响应 -import java.io.FileOutputStream; // 导入文件输出流,用于将文件内容写入文件 -import java.io.IOException; // 导入IO异常类,处理IO操作中的异常情况 -import java.io.UnsupportedEncodingException; // 导入不支持的编码异常类,处理编码问题 -import java.net.URLDecoder; // 导入URL解码类,用于解码URL -import java.util.regex.Matcher; // 导入正则表达式匹配器,用于匹配正则表达式 -import java.util.regex.Pattern; // 导入正则表达式类,用于编译正则表达式 +import com.yf.exam.ability.Constant; +import com.yf.exam.ability.upload.config.UploadConfig; +import com.yf.exam.ability.upload.dto.UploadReqDTO; +import com.yf.exam.ability.upload.dto.UploadRespDTO; +import com.yf.exam.ability.upload.service.UploadService; +import com.yf.exam.ability.upload.utils.FileUtils; +import com.yf.exam.core.exception.ServiceException; +import lombok.extern.log4j.Log4j2; +import org.apache.commons.io.FilenameUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * 文件上传业务类 - * 实现文件上传服务接口,提供文件上传和下载的业务逻辑。 * @author bool * @date 2019-07-30 21:02 */ -@Log4j2 // 使用Log4j2日志注解,启用日志功能 -@Service // 使用Spring服务注解,标记为服务组件 +@Log4j2 +@Service public class UploadServiceImpl implements UploadService { @Autowired - private UploadConfig conf; // 自动注入文件上传配置 + private UploadConfig conf; - /** - * 文件上传 - * 实现文件上传业务逻辑,包括文件验证、文件保存和返回上传结果。 - * - * @param reqDTO 上传请求DTO,包含上传文件所需的数据 - * @return 上传响应DTO,封装上传文件后的响应数据 - */ @Override public UploadRespDTO upload(UploadReqDTO reqDTO) { + + // 文件内容 - MultipartFile file = reqDTO.getFile(); // 获取上传的文件 + MultipartFile file = reqDTO.getFile(); // 验证文件后缀 - boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); // 验证文件后缀 + boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); if(!allow){ - throw new ServiceException("文件类型不允许上传!"); // 抛出异常 + throw new ServiceException("文件类型不允许上传!"); } // 上传文件夹 - String fileDir = conf.getDir(); // 获取文件存储目录 + String fileDir = conf.getDir(); // 真实物理地址 String fullPath; try { + // 新文件 - String filePath = FileUtils.processPath(file); // 处理文件路径 + String filePath = FileUtils.processPath(file); // 文件保存地址 - fullPath = fileDir + filePath; // 拼接完整路径 + fullPath = fileDir + filePath; // 创建文件夹 - FileUtils.checkDir(fullPath); // 检查并创建文件夹 + FileUtils.checkDir(fullPath); // 上传文件 - FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); // 复制文件内容到指定路径 + FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); - return this.generateResult(filePath); // 返回上传结果 + return this.generateResult(filePath); } catch (IOException e) { - e.printStackTrace(); // 打印异常堆栈 - throw new ServiceException("文件上传失败:"+e.getMessage()); // 抛出异常 + e.printStackTrace(); + throw new ServiceException("文件上传失败:"+e.getMessage()); } } - /** - * 独立文件下载 - * 实现文件下载业务逻辑,包括获取文件真实路径和返回文件内容。 - * - * @param request HTTP请求,包含下载请求的信息 - * @param response HTTP响应,用于返回文件内容 - */ + + @Override public void download(HttpServletRequest request, HttpServletResponse response) { + // 获取真实的文件路径 - String filePath = this.getRealPath(request.getRequestURI()); // 获取文件的真实路径 + String filePath = this.getRealPath(request.getRequestURI()); // 处理中文问题 try { - filePath = URLDecoder.decode(filePath, "utf-8"); // 解码文件路径 + filePath = URLDecoder.decode(filePath, "utf-8"); } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); // 抛出运行时异常 + throw new RuntimeException(e); } - System.out.println("++++完整路径为:"+filePath); // 打印完整路径 + System.out.println("++++完整路径为:"+filePath); try { - FileUtils.writeRange(request, response, filePath); // 调用文件工具类进行文件写入 + FileUtils.writeRange(request, response, filePath); } catch (IOException e) { - response.setStatus(404); // 设置响应状态为404 - log.error("预览文件失败" + e.getMessage()); // 打印错误日志 + response.setStatus(404); + log.error("预览文件失败" + e.getMessage()); } } + /** * 构造返回 - * 根据文件名构造上传响应DTO,包含上传后的完整URL地址。 - * - * @param fileName 文件名 - * @return 上传响应DTO + * @param fileName + * @return */ private UploadRespDTO generateResult(String fileName) { + //获取加速域名 - String domain = conf.getUrl(); // 获取文件访问的URL + String domain = conf.getUrl(); // 返回结果 - return new UploadRespDTO(domain + fileName); // 返回上传响应DTO + return new UploadRespDTO(domain + fileName); } + /** * 获取真实物理文件地址 - * 根据请求URI获取文件的真实物理路径。 - * - * @param uri 请求URI - * @return 真实文件路径 + * @param uri + * @return */ public String getRealPath(String uri){ - String regx = Constant.FILE_PREFIX+"(.*)"; // 正则表达式匹配文件路径 + + String regx = Constant.FILE_PREFIX+"(.*)"; // 查找全部变量 - Pattern pattern = Pattern.compile(regx); // 编译正则表达式 - Matcher m = pattern.matcher(uri); // 创建匹配器 + Pattern pattern = Pattern.compile(regx); + Matcher m = pattern.matcher(uri); if (m.find()) { - String str = m.group(1); // 获取匹配的文件路径 - return conf.getDir() + str; // 返回真实文件路径 + String str = m.group(1); + return conf.getDir() + str; } - return null; // 返回null表示未找到 + return null; } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java index 0c45c41..539ecb0 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java @@ -1,169 +1,172 @@ -// 定义包路径,用于存放文件工具类 package com.yf.exam.ability.upload.utils; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入ID生成工具,用于生成唯一的文件名 -import com.yf.exam.core.utils.DateUtils; // 导入日期工具类,用于处理日期相关的操作 -import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,用于处理文件名和扩展名 -import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.yf.exam.core.utils.DateUtils; +import org.apache.commons.io.FilenameUtils; +import org.springframework.web.multipart.MultipartFile; -import javax.servlet.ServletOutputStream; // 导入Servlet输出流,用于写入HTTP响应 -import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示客户端的请求 -import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示服务器的响应 -import java.io.File; // 导入文件类,用于操作文件和目录 -import java.io.IOException; // 导入IO异常类,处理IO操作中的异常 -import java.io.RandomAccessFile; // 导入随机访问文件类,用于高效地读写文件 -import java.util.Date; // 导入日期类,用于处理日期和时间 +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Date; /** * 文件工具类 - * 提供文件操作的辅助功能,包括文件上传、下载、重命名和目录管理等。 * @author bool */ public class FileUtils { - /** - * 后缀分割符号 - * 用于分割文件名和扩展名。 - */ - private static final String SUFFIX_SPLIT = "."; // 文件后缀分隔符 - - /** - * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 - * 方法用于处理HTTP请求,以断点续传的方式输出文件内容,支持文件在线预览和视频在线播放。 - * - * @param request HTTP请求,包含客户端的请求信息 - * @param response HTTP响应,包含服务器的响应信息 - * @param filePath 文件路径,指定要输出的文件 - * @throws IOException IO异常,处理文件操作中的异常 - */ - public static void writeRange(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException { - // 读取文件 - File file = new File(filePath); // 创建文件对象 - - // 只读模式 - RandomAccessFile randomFile = new RandomAccessFile(file, "r"); // 创建随机访问文件对象 - long contentLength = randomFile.length(); // 获取文件长度 - String range = request.getHeader("Range"); // 获取请求头中的Range - int start = 0, end = 0; // 初始化起始和结束位置 - if (range != null && range.startsWith("bytes=")) { - String[] values = range.split("=")[1].split("-"); // 解析Range - start = Integer.parseInt(values[0]); // 获取起始位置 - if (values.length > 1) { - end = Integer.parseInt(values[1]); // 获取结束位置 - } - } - int requestSize; // 请求大小 - if (end != 0 && end > start) { - requestSize = end - start + 1; // 计算请求大小 - } else { - requestSize = Integer.MAX_VALUE; // 设置为最大值 - } - - byte[] buffer = new byte[128]; // 创建缓冲区 - response.setContentType(MediaUtils.getContentType(filePath)); // 设置响应内容类型 - response.setHeader("Accept-Ranges", "bytes"); // 设置支持的范围 - response.setHeader("ETag", file.getName()); // 设置文件名 - response.setHeader("Last-Modified", new Date().toString()); // 设置最后修改时间 - // 第一次请求只返回content length来让客户端请求多次实际数据 - if (range == null) { - response.setHeader("Content-length", contentLength + ""); // 设置内容长度 - } else { - // 以后的多次以断点续传的方式来返回视频数据 - response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 设置部分内容状态 - long requestStart = 0, requestEnd = 0; // 初始化请求起始和结束位置 - String[] ranges = range.split("="); // 解析Range - if (ranges.length > 1) { - String[] rangeData = ranges[1].split("-"); // 获取范围数据 - requestStart = Integer.parseInt(rangeData[0]); // 获取请求起始位置 - if (rangeData.length > 1) { - requestEnd = Integer.parseInt(rangeData[1]); // 获取请求结束位置 - } - } - long length; // 请求长度 - if (requestEnd > 0) { - length = requestEnd - requestStart + 1; // 计算请求长度 - response.setHeader("Content-length", "" + length); // 设置内容长度 - response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); // 设置内容范围 - } else { - length = contentLength - requestStart; // 计算请求长度 - response.setHeader("Content-length", "" + length); // 设置内容长度 - response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); // 设置内容范围 - } - } - ServletOutputStream out = response.getOutputStream(); // 获取输出流 - int needSize = requestSize; // 需要的大小 - randomFile.seek(start); // 移动到起始位置 - while (needSize > 0) { - int len = randomFile.read(buffer); // 读取文件内容 - if (needSize < buffer.length) { - out.write(buffer, 0, needSize); // 写入需要的大小 - } else { - out.write(buffer, 0, len); // 写入缓冲区内容 - if (len < buffer.length) { - break; // 如果读取的长度小于缓冲区长度,退出循环 - } - } - needSize -= buffer.length; // 减少需要的大小 - } - randomFile.close(); // 关闭随机访问文件 - out.close(); // 关闭输出流 - } - - /** - * 重命名文件 - * 方法用于生成新的文件名,避免文件名冲突。 - * - * @param fileName 文件名 - * @return 新文件名 - */ - public static String renameFile(String fileName) { - // 没有后缀名不处理 - if (!fileName.contains(SUFFIX_SPLIT)) { - return fileName; // 返回原文件名 - } - - // 文件后缀 - String extension = FilenameUtils.getExtension(fileName); // 获取文件后缀 - - // 以系统时间命名 - return IdWorker.getIdStr() + "." + extension; // 返回新文件名 - } - - /** - * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 - * 方法用于处理上传文件的路径,根据当前日期生成目录结构。 - * - * @param file 文件 - * @return 处理后的文件路径 - */ - public static String processPath(MultipartFile file) { - // 创建OSSClient实例。 - String fileName = file.getOriginalFilename(); // 获取原始文件名 - - // 需要重命名 - fileName = renameFile(fileName); // 重命名文件 - - // 获得上传的文件夹 - String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); // 获取当前日期格式化后的目录 - - return new StringBuffer(dir).append(fileName).toString(); // 返回处理后的文件路径 - } - - /** - * 检查文件夹是否存在,不存在则创建 - * 方法用于检查指定的文件夹是否存在,如果不存在则创建。 - * - * @param fileName 文件名 - */ - public static void checkDir(String fileName) { - int index = fileName.lastIndexOf("/"); // 获取最后一个斜杠的位置 - if (index == -1) { - return; // 如果没有斜杠,返回 - } - - File file = new File(fileName.substring(0, index)); // 创建文件对象 - if (!file.exists()) { - file.mkdirs(); // 如果文件夹不存在,创建文件夹 - } - } -} \ No newline at end of file + /** + * 后缀分割符号 + */ + private static final String SUFFIX_SPLIT = "."; + + + /** + * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 + * @param request + * @param response + * @param filePath + * @throws IOException + */ + public static void writeRange(HttpServletRequest request, + HttpServletResponse response, String filePath) throws IOException { + + // 读取文件 + File file = new File(filePath); + + //只读模式 + RandomAccessFile randomFile = new RandomAccessFile(file, "r"); + long contentLength = randomFile.length(); + String range = request.getHeader("Range"); + int start = 0, end = 0; + if (range != null && range.startsWith("bytes=")) { + String[] values = range.split("=")[1].split("-"); + start = Integer.parseInt(values[0]); + if (values.length > 1) { + end = Integer.parseInt(values[1]); + } + } + int requestSize; + if (end != 0 && end > start) { + requestSize = end - start + 1; + } else { + requestSize = Integer.MAX_VALUE; + } + + byte[] buffer = new byte[128]; + response.setContentType(MediaUtils.getContentType(filePath)); + response.setHeader("Accept-Ranges", "bytes"); + response.setHeader("ETag", file.getName()); + response.setHeader("Last-Modified", new Date().toString()); + //第一次请求只返回content length来让客户端请求多次实际数据 + if (range == null) { + response.setHeader("Content-length", contentLength + ""); + } else { + //以后的多次以断点续传的方式来返回视频数据 + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + long requestStart = 0, requestEnd = 0; + String[] ranges = range.split("="); + if (ranges.length > 1) { + String[] rangeData = ranges[1].split("-"); + requestStart = Integer.parseInt(rangeData[0]); + if (rangeData.length > 1) { + requestEnd = Integer.parseInt(rangeData[1]); + } + } + long length; + if (requestEnd > 0) { + length = requestEnd - requestStart + 1; + response.setHeader("Content-length", "" + length); + response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); + } else { + length = contentLength - requestStart; + response.setHeader("Content-length", "" + length); + response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); + } + } + ServletOutputStream out = response.getOutputStream(); + int needSize = requestSize; + randomFile.seek(start); + while (needSize > 0) { + int len = randomFile.read(buffer); + if (needSize < buffer.length) { + out.write(buffer, 0, needSize); + } else { + out.write(buffer, 0, len); + if (len < buffer.length) { + break; + } + } + needSize -= buffer.length; + } + randomFile.close(); + out.close(); + } + + + + + /** + * 重命名文件 + * @param fileName + * @return + */ + public static String renameFile(String fileName) { + + //没有后缀名不处理 + if (!fileName.contains(SUFFIX_SPLIT)) { + return fileName; + } + + //文件后缀 + String extension = FilenameUtils.getExtension(fileName); + + //以系统时间命名 + return IdWorker.getIdStr() + "."+ extension; + + } + + + /** + * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 + * @param file 文件 + * @return + */ + public static String processPath(MultipartFile file){ + + // 创建OSSClient实例。 + String fileName = file.getOriginalFilename(); + + // 需要重命名 + fileName = renameFile(fileName); + + //获得上传的文件夹 + String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); + + return new StringBuffer(dir).append(fileName).toString(); + + } + + /** + * 检查文件夹是否存在,不存在则创建 + * @param fileName + * @return + */ + public static void checkDir(String fileName){ + int index = fileName.lastIndexOf("/"); + if(index == -1){ + return; + } + + File file = new File(fileName.substring(0,index)); + if(!file.exists()){ + file.mkdirs(); + } + } + + +} diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java index aff5557..b4394c0 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java @@ -1,75 +1,47 @@ package com.yf.exam.ability.upload.utils; -// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.utils。 -// 包用于对相关的Java类进行组织和管理,方便代码的分类、复用以及避免类名冲突。 -import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类,用于字符串操作 -// 引入了Apache Commons Lang库中的StringUtils类。 -// 这个类提供了许多方便的字符串操作方法,比如判断字符串是否为空、是否空白(包含空格等空白字符)、字符串的拼接、截取等操作,在这里主要用于对文件路径字符串进行相关判断。 +import org.apache.commons.lang3.StringUtils; -import java.util.HashMap; // 导入Java的HashMap类,用于创建映射 -// 导入了Java标准库中的HashMap类。 -// HashMap是实现了Map接口的一个具体类,它用于存储键值对形式的数据,通过键可以快速获取对应的值,在这里用于创建文件后缀名到MIME类型的映射关系。 - -import java.util.Map; // 导入Java的Map接口,用于键值对映射 -// 引入了Java标准库中的Map接口。 -// Map接口定义了键值对数据结构的通用操作规范,如添加键值对、根据键获取值、删除键值对等操作。 -// 虽然这里同时导入了HashMap类,但导入Map接口使得代码在使用映射数据结构时更具通用性,方便后续可能的替换为其他实现Map接口的类。 +import java.util.HashMap; +import java.util.Map; /** - * 媒体工具类,用于判断和获取媒体文件的MIME类型 - * 该类提供了一个静态映射,用于将文件后缀名映射到对应的MIME类型,以便在处理文件上传和下载时确定正确的媒体类型。 - * @author bool + * 媒体工具,判断媒体类型 + * @author bool * @date 2019-11-14 16:21 */ -// 这是一个Java类的文档注释,用于描述该类的整体功能和用途。 -// 说明这个类主要是作为媒体工具类,其核心功能是判断和获取媒体文件的MIME类型。 -// 通过维护一个静态的映射关系(文件后缀名到MIME类型的映射),在文件上传和下载的业务场景中,能够依据文件的后缀名准确地确定其对应的MIME类型,从而正确处理文件的传输和展示等操作。 -// 同时标注了类的作者是bool,创建日期是2019年11月14日16:21。 - public class MediaUtils { - /** - * 媒体类型映射 - * 静态映射,包含文件后缀名到MIME类型的映射。 - */ - // 这是对下面定义的MEDIA_MAP成员变量的文档注释,说明它是一个静态的映射,用于存储文件后缀名和对应的MIME类型之间的映射关系。 + public static final Map MEDIA_MAP = new HashMap(){ + { - public static final Map MEDIA_MAP = new HashMap() {{ - // 初始化映射 - // PDF文件的MIME类型 - put(".pdf", "application/pdf"); - // 视频文件的MIME类型 - put(".mp4", "video/mp4"); - }}; - // 这里定义了一个名为MEDIA_MAP的公共静态最终变量,它是一个HashMap类型的映射。 - // 通过匿名内部类的初始化方式,在创建HashMap实例的同时向其中添加了一些常见的文件后缀名到MIME类型的映射关系,比如将".pdf"后缀名映射到"application/pdf"这个MIME类型,将".mp4"后缀名映射到"video/mp4"这个MIME类型。 - // 由于被声明为静态最终变量,它在类加载时就会被初始化,并且其值不能再被修改,方便在整个类的其他地方直接使用这个映射关系来获取文件的MIME类型。 + //本来是pdf的 + put(".pdf", "application/pdf"); + + //视频 + put(".mp4", "video,video/mp4"); + + } + }; /** - * 根据文件路径获取文件的MIME类型 - * 方法根据文件的后缀名,从MEDIA_MAP中获取对应的MIME类型。 - * - * @param filePath 文件路径 - * @return 文件的MIME类型 + * 获得文件类型 + * @param filePath + * @return */ - // 这是对下面定义的getContentType方法的文档注释,说明该方法的功能是根据传入的文件路径,提取出文件的后缀名,然后从MEDIA_MAP这个静态映射中获取对应的MIME类型并返回。 + public static String getContentType(String filePath){ + + if(!StringUtils.isBlank(filePath) + && filePath.indexOf(".")!=-1) { - public static String getContentType(String filePath) { - if (!StringUtils.isBlank(filePath) && filePath.indexOf(".")!= -1) { - // 提取文件后缀名,并转换为小写 + // 后缀转换成小写 String suffix = filePath.substring(filePath.lastIndexOf(".")).toLowerCase(); - // 从映射中获取MIME类型 if (MEDIA_MAP.containsKey(suffix)) { return MEDIA_MAP.get(suffix); } } - // 如果没有找到对应的MIME类型,返回默认值 return "application/octet-stream"; } - // 这是定义的一个公共静态方法getContentType,它接受一个字符串类型的参数filePath,表示文件的路径。 - // 首先,通过StringUtils.isBlank方法判断文件路径是否不为空且包含小数点(即有文件后缀名)。 - // 如果满足条件,就使用substring方法从文件路径中提取出文件的后缀名,并通过toLowerCase方法将其转换为小写形式。 - // 然后,检查提取出的后缀名是否存在于MEDIA_MAP这个静态映射中,如果存在,就返回对应的MIME类型;如果不存在,就返回默认的MIME类型"application/octet-stream",这个默认值通常用于表示未知类型的二进制数据文件。 -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java index a85ec9a..441a154 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java +++ b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java @@ -1,189 +1,156 @@ package com.yf.exam.aspect; -// 导入FastJSON库,用于将Java对象转换为JSON字符串以及从JSON字符串解析为Java对象等操作, -// 在本类的多个方法中用于对象与JSON字符串之间的转换,以便于处理数据字典相关的值。 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; - -// 导入MyBatis Plus的接口,用于处理分页相关的数据结构,在本类中用于判断和处理分页数据中的数据字典值。 import com.baomidou.mybatisplus.core.metadata.IPage; - -// 导入Jackson库的注解,用于指定日期格式的序列化和反序列化方式, -// 在本类的parseObject方法中用于根据注解设置日期字段的格式化输出。 import com.fasterxml.jackson.annotation.JsonFormat; - -// 导入自定义的注解,可能用于标记与数据字典相关的字段,以便在本类中识别并处理这些字段的数据字典值。 import com.yf.exam.core.annon.Dict; - -// 导入自定义的API响应类,用于封装API调用的返回结果,包括数据、状态码等信息, -// 在本类的多个方法中用于获取和设置返回结果中的数据部分,以便处理其中的数据字典值。 import com.yf.exam.core.api.ApiRest; - -// 导入自定义的反射工具类,可能用于获取对象的所有字段等反射相关操作, -// 在本类的parseObject方法中用于获取对象的所有字段以便遍历处理数据字典值。 import com.yf.exam.core.utils.Reflections; - -// 导入系统数据字典服务类,用于查询数据字典表以获取数据字典值的翻译文本, -// 在本类的translateDictValue方法中用于根据字典代码、文本、表名和键值查询对应的字典文本。 import com.yf.exam.modules.sys.system.service.SysDictService; - -// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 -import lombok.extern.log4j.Log4j2; - -// 导入AspectJ的相关类,用于定义切面、切点和环绕通知等AOP相关的操作, -// 在本类中用于实现对特定方法的拦截和处理,以实现数据字典值的翻译等功能。 +import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; - -// 导入Spring框架的注解,用于自动注入依赖对象和标记类为Spring组件, -// 在本类中通过@Autowired注入SysDictService对象,并通过@Component标记本类为Spring组件,使其可被Spring容器管理。 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - -// 导入Spring框架的工具类,用于判断字符串是否为空等操作, -// 在本类的多个方法中用于判断字符串是否为空,以便进行相应的处理逻辑。 import org.springframework.util.StringUtils; -// 导入Java标准库中的反射相关类,用于通过反射操作对象的字段、获取类型信息等, -// 在本类的多个方法中广泛用于获取对象的字段、判断字段类型、获取字段注解等操作。 import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; - -// 导入Java标准库中的日期格式化类和日期类,用于处理日期格式的转换和操作, -// 在本类的parseObject方法中用于根据注解或默认格式对日期字段进行格式化输出。 import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** - * 数据字典AOP类,主要功能是处理数据字典值。通过拦截特定的方法调用, - * 对返回结果中的数据字典相关字段进行翻译、格式化等处理,以提供更友好的展示效果。 + * 数据字典AOP类,处理数据字典值 * * @author bool */ -@Aspect // 标记该类为一个AspectJ切面类,用于定义切面相关的逻辑。 -@Component // 标记该类为Spring组件,使其能够被Spring容器管理和实例化,以便在应用中使用。 -@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 +@Aspect +@Component +@Slf4j public class DictAspect { @Autowired - private SysDictService sysDictService; // 通过自动注入获取系统数据字典服务对象,用于查询数据字典值。 + private SysDictService sysDictService; /** - * 定义一个环绕通知,切入到指定的Controller方法执行前后。 - * 这里的切点表达式指定了拦截所有在com.yf.exam包及其子包下的所有Controller类中的所有公有方法。 - * - * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 - * @return 返回结果,经过处理后的方法执行结果,可能经过了数据字典值的处理等操作。 - * @throws Throwable 如果在环绕通知的执行过程中出现异常,则抛出。 + * 切入Controller执行 + * @param pjp + * @return + * @throws Throwable */ @Around("execution(public * com.yf.exam..*.*Controller.*(..))") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { - return this.translate(pjp); // 调用translate方法对被拦截方法的执行结果进行处理,主要是处理数据字典值。 + return this.translate(pjp); } /** - * 对被拦截方法的执行结果进行翻译处理,并返回处理后的结果。 - * 在调用此方法之前,通常需要确保相关的BaseDictService(可能是数据字典相关的基础服务)已经实现。 + * 进行翻译并返回,调用前必须实现:BaseDictService * - * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 - * @return 返回结果,经过数据字典值处理后的方法执行结果。 - * @throws Throwable 如果在处理过程中出现异常,则抛出。 + * @param pjp + * @return + * @throws Throwable */ public Object translate(ProceedingJoinPoint pjp) throws Throwable { - // 调用被拦截方法获取原始结果,然后调用parseAllDictText方法对结果进行数据字典值的处理。 + // 处理字典 return this.parseAllDictText(pjp.proceed()); } /** - * 根据结果对象的类型,判断是否需要对其进行数据字典值的处理。 - * 如果结果对象是ApiRest类型,则调用parseFullDictText方法进行完整的数据字典值处理。 + * 转换全部数据字典 * - * @param result 结果对象,即被拦截方法执行后的返回结果。 + * @param result */ private Object parseAllDictText(Object result) { - // 判断结果对象是否是ApiRest类型,如果是则进行数据字典值的处理。 + + // 非ApiRest类型不处理 if (result instanceof ApiRest) { parseFullDictText(result); } + return result; } + /** - * 对ApiRest类型的结果对象进行完整的数据字典值处理,包括处理分页数据、列表数据以及单对象数据等情况。 + * 转换所有类型的数据字典、包含子列表 * - * @param result 结果对象,即ApiRest类型的返回结果,其中包含了要处理的数据部分。 + * @param result */ private void parseFullDictText(Object result) { + try { - Object rest = ((ApiRest) result).getData(); // 获取ApiRest对象中的数据部分,这部分数据可能包含数据字典相关字段。 - // 如果数据部分为空或者是基本数据类型,则不需要进行数据字典值的处理,直接返回。 + Object rest = ((ApiRest) result).getData(); + + // 不处理普通数据类型 if (rest == null || this.isBaseType(rest.getClass())) { return; } - // 如果数据部分是分页数据类型(IPage),则对分页数据中的每条记录进行数据字典值处理。 + // 分页的 if (rest instanceof IPage) { List items = new ArrayList<>(16); for (Object record : ((IPage) rest).getRecords()) { - Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 + Object item = this.parseObject(record); items.add(item); } - ((IPage) rest).setRecords(items); // 将处理后的记录列表重新设置回分页对象中。 + ((IPage) rest).setRecords(items); return; } - // 如果数据部分是列表数据类型(List),则对列表中的每条记录进行数据字典值处理。 + // 数据列表的 if (rest instanceof List) { List items = new ArrayList<>(); for (Object record : ((List) rest)) { - Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 + Object item = this.parseObject(record); items.add(item); } - // 将处理后的记录列表重新设置回ApiRest对象的数据部分。 + // 重新回写值 ((ApiRest) result).setData(items); return; } - // 如果数据部分是单对象数据,则对该单对象进行数据字典值处理。 + // 处理单对象 Object item = this.parseObject(((ApiRest) result).getData()); ((ApiRest) result).setData(item); } catch (Exception e) { - e.printStackTrace(); // 如果在处理过程中出现异常,则打印异常堆栈信息。 + e.printStackTrace(); } } /** - * 对单个记录对象进行数据字典值处理,包括处理列表字段、带有数据字典注解的普通字段以及日期字段等情况。 + * 处理数据字典值 * - * @param record 记录对象,即要进行数据字典值处理的对象。 - * @return 处理后的对象,经过数据字典值处理后的记录对象。 + * @param record + * @return */ public Object parseObject(Object record) { + if (record == null) { return null; } - // 如果记录对象是基本数据类型,则不需要进行数据字典值处理,直接返回原对象。 + // 不处理普通数据类型 if (this.isBaseType(record.getClass())) { return record; } - // 将记录对象转换为JSON字符串,再解析为JSONObject对象,以便于通过字段名获取和设置值。 + // 转换JSON字符 String json = JSON.toJSONString(record); JSONObject item = JSONObject.parseObject(json); - for (Field field : Reflections.getAllFields(record)) { // 遍历记录对象的所有字段。 + for (Field field : Reflections.getAllFields(record)) { - // 如果字段类型是List类型,则对列表字段进行特殊处理。 + // 如果是List类型 if (List.class.isAssignableFrom(field.getType())) { try { - List list = this.processList(field, item.getObject(field.getName(), List.class)); // 调用processList方法处理列表字段。 + List list = this.processList(field, item.getObject(field.getName(), List.class)); item.put(field.getName(), list); continue; } catch (Exception e) { @@ -192,14 +159,14 @@ public class DictAspect { continue; } - // 如果字段带有数据字典注解(Dict),则对该字段进行数据字典值的翻译处理。 - if (field.getAnnotation(Dict.class)!= null) { + // 处理普通字段 + if (field.getAnnotation(Dict.class) != null) { String code = field.getAnnotation(Dict.class).dicCode(); String text = field.getAnnotation(Dict.class).dicText(); String table = field.getAnnotation(Dict.class).dictTable(); String key = String.valueOf(item.get(field.getName())); - // 调用translateDictValue方法翻译字典值对应的文本,根据字典代码、文本、表名和键值查询对应的字典文本。 + //翻译字典值对应的txt String textValue = this.translateDictValue(code, text, table, key); if (StringUtils.isEmpty(textValue)) { textValue = ""; @@ -208,22 +175,24 @@ public class DictAspect { continue; } - // 如果字段类型是日期类型(java.util.Date)且字段值不为空,则对日期字段进行格式转换处理。 - if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName())!= null) { - // 获取字段上的JsonFormat注解。 + //日期格式转换 + if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName()) != null) { + + // 获取注解 JsonFormat ann = field.getAnnotation(JsonFormat.class); - // 定义日期格式化对象。 + // 格式化方式 SimpleDateFormat fmt; - // 如果注解不为空且指定了日期格式模式,则使用注解指定的格式创建日期格式化对象。 - if (ann!= null &&!StringUtils.isEmpty(ann.pattern())) { + // 使用注解指定的 + if (ann != null && !StringUtils.isEmpty(ann.pattern())) { fmt = new SimpleDateFormat(ann.pattern()); } else { - // 如果注解为空或未指定格式,则使用默认的日期格式创建日期格式化对象。 + // 默认时间样式 fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } item.put(field.getName(), fmt.format(new Date((Long) item.get(field.getName())))); continue; + } } @@ -231,53 +200,49 @@ public class DictAspect { } /** - * 处理类型为List的字段,对列表中的每个元素进行数据字典值处理等操作。 + * 获得类型为List的值 * - * @param field 字段对象,即要处理的List类型字段。 - , - * @param list 列表对象,即字段对应的列表值。 - * @return 处理后的列表,经过数据字典值处理后的列表对象。 + * @param field + * @return */ private List processList(Field field, List list) { - // 如果列表为空,则返回一个空的ArrayList对象。 + + // 空判断 if (list == null || list.size() == 0) { return new ArrayList<>(); } - // 获取List属性的真实类型,通过反射获取字段的泛型类型,再尝试获取其实际的类型参数。 + // 获得List属性的真实类 Type genericType = field.getGenericType(); Class actualType = null; if (genericType instanceof ParameterizedType) { + // 尝试获取数据类型 ParameterizedType pt = (ParameterizedType) genericType; try { actualType = (Class) pt.getActualTypeArguments()[0]; - } catch (Exception e) { + }catch (Exception e){ return list; } } - // 如果列表元素的类型是基本数据类型,则不需要进行数据字典值处理,直接返回原列表。 + // 常规列表无需处理 if (isBaseType(actualType)) { return list; } - // 创建一个新的ArrayList对象,用于存储处理后的列表元素。 + // 返回列表 List result = new ArrayList<>(16); for (int i = 0; i < list.size(); i++) { - // 获取列表中的每个元素。 + // 创建实例-->赋值-->字典处理 Object data = list.get(i); try { - // 将列表元素转换为JSON字符串,再解析为其真实类型的对象,以便进行数据字典值处理。 data = JSON.parseObject(JSON.toJSONString(data), actualType); - } catch (Exception e) { - // 如果转换过程中出现错误,则不进行处理,直接使用原元素。 - // 这里可以根据实际需求进一步处理错误情况,比如记录日志等。 - // 目前只是简单地忽略错误,继续处理下一个元素。 - ; + }catch (Exception e){ + // 转换出错不处理 } - // 对处理后的元素进行数据字典值处理,调用parseObject方法。 + // 处理后的数据 Object pds = this.parseObject(data); result.add(pds); } @@ -286,25 +251,23 @@ public class DictAspect { } /** - , - * 根据字典代码、文本、表名和键值翻译数据字典值对应的文本。 + * 翻译实现 * - * @param code 字典代码,用于在数据字典表中定位特定的字典项。 - * @param text 字典文本,可能是与字典代码相关的描述信息等。 - * @param table 字典表名,指定要查询的数据字典表。 - * @param key 字典键值,用于在字典表中查找对应的字典项。 - * @return 翻译后的值,即根据字典代码、文本、表名和键值查询到的字典文本值,如果未找到则返回空字符串。 + * @param code + * @param text + * @param table + * @param key + * @return */ - private String translateDictValue(String code, String text, String table, String键值) { + private String translateDictValue(String code, String text, String table, String key) { if (StringUtils.isEmpty(key)) { return null; } try { - // 定义变量用于存储翻译后的字典文本值。 + // 翻译值 String dictText = null; if (!StringUtils.isEmpty(table)) { - // 如果字典表名不为空,则调用sysDictService的findDict方法查询数据字典表,获取对应的字典文本值。 - dictText = sysDictService.findDict(table, text, code, key.trim()); + dictText = sysDictService.findDict(table, text, code, key.trim()); } if (!StringUtils.isEmpty(dictText)) { @@ -317,13 +280,15 @@ public class DictAspect { } /** - * 判断给定的类是否是基本数据类型,包括常见的整数、字节、长整数、双精度浮点数、单精度浮点数、字符、短整数、布尔值以及字符串和数字类型等。 + * 判断是否基本类型 * - * @param clazz 要判断的类对象。 - * @return 是否基本类型,如果是基本数据类型则返回true,否则返回false。 + * @param clazz + * @return */ private boolean isBaseType(Class clazz) { - // 判断是否是常见的基本数据类型,如整数、字节、长整数等。 + + + // 基础数据类型 if (clazz.equals(java.lang.Integer.class) || clazz.equals(java.lang.Byte.class) || clazz.equals(java.lang.Long.class) || @@ -335,16 +300,18 @@ public class DictAspect { return true; } - // 判断是否是字符串类型。 + // String类型 if (clazz.equals(java.lang.String.class)) { return true; } - // 判断是否是数字类型(这里的数字类型可能是指抽象的数字类型,比如Number的子类等)。 + // 数字 if (clazz.equals(java.lang.Number.class)) { return true; } return false; } -} \ No newline at end of file + + +} diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java index 2ca40a4..6b958ca 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java @@ -1,255 +1,144 @@ package com.yf.exam.aspect.mybatis; -// 导入MyBatis Plus的分页拦截器类,用于实现分页功能, -// 本类继承自该类以在拦截查询操作时能正确处理分页相关逻辑。 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; - -// 导入系统用户登录信息的数据传输对象(DTO)类,用于获取当前登录用户的相关信息, -// 比如在处理查询拦截时可能需要根据登录用户的信息来过滤或修改查询语句。 import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; - -// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; - -// 导入JSqlParser库中的解析器管理器类,用于解析SQL语句, -// 在本类中用于解析查询语句以便进行后续的处理,如替换用户ID等操作。 import net.sf.jsqlparser.parser.CCJSqlParserManager; - -// 导入JSqlParser库中表示简单查询语句的类,它是查询语句的一种具体表示形式, -// 在解析查询语句后可以获取到该对象来进一步处理查询语句的内容。 import net.sf.jsqlparser.statement.select.PlainSelect; - -// 导入JSqlParser库中表示查询语句的通用类,用于接收解析后的查询语句对象, -// 以便进行后续的类型转换和处理操作。 import net.sf.jsqlparser.statement.select.Select; - -// 导入Apache Commons Lang3库中的StringUtils类,用于处理字符串相关的操作, -// 如判断字符串是否为空、非空等情况,在本类中用于判断用户ID等字符串是否有效。 import org.apache.commons.lang3.StringUtils; - -// 导入MyBatis中的语句处理器接口类,它是MyBatis在执行SQL语句时涉及的一个重要组件, -// 在本类中作为拦截的目标对象类型,以便在其执行查询准备阶段进行拦截操作。 import org.apache.ibatis.executor.statement.StatementHandler; - -// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, -// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等。 import org.apache.ibatis.mapping.MappedStatement; - -// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, -// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是否为查询语句。 import org.apache.ibatis.mapping.SqlCommandType; - -// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, -// 本类实现了该接口以作为一个MyBatis的拦截器来拦截查询语句的执行过程。 import org.apache.ibatis.plugin.Interceptor; - -// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, -// 本类通过该注解指定了要拦截StatementHandler的prepare方法。 import org.apache.ibatis.plugin.Intercepts; - -// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, -// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; - -// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, -// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; - -// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, -// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; - -// 导入MyBatis的默认反射工厂类,用于创建反射对象来访问和修改MyBatis相关对象的属性, -// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.DefaultReflectorFactory; - -// 导入MyBatis的元对象类,它提供了一种通过反射来访问和操作MyBatis相关对象属性的机制, -// 在本类中用于获取和设置StatementHandler等对象的内部属性,如SQL语句等。 import org.apache.ibatis.reflection.MetaObject; - -// 导入MyBatis的系统元对象类,它是MetaObject的一种特殊实现,提供了一些默认的对象工厂和包装器工厂, -// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.SystemMetaObject; - -// 导入Apache Shiro的安全工具类,用于获取当前安全上下文的相关信息, -// 在本类中用于获取当前登录用户的信息,以便根据用户信息来处理查询语句。 import org.apache.shiro.SecurityUtils; -// 导入Java标准库中的字符串读取器类,用于将字符串转换为可读取的流形式, -// 在本类中用于将SQL语句字符串提供给CCJSqlParserManager进行解析。 import java.io.StringReader; - -// 导入Java标准库中的数据库连接接口类,它是Java数据库操作中与数据库建立连接的关键接口, -// 在本类中作为StatementHandler的prepare方法的参数类型之一出现,虽然在本类代码中未直接对其进行复杂操作, -// 但它是MyBatis执行SQL语句过程中涉及到的重要组件之一。 import java.sql.Connection; - -// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, -// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, -// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 查询拦截器类,用于拦截处理通用的信息,如用户ID、多租户信息等。 - * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确, - * 分页计数大于实际数量等问题。 + * 查询拦截器,用于拦截处理通用的信息、如用户ID、多租户信息等; + * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确,分页计数大于实际数量等问题 * @author bool */ @Log4j2 -// 使用@Intercepts注解指定该类作为MyBatis的拦截器要拦截的目标和方法。 -// 这里拦截的是StatementHandler类的prepare方法,并且该方法的参数类型为Connection和Integer。 -@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),}) public class QueryInterceptor extends PaginationInterceptor implements Interceptor { /** - * 客户ID的占位符字符串,在原始SQL语句中如果出现该占位符,将会被替换为实际的用户ID。 + * 客户ID */ private static final String USER_FILTER = "{{userId}}"; - /** - * 拦截器的核心方法,用于在目标方法(StatementHandler的prepare方法)被调用时进行拦截处理。 - * - * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 - * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 - * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 - */ + + @Override public Object intercept(Invocation invocation) throws Throwable { - // 从invocation对象中获取被拦截的目标对象,即StatementHandler对象。 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); - - // 使用MetaObject.forObject方法创建一个元对象,用于通过反射访问和修改StatementHandler对象的属性。 - // 这里传入了默认的对象工厂、包装器工厂和反射工厂,以便能够正确地操作StatementHandler对象的内部属性。 MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); - - // 从元对象中获取MappedStatement对象,该对象包含了关于SQL语句的映射信息,如SQL语句的ID、参数映射、结果映射等。 MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); - // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 - // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 + //sql语句类型 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - // 只对查询类型的SQL语句进行处理,如果当前SQL语句类型是SELECT,则进入下面的处理逻辑。 + // 只过滤查询的 if (SqlCommandType.SELECT == sqlCommandType) { - - // 获取原始的SQL语句,通过StatementHandler的getBoundSql方法获取绑定的SQL语句对象,再获取其SQL字符串。 + // 获得原始SQL String sql = statementHandler.getBoundSql().getSql(); - // 如果原始SQL语句中不包含用户ID占位符(USER_FILTER),则直接调用父类(PaginationInterceptor)的intercept方法, - // 即按照原有的分页逻辑进行处理,不进行用户ID相关的替换等操作。 - if (!sql.contains(USER_FILTER)) { + // 不处理 + if(!sql.contains(USER_FILTER)){ return super.intercept(invocation); } - - // 如果原始SQL语句中包含用户ID占位符,则需要对SQL语句进行处理。 - // 首先调用parseSql方法对SQL语句进行解析和处理,包括替换用户ID等操作。 + // 处理SQL语句 String outSql = this.parseSql(sql); - - // 将处理后的SQL语句设置回StatementHandler对象的内部属性中,通过元对象的setValue方法设置boundSql.sql属性的值。 + // 设置SQL metaObject.setValue("delegate.boundSql.sql", outSql); - - // 再次调用父类(PaginationInterceptor)的intercept方法,此时是在处理完用户ID等信息后, - // 按照正确的分页逻辑进行处理,以确保分页功能在拦截数据并处理相关信息后正确执行。 + // 再分页 return super.intercept(invocation); } - // 如果当前SQL语句不是查询类型(SELECT),则直接执行被拦截方法的原有逻辑,不进行额外的处理。 return invocation.proceed(); } - /** - * 将拦截器包装成MyBatis可识别的插件形式的方法。 - * - * @param target 要包装的目标对象,通常是被拦截的对象,如StatementHandler等。 - * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 - */ @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } - /** - * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, - * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 - * - * @param properties 包含了外部配置的属性信息的Properties对象。 - */ @Override public void setProperties(Properties properties) { } + + /** - * 获取当前登录用户的方法,通过Apache Shiro的SecurityUtils工具类来获取当前安全上下文的主体对象, - * 并获取其主体信息(即登录用户的信息),如果获取成功则转换为SysUserLoginDTO类型返回,否则返回null。 - * - * @return 返回当前登录用户的SysUserLoginDTO对象,如果获取失败则返回null。 + * 获取当前登录用户 + * @return */ private SysUserLoginDTO getLoginUser() { try { - return SecurityUtils.getSubject().getPrincipal()!= null? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; + return SecurityUtils.getSubject().getPrincipal() != null ? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; } catch (Exception e) { return null; } } /** - * 替换用户ID的方法,根据当前登录用户的ID,将原始SQL语句中的用户ID占位符(USER_FILTER)替换为实际的用户ID。 - * - * @param sql 原始的SQL语句。 - * @return 返回替换用户ID后的SQL语句,如果用户ID为空,则返回null。 + * 替换用户ID + * @param sql + * @return */ private String processUserId(String sql) { - // 获取当前登录用户的信息,通过调用getLoginUser方法获取。 + // 当前用户 SysUserLoginDTO user = this.getLoginUser(); String userId = user.getId(); - - // 如果获取到的用户ID不为空,则将原始SQL语句中的用户ID占位符替换为实际的用户ID,并返回替换后的SQL语句。 - if (StringUtils.isNotBlank(userId)) { + if(StringUtils.isNotBlank(userId)){ return sql.replace(USER_FILTER, userId); } - - // 如果用户ID为空,则返回null。 return null; } /** - * 处理注入用户信息的方法,主要用于解析原始SQL语句,替换用户ID等操作,以实现根据用户信息来调整查询语句的目的。 - * - * @param src 原始的SQL语句。 - * @return 返回处理后的SQL语句,如果在处理过程中出现异常,则返回原始的SQL语句。 + * 处理注入用户信息 + * @param src + * @return */ private String parseSql(String src) { - // 创建一个CCJSqlParserManager对象,用于解析SQL语句。 CCJSqlParserManager parserManager = new CCJSqlParserManager(); try { - // 使用CCJSqlParserManager对象的parse方法解析原始SQL语句,将其转换为Select类型的对象。 - // 这里需要将原始SQL语句通过StringReader转换为可读取的流形式提供给parse方法进行解析。 Select select = (Select) parserManager.parse(new StringReader(src)); - - // 从Select对象中获取其查询主体部分,即PlainSelect对象,它包含了查询语句的具体内容,如查询条件、字段等。 PlainSelect selectBody = (PlainSelect) select.getSelectBody(); - // 将PlainSelect对象转换为字符串形式,得到初步处理后的SQL语句。 - // 这里主要是为了后续方便进行用户ID等信息的替换操作。 + // 过滤客户 String sql = selectBody.toString(); - // 调用processUserId方法对初步处理后的SQL语句进行用户ID的替换操作,将用户ID占位符替换为实际的用户ID。 + // 过滤用户ID sql = this.processUserId(sql); - // 返回处理后的SQL语句。 + // 获得SQL return sql; } catch (Exception e) { e.printStackTrace(); } - // 如果在处理过程中出现异常,则返回原始的SQL语句。 return src; } -} \ No newline at end of file + + +} diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java index c85e5f0..8baae8f 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java @@ -1,188 +1,80 @@ -// 定义包路径,用于存放更新拦截器相关的类。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.mybatis部分, -// 通常用于组织和管理与MyBatis相关的切面逻辑代码。 package com.yf.exam.aspect.mybatis; -// 导入MyBatis-Plus的抽象SQL解析处理器类,它提供了一些基础的SQL解析处理功能, -// 本类继承自该类以便在处理更新操作时利用其相关功能或遵循其处理规范。 import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; - -// 导入Apache Commons Lang3库中的数组工具类,用于对数组进行各种操作, -// 如合并数组等,在本类中用于合并对象的字段数组(当存在父类字段时)。 import org.apache.commons.lang3.ArrayUtils; - -// 导入MyBatis中的执行器接口类,它是MyBatis执行SQL语句的核心组件,负责实际执行数据库操作, -// 在本类中作为拦截的目标对象类型,通过拦截其update方法来实现自动设置创建时间和更新时间的功能。 import org.apache.ibatis.executor.Executor; - -// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, -// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等, -// 以便根据不同的操作类型(插入、更新等)来处理创建时间和更新时间的赋值。 import org.apache.ibatis.mapping.MappedStatement; - -// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, -// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是何种类型的操作, -// 从而确定是否需要对创建时间和更新时间进行赋值。 import org.apache.ibatis.mapping.SqlCommandType; - -// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, -// 本类实现了该接口以作为一个MyBatis的拦截器来拦截更新语句的执行过程,实现自动设置时间的功能。 import org.apache.ibatis.plugin.Interceptor; - -// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, -// 本类通过该注解指定了要拦截Executor类的update方法。 import org.apache.ibatis.plugin.Intercepts; - -// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, -// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; - -// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, -// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; - -// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, -// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; -// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, -// 在本类中用于获取和设置对象的创建时间和更新时间字段的值。 import java.lang.reflect.Field; - -// 导入Java标准库中的时间戳类,用于表示某个特定时刻的时间点, -// 在本类中用于设置创建时间和更新时间为当前的时间戳,以记录操作发生的准确时间。 import java.sql.Timestamp; - -// 导入Java标准库中的对象工具类,提供了一些用于比较和操作对象的方法, -// 在本类中用于比较字段名与预定义的创建时间、更新时间字段名是否相等。 import java.util.Objects; - -// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, -// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, -// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 该类是一个更新拦截器,主要功能是自动给创建时间和更新时间字段赋值。 - * 它会拦截MyBatis执行器(Executor)的update方法,根据操作类型(插入或更新)以及对象的字段情况, - * 为创建时间和更新时间字段设置当前的时间戳值。 + * 自动给创建时间个更新时间加值 * @author bool */ @Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) -// 使用@Intercepts注解并通过@Signature指定该类作为MyBatis的拦截器要拦截的目标和方法。 -// 这里拦截的是Executor类的update方法,并且该方法的参数类型为MappedStatement和Object。 public class UpdateInterceptor extends AbstractSqlParserHandler implements Interceptor { /** - * 定义创建时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的创建时间字段。 + * 创建时间 */ private static final String CREATE_TIME = "createTime"; - /** - * 定义更新时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的更新时间字段。 + * 更新时间 */ private static final String UPDATE_TIME = "updateTime"; - /** - * 拦截器的核心方法,用于在目标方法(Executor的update方法)被调用时进行拦截处理。 - * - * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 - * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 - * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 - */ @Override public Object intercept(Invocation invocation) throws Throwable { - // 从invocation对象的参数数组中获取第一个参数,即MappedStatement对象, - // 它包含了关于SQL语句的映射信息,用于后续获取SQL命令类型等操作。 MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; - - // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 - // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 + // SQL操作命令 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - - // 从invocation对象的参数数组中获取第二个参数,即要进行新增或修改操作的对象参数, - // 后续会通过反射操作该对象来设置创建时间和更新时间字段的值。 + // 获取新增或修改的对象参数 Object parameter = invocation.getArgs()[1]; - - // 获取对象中所有的私有成员变量(对应表字段),通过反射获取parameter对象的声明字段数组。 + // 获取对象中所有的私有成员变量(对应表字段) Field[] declaredFields = parameter.getClass().getDeclaredFields(); - - // 判断parameter对象的父类是否存在,如果存在则获取父类的声明字段数组, - // 并将其与之前获取的子类声明字段数组进行合并,以获取完整的包含父类和子类字段的数组。 - if (parameter.getClass().getSuperclass()!= null) { + if (parameter.getClass().getSuperclass() != null) { Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields(); declaredFields = ArrayUtils.addAll(declaredFields, superField); } - // 用于临时存储当前遍历到的字段名,以便后续与预定义的创建时间、更新时间字段名进行比较。 String fieldName = null; - - // 遍历获取到的所有字段数组(包含父类和子类字段),对每个字段进行处理。 for (Field field : declaredFields) { fieldName = field.getName(); - - // 如果当前遍历到的字段名与预定义的创建时间字段名相等,说明找到了创建时间字段。 if (Objects.equals(CREATE_TIME, fieldName)) { - - // 如果当前SQL语句的操作类型是插入操作(INSERT),则需要为创建时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType)) { - - // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); - - // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, - // 再创建一个Timestamp对象来表示该时间点,从而为创建时间字段赋值。 field.set(parameter, new Timestamp(System.currentTimeMillis())); } } - - // 如果当前遍历到的字段名与预定义的更新时间字段名相等,说明找到了更新时间字段。 if (Objects.equals(UPDATE_TIME, fieldName)) { - - // 如果当前SQL语句的操作类型是插入操作(INSERT)或者更新操作(UPDATE), - // 则需要为更新时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { - - // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); - - // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, - // 再创建一个Timestamp对象来表示该时间点,从而为更新时间字段赋值。 field.set(parameter, new Timestamp(System.currentTimeMillis())); + } } } - - // 继续执行被拦截的Executor的update方法的原有逻辑,经过上述处理后, - // 已经为创建时间和更新时间字段设置了合适的值(如果符合条件的话),现在继续执行原始的更新操作。 return invocation.proceed(); } - /** - * 将拦截器包装成MyBatis可识别的插件形式的方法。 - * - * @param target 要包装的目标对象,通常是被拦截的对象,如Executor等。 - * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 - */ @Override public Object plugin(Object target) { - // 如果目标对象是Executor类型,说明是我们要拦截的对象, - // 则使用Plugin.wrap方法将拦截器(this)包装到目标对象上,以便实现拦截功能。 if (target instanceof Executor) { return Plugin.wrap(target, this); } - - // 如果目标对象不是Executor类型,说明不是我们要拦截的对象,直接返回该目标对象即可。 return target; } - /** - * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, - * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 - * - * @param properties 包含了外部配置的属性信息的Properties对象。 - */ @Override public void setProperties(Properties properties) { - // 这里暂时没有具体的设置属性操作,可根据后续需求添加相关逻辑来处理接收到的属性信息。 } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java index 77ed253..4b47fee 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java +++ b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java @@ -1,128 +1,99 @@ -// 定义包路径,用于存放注入工具类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.utils部分, -// 通常用于组织和管理与注入操作相关的工具类代码。 package com.yf.exam.aspect.utils; -// 导入FastJSON库,它是一个用于将Java对象与JSON字符串进行相互转换的高性能库, -// 在本类的restError方法中用于将API响应对象转换为JSON字符串以便写入HTTP响应中。 import com.alibaba.fastjson.JSON; - -// 导入API错误类,它可能定义了一系列表示不同类型API错误的常量或属性, -// 在本类的restError方法中用于创建包含特定错误信息的API响应对象。 import com.yf.exam.core.api.ApiError; - -// 导入API响应类,它用于封装API调用的返回结果,包括成功的结果以及可能出现的错误信息等, -// 在本类的restError方法中用于创建要返回给客户端的错误响应对象。 import com.yf.exam.core.api.ApiRest; - -// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; - -// 导入Spring框架的组件注解,用于标记该类是一个Spring组件,这样Spring容器可以对其进行管理和实例化, -// 使其能够在Spring应用程序中被其他组件所使用。 import org.springframework.stereotype.Component; -// 导入Java标准库中的HTTP响应类,用于处理HTTP协议相关的响应操作, -// 在本类的restError方法中用于设置响应的编码、内容类型以及写入响应内容等操作。 import javax.servlet.http.HttpServletResponse; - -// 导入Java标准库中的IO异常类,用于处理输入输出操作过程中可能出现的异常情况, -// 在本类的restError方法以及其他可能涉及到IO操作的地方用于捕获和处理相关异常。 import java.io.IOException; - -// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, -// 在本类的setValue和getFiled方法中用于获取和设置对象的指定字段的值。 import java.lang.reflect.Field; /** - * 注入工具类,提供了一些用于对象字段赋值以及处理错误响应返回等功能的方法。 + * 注入工具类 * @author bool * @date 2019-07-17 09:32 */ -@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 -@Component // 将该类标记为Spring组件,使其能够被Spring容器管理和使用。 +@Log4j2 +@Component public class InjectUtils { + + /** - * 给指定对象的指定字段赋值的方法。 + * 给对象字段赋值 * - * @param object 要进行赋值操作的对象。 - * @param value 要赋给指定字段的值。 - * @param fields 一个可变参数,用于指定要赋值的字段名数组。 - * @throws Exception 如果在获取字段或设置字段值的过程中出现异常,则抛出。 + * @param object 赋值的对象 + * @param value 值 + * @param fields 字段 + * @throws Exception 异常 */ public void setValue(Object object, Object value, String... fields) throws Exception { - // 遍历要赋值的字段名数组 + + //设置同类的属性 for (String fieldName : fields) { - // 根据对象的类和字段名获取对应的字段对象 - Field field = this.getFiled(object.getClass(), fieldName); - // 如果获取到的字段对象为空,说明未找到对应的字段,继续下一个字段的处理。 - if (field == null) { + //获取当前 + Field field = this.getFiled(object.getClass(), fieldName); + if(field == null){ continue; } - // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); - - // 使用反射设置该字段的值为传入的值,即将指定的值赋给对象的指定字段。 field.set(object, value); } + } /** - * 根据目标类和字段名获取对应的字段对象的方法。 + * 获取字段名对应的字段 * - * @param clazz 目标类,即要在其中查找字段的类。 - * @param fieldName 要查找的字段名。 - * @return 返回找到的字段对象,如果未找到则返回null。 + * @param clazz 目标类 + * @param fieldName 字段名 */ private Field getFiled(Class clazz, String fieldName) { - System.out.println("注入的类:" + clazz.toString()); // 打印当前正在查找字段的目标类的信息,方便调试查看。 - // 尝试获取当前类中指定字段名的字段对象 + System.out.println("注入的类:"+clazz.toString()); + + //是否具有包含关系 try { + //获取当前类的属性 return clazz.getDeclaredField(fieldName); - } catch (Exception e) { - log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); // 如果获取字段失败,记录错误日志, - // 提示在当前类中不存在指定字段, - // 并准备尝试在父类中查找。 + }catch (Exception e){ - // 如果当前类未找到指定字段且存在父类,则递归调用本方法在父类中继续查找指定字段。 - if (clazz.getSuperclass()!= null) { + log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); + + //如果为空且存在父类,则往上找 + if(clazz.getSuperclass()!=null){ return this.getFiled(clazz.getSuperclass(), fieldName); } - // 如果在当前类及其所有父类中都未找到指定字段,则返回null。 return null; } } + /** - * 用于处理错误情况并将错误结果返回给客户端的方法,通过设置HTTP响应的相关属性和写入错误响应内容来实现。 - * - * @param response HTTP响应对象,用于向客户端发送响应信息。 - * @throws IOException 如果在设置响应属性或写入响应内容过程中出现IO异常,则抛出。 + * 打印结果返回 + * @param response + * @throws IOException */ public static void restError(HttpServletResponse response) { + try { - // 创建一个包含特定API错误信息的API响应对象,这里使用了ApiError.ERROR_10010002作为错误码, - // 具体含义可能在ApiError类中定义,通常表示某种常见的错误情况。 - ApiRest apiRest = new ApiRest(ApiError.ERROR_10010002); - // 设置HTTP响应的字符编码为UTF-8,确保能够正确处理和传输各种字符,特别是中文等非ASCII字符。 + //固定错误 + ApiRest apiRest = new ApiRest(ApiError.ERROR_10010002); response.setCharacterEncoding("UTF-8"); - - // 设置HTTP响应的内容类型为application/json,表明返回给客户端的内容是JSON格式的数据。 response.setContentType("application/json"); - - // 将创建的API响应对象转换为JSON字符串,并写入到HTTP响应的输出流中,以便客户端能够接收到错误信息。 response.getWriter().write(JSON.toJSONString(apiRest)); - - // 关闭HTTP响应的写入流,释放相关资源。 response.getWriter().close(); - } catch (IOException e) { - // 如果在设置响应属性或写入响应内容过程中出现IO异常,这里只是简单地捕获异常, - // 可以根据实际需求进一步处理异常,比如记录更详细的日志信息等。 + + }catch (IOException e){ + } + } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java index 83b86ab..e88cb08 100644 --- a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java @@ -1,81 +1,35 @@ package com.yf.exam.config; -// 导入Spring Boot中用于注册Servlet过滤器的类,通过它可以将自定义的过滤器注册到Servlet容器中, -// 并配置相关属性,如过滤器的执行顺序等。在本类中用于注册跨域过滤器(CorsFilter)。 import org.springframework.boot.web.servlet.FilterRegistrationBean; - -// 导入Spring框架中用于标记一个类是配置类的注解,被该注解标记的类可以在其中定义各种Bean配置方法, -// 这些方法会被Spring容器在启动时自动识别并执行,用于创建和配置应用程序所需的各种组件。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; - -// 导入Spring框架中用于指定顺序的接口,实现该接口可以定义对象的顺序, -// 在本类中用于指定跨域过滤器(CorsFilter)在过滤器链中的执行顺序,使其具有最高优先级。 import org.springframework.core.Ordered; - -// 导入Spring框架中用于配置跨域资源共享(Cors)的类,通过它可以设置允许的源、请求头、请求方法等跨域相关的配置项。 import org.springframework.web.cors.CorsConfiguration; - -// 导入Spring框架中基于URL的跨域配置源类,它允许根据不同的URL模式来配置不同的跨域设置, -// 在本类中用于创建一个基于URL的跨域配置源,并将统一的跨域配置应用到所有的URL路径("**")上。 import org.springframework.web.cors.UrlBasedCorsConfigurationSource; - -// 导入Spring框架中实现跨域过滤功能的类,它会根据配置的跨域规则对请求进行过滤和处理, -// 以实现允许跨域访问的功能。在本类中创建该过滤器并将其注册到Servlet容器中。 import org.springframework.web.filter.CorsFilter; + /** - * 网关全局设置类,主要功能是配置允许跨域访问的相关设置。 - * 通过创建和注册跨域过滤器(CorsFilter),并设置允许的源、请求头、请求方法等配置项, - * 使得应用程序能够处理来自不同域的请求,避免跨域访问限制。 - * + * 网关全局设置,允许跨域 * @author bool * @date 2019-08-13 17:28 */ -@Configuration // 标记该类为Spring框架的配置类,表明其中可以定义各种Bean的创建和配置方法。 + +@Configuration public class CorsConfig { - /** - * 定义一个Bean方法,用于创建并返回一个FilterRegistrationBean对象,该对象用于注册跨域过滤器(CorsFilter)。 - * - * @return 返回一个FilterRegistrationBean对象,其中包含了配置好的跨域过滤器以及相关的执行顺序等设置。 - */ @Bean public FilterRegistrationBean corsFilter() { - // 创建一个基于URL的跨域配置源对象,它将作为跨域配置的基础,用于后续设置跨域规则并应用到特定的URL路径上。 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - - // 创建一个CorsConfiguration对象,用于设置具体的跨域配置项,如允许的源、请求头、请求方法等。 CorsConfiguration config = new CorsConfiguration(); - - // 设置是否允许携带凭证(如Cookie等)进行跨域请求,这里设置为true,表示允许携带凭证。 config.setAllowCredentials(true); - - // 添加允许的源,这里使用CorsConfiguration.ALL表示允许所有的源进行跨域访问。 - // 可以根据实际需求设置具体的源地址,如"http://example.com"等,多个源地址可以多次调用addAllowedOrigin方法添加。 config.addAllowedOrigin(CorsConfiguration.ALL); - - // 添加允许的请求头,同样使用CorsConfiguration.ALL表示允许所有的请求头进行跨域请求。 - // 如果需要限制特定的请求头,可以通过其他方式设置具体的请求头列表。 config.addAllowedHeader(CorsConfiguration.ALL); - - // 添加允许的请求方法,使用CorsConfiguration.ALL表示允许所有的请求方法进行跨域请求, - // 包括常见的GET、POST、PUT、DELETE等方法。也可以根据实际需求设置具体的请求方法列表。 config.addAllowedMethod(CorsConfiguration.ALL); - - // 将上述设置好的跨域配置应用到所有的URL路径上,"**"表示匹配任意的URL路径。 - // 这样,对于应用程序接收到的任何请求,都会根据这个统一的跨域配置进行处理。 source.registerCorsConfiguration("/**", config); - - // 创建一个FilterRegistrationBean对象,用于注册跨域过滤器(CorsFilter)。 - // 将创建好的基于上述跨域配置源的跨域过滤器(new CorsFilter(source))作为参数传入FilterRegistrationBean的构造函数。 FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); - - // 设置跨域过滤器在过滤器链中的执行顺序,这里设置为Ordered.HIGHEST_PRECEDENCE,表示具有最高优先级。 - // 即该过滤器会在其他过滤器之前首先对请求进行处理,以确保跨域配置能够最先生效。 bean.setOrder(Ordered.HIGHEST_PRECEDENCE); - - // 返回配置好的FilterRegistrationBean对象,完成跨域过滤器的注册和相关设置。 return bean; } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java index 69d16f5..75e6dfa 100644 --- a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java @@ -1,67 +1,28 @@ -// 定义包路径,用于存放文件上传配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, -// 通常用于组织和管理与文件上传配置相关的代码。 package com.yf.exam.config; -// 导入Spring Boot中用于创建和配置多部分(Multipart)上传相关设置的工厂类。 -// 通过这个工厂类可以方便地设置如单个文件大小限制、总上传数据大小限制等参数, -// 在本类中用于创建和配置文件上传的相关限制。 import org.springframework.boot.web.servlet.MultipartConfigFactory; - -// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 -// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 -// 在本类中用于将multipartConfigElement方法返回的MultipartConfigElement对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; - -// 导入Spring框架中用于标记一个类是配置类的注解。 -// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, -// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行文件上传相关的配置。 import org.springframework.context.annotation.Configuration; - -// 导入Spring框架中用于处理数据大小单位转换和表示的工具类。 -// 它可以方便地将不同单位的数据大小表示转换为统一的格式, -// 在本类中用于设置文件上传的单个文件大小和总上传数据大小的限制,以兆字节(MB)为单位进行设置。 import org.springframework.util.unit.DataSize; -// 导入Java标准库中的用于表示多部分(Multipart)上传配置元素的接口。 -// 这个接口定义了多部分上传相关的配置参数,如文件大小限制、请求大小限制等, -// 在本类中通过MultipartConfigFactory创建并返回实现了该接口的对象,以完成文件上传的配置设置。 import javax.servlet.MultipartConfigElement; /** - * 文件上传配置类,主要功能是配置文件上传过程中的相关参数, -// 包括单个文件的最大允许大小以及整个上传请求的最大允许数据大小等。 - * + * 文件上传配置 * @author bool * @date 2019-07-29 16:23 */ -@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@Configuration public class MultipartConfig { - /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个MultipartConfigElement对象,这个对象包含了文件上传的具体配置参数。 - * - * @return 返回一个MultipartConfigElement对象,其中设置了单个文件大小和总上传数据大小的限制等配置信息。 - */ @Bean public MultipartConfigElement multipartConfigElement() { - MultipartConfigFactory factory = new MultipartConfigFactory(); // 创建一个MultipartConfigFactory对象, - // 它是用于创建MultipartConfigElement对象的工厂类, - // 通过它可以方便地设置各种文件上传的配置参数。 - - // 设置单个文件的最大允许大小。 - // 这里使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), - // 即限制单个上传的文件大小不能超过5000MB。 + MultipartConfigFactory factory = new MultipartConfigFactory(); + // 单个数据大小 factory.setMaxFileSize(DataSize.ofMegabytes(5000L)); - - // 设置整个上传请求的最大允许数据大小。 - // 同样使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), - // 也就是说,整个上传请求(包括可能上传的多个文件以及其他相关数据)的总数据量不能超过5000MB。 + /// 总上传数据大小 factory.setMaxRequestSize(DataSize.ofMegabytes(5000L)); - - // 通过MultipartConfigFactory对象的createMultipartConfig方法创建并返回一个MultipartConfigElement对象, - // 这个对象包含了我们刚刚设置的单个文件大小和总上传数据大小等配置信息, - // 它会被Spring容器管理并应用到文件上传的相关处理中。 return factory.createMultipartConfig(); } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java index 1645a7f..642fc25 100644 --- a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java @@ -1,70 +1,37 @@ -// 定义包路径,用于存放MyBatis配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, -// 通常用于组织和管理与MyBatis配置相关的代码。 package com.yf.exam.config; -// 导入自定义的查询拦截器类,该拦截器用于在查询操作时进行一些额外的处理, -// 比如可能会根据特定条件对查询语句进行修改、添加过滤条件等操作。 import com.yf.exam.aspect.mybatis.QueryInterceptor; - -// 导入自定义的更新拦截器类,该拦截器用于在插入或更新操作时进行相关处理, -// 例如自动设置创建时间、更新时间等字段的值。 import com.yf.exam.aspect.mybatis.UpdateInterceptor; - -// 导入MyBatis与Spring集成时用于扫描MyBatis映射接口的注解。 -// 通过该注解可以指定要扫描的包路径,以便Spring能够自动发现并注册MyBatis的映射接口, -// 使得这些接口可以被正确地用于数据库操作。 import org.mybatis.spring.annotation.MapperScan; - -// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 -// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 -// 在本类中用于将queryInterceptor和updateInterceptor方法返回的拦截器对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; - -// 导入Spring框架中用于标记一个类是配置类的注解。 -// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, -// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行MyBatis相关的配置。 import org.springframework.context.annotation.Configuration; /** - * Mybatis过滤器配置类,主要功能是配置MyBatis的相关过滤器, - * 包括查询拦截器和更新拦截器等,并设置相关参数。同时通过注解指定MyBatis映射接口的扫描路径。 - * 注意:必须按顺序进行配置,否则容易出现业务异常。 + * Mybatis过滤器配置 + * 注意:必须按顺序进行配置,否则容易出现业务异常 * @author bool */ -@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 -@MapperScan("com.yf.exam.modules.**.mapper") // 使用MapperScan注解指定要扫描的MyBatis映射接口所在的包路径, - // "com.yf.exam.modules.**.mapper"表示会扫描com.yf.exam.modules包及其子包下的所有mapper接口。 - +@Configuration +@MapperScan("com.yf.exam.modules.**.mapper") public class MybatisConfig { /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个查询拦截器(QueryInterceptor)对象,用于在查询操作时进行拦截处理。 - * - * @return 返回一个查询拦截器(QueryInterceptor)对象,该对象已进行了相关设置(如设置查询限制)。 + * 数据查询过滤器 */ - @Bean // 将该方法返回的查询拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 + @Bean public QueryInterceptor queryInterceptor() { - QueryInterceptor query = new QueryInterceptor(); // 创建一个新的查询拦截器对象。 - - // 设置查询限制,这里将查询限制设置为 -1L,具体含义可能根据QueryInterceptor类的内部逻辑而定, - // 可能表示不限制查询结果的数量或者有其他特殊的处理方式与该值相关。 + QueryInterceptor query = new QueryInterceptor(); query.setLimit(-1L); - - // 返回设置好的查询拦截器对象,该对象将被Spring容器管理并在合适的查询操作场景中被调用执行拦截处理。 return query; } /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个更新拦截器(UpdateInterceptor)对象,用于在插入或更新操作时进行拦截处理。 - * - * @return 返回一个更新拦截器(UpdateInterceptor)对象,该对象可直接用于插入或更新操作的拦截处理。 + * 插入数据过滤器 */ - @Bean // 将该方法返回的更新拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 + @Bean public UpdateInterceptor updateInterceptor() { - // 创建一个新的更新拦截器对象,这里没有进行额外的设置操作(可能在UpdateInterceptor类内部有默认的处理逻辑), - // 直接返回该对象,它将被Spring容器管理并在合适的插入或更新操作场景中被调用执行拦截处理。 return new UpdateInterceptor(); } + + } \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java index 994b761..b08f96f 100644 --- a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java @@ -1,182 +1,77 @@ -// 定义包路径,用于存放任务调度配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, -// 通常用于组织和管理与任务调度配置相关的代码。 package com.yf.exam.config; -// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; - -// 导入Spring框架中用于处理异步方法执行过程中未捕获异常的处理器接口。 -// 当异步方法抛出异常且未在方法内部被捕获时,会由该处理器来处理异常情况, -// 在本类中实现该接口来定义异步未捕获异常的处理逻辑。 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; - -// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 -// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 -// 在本类中用于将taskScheduler和asyncExecutor等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; - -// 导入Spring框架中用于标记一个类是配置类的注解。 -// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, -// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行任务调度相关的配置。 import org.springframework.context.annotation.Configuration; - -// 导入Spring框架中用于配置异步任务执行相关设置的接口。 -// 实现该接口可以定义异步任务执行的线程池等配置信息,在本类中实现该接口来配置异步任务执行的相关参数。 import org.springframework.scheduling.annotation.AsyncConfigurer; - -// 导入Spring框架中用于启用异步任务执行功能的注解。 -// 当在类上添加该注解后,Spring会自动识别并处理类中的异步方法,使其能够在独立的线程中执行。 -// 在本类上添加该注解以启用异步任务执行功能。 import org.springframework.scheduling.annotation.EnableAsync; - -// 导入Spring框架中用于启用任务调度功能的注解。 -// 当在类上添加该注解后,Spring会自动识别并处理类中的定时任务等调度相关的设置,使其能够按照预定的时间执行任务。 -// 在本类上添加该注解以启用任务调度功能。 import org.springframework.scheduling.annotation.EnableScheduling; - -// 导入Spring框架中用于配置任务调度相关设置的接口。 -// 实现该接口可以定义任务调度的线程池、任务注册等配置信息,在本类中实现该接口来配置任务调度的相关参数。 import org.springframework.scheduling.annotation.SchedulingConfigurer; - -// 导入Spring框架中用于执行线程池任务的执行器类。 -// 它可以创建一个线程池,并通过该线程池来执行任务,在本类的asyncExecutor方法中用于创建异步任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -// 导入Spring框架中用于调度线程池任务的调度器类。 -// 它可以创建一个线程池,并通过该线程池来调度任务的执行时间,在本类的taskScheduler方法中用于创建定时任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; - -// 导入Spring框架中用于注册调度任务的类。 -// 通过它可以将需要调度执行的任务注册到相应的调度器中,在本类的configureTasks方法中用于设置任务调度器。 import org.springframework.scheduling.config.ScheduledTaskRegistrar; -// 导入Java标准库中的执行器接口,它定义了执行任务的通用规范, -// 在本类的getAsyncExecutor方法中用于返回异步任务执行的执行器对象。 import java.util.concurrent.Executor; - -// 导入Java标准库中的线程池执行器类,它是实现了线程池功能的具体类, -// 在本类的asyncExecutor方法中用于设置异步任务执行线程池的拒绝策略。 import java.util.concurrent.ThreadPoolExecutor; /** - * 任务调度配置类,主要功能是配置任务调度和异步任务执行相关的设置, - * 包括创建定时任务执行的线程池和异步任务执行的线程池,设置线程池的大小、名称前缀、 - * 等待终止时间、队列容量等参数,同时实现了处理异步未捕获异常的逻辑。 + * 任务调度配置 * @author bool */ -@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 -@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 -@EnableScheduling // 使用该注解启用任务调度功能,使得Spring能够识别并处理类中的定时任务等调度相关设置。 -@EnableAsync // 使用该注解启用异步任务执行功能,使得Spring能够识别并处理类中的异步方法,使其能够在独立的线程中执行。 +@Log4j2 +@Configuration +@EnableScheduling +@EnableAsync public class ScheduledConfig implements SchedulingConfigurer, AsyncConfigurer { /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,用于定时任务的执行调度。 - * - * @return 返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,该对象已进行了相关设置(如线程池大小、名称前缀等)。 + * 定时任务使用的线程池 + * @return */ - @Bean(destroyMethod = "shutdown", name = "taskScheduler") // 将该方法返回的线程池任务调度器对象声明为Spring Bean, - // 并指定销毁方法为"shutdown",以便在容器关闭时正确关闭线程池。 - public ThreadPoolTaskScheduler taskScheduler() { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 创建一个新的线程池任务调度器对象。 - - // 设置线程池的大小,即同时可执行的定时任务数量,这里设置为10,表示线程池最多可同时执行10个定时任务。 + @Bean(destroyMethod = "shutdown", name = "taskScheduler") + public ThreadPoolTaskScheduler taskScheduler(){ + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); - - // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务调度器,这里设置为"task-", - // 生成的线程名称可能类似"task-1"、"task-2"等。 scheduler.setThreadNamePrefix("task-"); - - // 设置线程池在关闭时等待任务完成的时间,单位为秒,这里设置为600秒(10分钟), - // 表示在容器关闭时,线程池会等待正在执行的任务完成,最长等待时间为10分钟。 scheduler.setAwaitTerminationSeconds(600); - - // 设置在关闭时是否等待任务完成,这里设置为true,表示在容器关闭时,线程池会等待所有任务完成后再关闭。 scheduler.setWaitForTasksToCompleteOnShutdown(true); - - // 返回设置好的线程池任务调度器对象,该对象将被Spring容器管理并在定时任务执行场景中被调用进行任务调度。 return scheduler; } /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,用于异步任务的执行。 - * - * @return 返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,该对象已进行了相关设置(如核心线程数、队列容量等)。 + * 异步任务执行线程池 + * @return */ - @Bean(name = "asyncExecutor") // 将该方法返回的线程池任务执行器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 + @Bean(name = "asyncExecutor") public ThreadPoolTaskExecutor asyncExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 创建一个新的线程池任务执行器对象。 - - // 设置线程池的核心线程数,即线程池始终保持的活跃线程数量,这里设置为10,表示线程池至少会保持10个线程处于活跃状态。 + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); - - // 设置线程池的队列容量,即用于存储等待执行任务的队列大小,这里设置为1000,表示队列最多可容纳1000个等待执行的任务。 executor.setQueueCapacity(1000); - - // 设置线程池中非核心线程的保持活动时间,单位为秒,这里设置为600秒(10分钟), - // 表示当非核心线程空闲时间超过10分钟时,可能会被回收。 executor.setKeepAliveSeconds(600); - - // 设置线程池的最大线程数,即线程池最多可同时拥有的线程数量,这里设置为20,表示线程池最多可扩展到20个线程同时执行任务。 executor.setMaxPoolSize(20); - - // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务执行器,这里设置为"taskExecutor-", - // 生成的线程名称可能类似"taskExecutor-1"、"taskExecutor-2"等。 executor.setThreadNamePrefix("taskExecutor-"); - - // 设置线程池的拒绝策略,这里采用ThreadPoolExecutor.CallerRunsPolicy(), - // 表示当线程池和队列都已满,无法再接受新任务时,会由调用线程来执行该任务,而不是直接抛出异常。 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - - // 初始化线程池,使其处于可使用状态,完成各项参数的设置和内部资源的初始化。 executor.initialize(); - - // 返回设置好的线程池任务执行器对象,该对象将被Spring容器管理并在异步任务执行场景中被调用进行任务执行。 return executor; } - /** - * 实现SchedulingConfigurer接口的方法,用于配置任务调度相关的设置。 - * 在本方法中,获取之前创建的线程池任务调度器对象,并将其设置到调度任务注册类中, - * 以便后续注册的定时任务能够使用该调度器进行任务调度。 - * - * @param scheduledTaskRegistrar 调度任务注册类对象,用于注册调度任务和设置调度器等操作。 - */ @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { - ThreadPoolTaskScheduler taskScheduler = taskScheduler(); // 获取之前创建的线程池任务调度器对象。 - - // 将获取到的线程池任务调度器对象设置到调度任务注册类中,使得后续注册的定时任务能够使用该调度器进行任务调度。 + ThreadPoolTaskScheduler taskScheduler = taskScheduler(); scheduledTaskRegistrar.setTaskScheduler(taskScheduler); } - /** - * 实现AsyncConfigurer接口的方法,用于返回异步任务执行的执行器对象。 - * 在本方法中,直接返回之前创建的线程池任务执行器对象,该对象将作为异步任务执行的执行器。 - * - * @return 返回异步任务执行的执行器对象,即之前创建的线程池任务执行器对象。 - */ @Override public Executor getAsyncExecutor() { return asyncExecutor(); } - /** - * 实现AsyncConfigurer接口的方法,用于定义异步未捕获异常的处理逻辑。 - * 在本方法中,当异步任务执行出现异常且未在方法内部被捕获时,会通过日志记录异常信息, - * 包括异常对象、执行的方法以及方法的参数等内容。 - * - * @param throwable 异步任务执行过程中抛出的异常对象。 - * @param method 执行异步任务的方法对象。 - * @param objects 执行异步任务的方法的参数对象数组。 - * @return 返回值无实际意义,这里主要是为了符合AsyncUncaughtExceptionHandler接口的定义。 - */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { - log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects); + log.error("异步任务执行出现异常, message {}, emthod {}, params {}", throwable, method, objects); }; } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java index 52d179c..cbb3f38 100644 --- a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java @@ -1,133 +1,127 @@ -// 定义包路径,用于存放Shiro配置类 package com.yf.exam.config; -import com.yf.exam.ability.shiro.CNFilterFactoryBean; // 自定义过滤器工厂类 -import com.yf.exam.ability.shiro.ShiroRealm; // 自定义Shiro领域类 -import com.yf.exam.ability.shiro.aop.JwtFilter; // JWT认证过滤器 -import lombok.extern.slf4j.Slf4j; // Lombok日志注解 -import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; // Shiro默认会话存储评估器 -import org.apache.shiro.mgt.DefaultSubjectDAO; // Shiro默认主体DAO -import org.apache.shiro.mgt.SecurityManager; // Shiro安全管理器 -import org.apache.shiro.spring.LifecycleBeanPostProcessor; // Spring生命周期Bean后处理器 -import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; // Shiro授权属性源顾问 -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类 -import org.apache.shiro.web.mgt.DefaultWebSecurityManager; // Shiro默认Web安全管理器 -import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; // Spring默认顾问自动代理创建器 -import org.springframework.context.annotation.Bean; // Spring Bean注解 -import org.springframework.context.annotation.Configuration; // Spring配置注解 -import org.springframework.context.annotation.DependsOn; // Spring依赖注解 - -import javax.servlet.Filter; // Servlet过滤器接口 -import java.util.HashMap; // Java哈希映射类 -import java.util.LinkedHashMap; // Java链接哈希映射类 -import java.util.Map; // Java映射类 +import com.yf.exam.ability.shiro.CNFilterFactoryBean; +import com.yf.exam.ability.shiro.ShiroRealm; +import com.yf.exam.ability.shiro.aop.JwtFilter; +import lombok.extern.slf4j.Slf4j; +import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; +import org.apache.shiro.mgt.DefaultSubjectDAO; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; + +import javax.servlet.Filter; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + /** * Shiro配置类 - * 用于配置和自定义Shiro框架的相关组件,包括安全管理器、过滤器工厂、Realm等。 * @author bool */ -@Slf4j // 使用Lombok注解,启用Log4j2日志 -@Configuration // 使用Spring注解,标记为配置类 +@Slf4j +@Configuration public class ShiroConfig { - /** - * 定义Shiro过滤器链 - * 方法用于配置Shiro过滤器链,定义哪些URL路径需要通过哪些过滤器。 - * - * @param securityManager Shiro安全管理器 - * @return ShiroFilterFactoryBean Shiro过滤器工厂Bean - */ - @Bean("shiroFilterFactoryBean") // 使用Spring注解,声明为Bean,并指定Bean名称 - public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { - CNFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); // 创建自定义过滤器工厂Bean - shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置安全管理器 - - // 定义过滤器链 - Map map = new LinkedHashMap<>(); // 创建拦截器映射 - - // 配置不需要认证的路径 - map.put("/exam/api/sys/user/login", "anon"); // 登录接口不需要认证 - map.put("/exam/api/sys/user/reg", "anon"); // 注册接口不需要认证 - map.put("/exam/api/sys/user/quick-reg", "anon"); // 快速注册接口不需要认证 - - // 配置其他不需要认证的静态资源路径 - map.put("/upload/file/**", "anon"); // 文件上传路径不需要认证 - map.put("/", "anon"); // 根路径不需要认证 - map.put("/v2/**", "anon"); // Swagger路径不需要认证 - map.put("/doc.html", "anon"); // Swagger文档不需要认证 - // ... 省略其他静态资源配置 - - // 添加自定义JWT过滤器 - Map filterMap = new HashMap<>(); // 创建过滤器映射 - filterMap.put("jwt", new JwtFilter()); // 添加JWT过滤器 - shiroFilterFactoryBean.setFilters(filterMap); // 设置过滤器 - - // 设置过滤器链定义 - map.put("/**", "jwt"); // 所有请求都需要通过JWT过滤器 - shiroFilterFactoryBean.setFilterChainDefinitionMap(map); // 设置过滤器链定义 - - return shiroFilterFactoryBean; // 返回Shiro过滤器工厂Bean - } - - /** - * 定义Shiro安全管理器 - * 方法用于配置Shiro安全管理器,设置自定义Realm和禁用Shiro的会话存储。 - * - * @param myRealm 自定义Shiro领域 - * @return DefaultWebSecurityManager Shiro安全管理器 - */ - @Bean("securityManager") // 使用Spring注解,声明为Bean,并指定Bean名称 - public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { - DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 创建默认Web安全管理器 - securityManager.setRealm(myRealm); // 设置自定义Realm - - // 禁用Shiro的会话存储 - DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); // 创建默认主体DAO - DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); // 创建默认会话存储评估器 - defaultSessionStorageEvaluator.setSessionStorageEnabled(false); // 禁用会话存储 - subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); // 设置会话存储评估器 - securityManager.setSubjectDAO(subjectDAO); // 设置主体DAO - - return securityManager; // 返回安全管理器 - } - - /** - * 定义注解支持 - * 方法用于添加注解支持,使得Shiro的注解可以正常工作。 - * - * @return DefaultAdvisorAutoProxyCreator 顾问自动代理创建器 - */ - @Bean // 使用Spring注解,声明为Bean - @DependsOn("lifecycleBeanPostProcessor") // 依赖于生命周期Bean后处理器 - public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { - DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // 创建顾问自动代理创建器 - defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); // 设置代理目标类 - return defaultAdvisorAutoProxyCreator; // 返回顾问自动代理创建器 - } - - /** - * 定义生命周期Bean后处理器 - * 方法用于定义Shiro的生命周期Bean后处理器,确保Shiro的组件能够按照预期的生命周期工作。 - * - * @return LifecycleBeanPostProcessor 生命周期Bean后处理器 - */ - @Bean // 使用Spring注解,声明为Bean - public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { - return new LifecycleBeanPostProcessor(); // 返回生命周期Bean后处理器 - } - - /** - * 定义授权属性源顾问 - * 方法用于定义Shiro的授权属性源顾问,用于处理Shiro注解中的权限控制。 - * - * @param securityManager Shiro安全管理器 - * @return AuthorizationAttributeSourceAdvisor 授权属性源顾问 - */ - @Bean // 使用Spring注解,声明为Bean - public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { - AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); // 创建授权属性源顾问 - advisor.setSecurityManager(securityManager); // 设置安全管理器 - return advisor; // 返回授权属性源顾问 - } -} \ No newline at end of file + /** + * Filter Chain定义说明 + * + * 1、一个URL可以配置多个Filter,使用逗号分隔 + * 2、当设置多个过滤器时,全部验证通过,才视为通过 + * 3、部分过滤器可指定参数,如perms,roles + */ + @Bean("shiroFilterFactoryBean") + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + ShiroFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); + shiroFilterFactoryBean.setSecurityManager(securityManager); + // 拦截器 + Map map = new LinkedHashMap<>(); + + // 需要排除的一些接口 + map.put("/exam/api/sys/user/login", "anon"); + map.put("/exam/api/sys/user/reg", "anon"); + map.put("/exam/api/sys/user/quick-reg", "anon"); + + // 获取网站基本信息 + map.put("/exam/api/sys/config/detail", "anon"); + + // 文件读取 + map.put("/upload/file/**", "anon"); + + map.put("/", "anon"); + map.put("/v2/**", "anon"); + map.put("/doc.html", "anon"); + map.put("/**/*.js", "anon"); + map.put("/**/*.css", "anon"); + map.put("/**/*.html", "anon"); + map.put("/**/*.svg", "anon"); + map.put("/**/*.pdf", "anon"); + map.put("/**/*.jpg", "anon"); + map.put("/**/*.png", "anon"); + map.put("/**/*.ico", "anon"); + + // 字体 + map.put("/**/*.ttf", "anon"); + map.put("/**/*.woff", "anon"); + map.put("/**/*.woff2", "anon"); + map.put("/druid/**", "anon"); + map.put("/swagger-ui.html", "anon"); + map.put("/swagger**/**", "anon"); + map.put("/webjars/**", "anon"); + + // 添加自己的过滤器并且取名为jwt + Map filterMap = new HashMap(1); + filterMap.put("jwt", new JwtFilter()); + shiroFilterFactoryBean.setFilters(filterMap); + map.put("/**", "jwt"); + + shiroFilterFactoryBean.setFilterChainDefinitionMap(map); + return shiroFilterFactoryBean; + } + + @Bean("securityManager") + public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + securityManager.setRealm(myRealm); + DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); + DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); + defaultSessionStorageEvaluator.setSessionStorageEnabled(false); + subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); + securityManager.setSubjectDAO(subjectDAO); + return securityManager; + } + + /** + * 下面的代码是添加注解支持 + * @return + */ + @Bean + @DependsOn("lifecycleBeanPostProcessor") + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { + DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); + defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); + defaultAdvisorAutoProxyCreator.setUsePrefix(true); + defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); + return defaultAdvisorAutoProxyCreator; + } + + @Bean + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); + advisor.setSecurityManager(securityManager); + return advisor; + } + +} diff --git a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java index 038caa6..d4208aa 100644 --- a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java @@ -1,164 +1,65 @@ -// 定义包路径,用于存放Swagger配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, -// 通常用于组织和管理与Swagger配置相关的代码。 package com.yf.exam.config; -// 导入用于启用Swagger Bootstrap UI的注解,Swagger Bootstrap UI是对Swagger UI的一种增强, -// 提供了更友好的界面展示和交互功能,通过该注解可以在项目中启用这一特性。 import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; - -// 导入Swagger用于标注API操作的注解,通过在方法上添加该注解,可以为该方法在Swagger文档中生成详细的操作描述信息, -// 包括方法的功能、参数、返回值等内容,方便开发者和使用者了解API的具体使用方式。 import io.swagger.annotations.ApiOperation; - -// 导入Spring框架中用于将类的属性与配置文件中的属性进行绑定的注解。 -// 通过指定prefix属性,可以将配置文件中以该前缀开头的属性值绑定到类的对应属性上, -// 在本类中用于绑定以"swagger"为前缀的配置属性。 import org.springframework.boot.context.properties.ConfigurationProperties; - -// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 -// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 -// 在本类中用于将examApi、securityScheme等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; - -// 导入Spring框架中用于标记一个类是配置类的注解。 -// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, -// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行Swagger相关的配置。 import org.springframework.context.annotation.Configuration; - -// 导入Swagger用于构建API信息的构建器类,通过该构建器可以方便地设置API的标题、描述、联系人、版本等信息, -// 在本类的apiInfo方法中用于创建并返回包含详细API信息的ApiInfo对象。 import springfox.documentation.builders.ApiInfoBuilder; - -// 导入Swagger用于选择路径的选择器类,通过该选择器可以指定哪些路径下的API需要被Swagger生成文档并展示, -// 在本类的examApi方法中用于选择符合特定路径模式的API。 import springfox.documentation.builders.PathSelectors; - -// 导入Swagger用于选择请求处理器(即包含API方法的类或接口)的选择器类, -// 通过该选择器可以指定哪些请求处理器中的方法需要被Swagger生成文档并展示, -// 在本类的examApi方法中用于选择带有ApiOperation注解的方法所在的请求处理器。 import springfox.documentation.builders.RequestHandlerSelectors; - -// 导入Swagger用于表示API信息的类,该类包含了API的标题、描述、联系人、版本等详细信息, -// 在本类的examApi方法中通过调用apiInfo方法获取该对象并设置到Docket中,以便在Swagger文档中展示这些信息。 import springfox.documentation.service.ApiInfo; - -// 导入Swagger用于表示API密钥的类,用于设置API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, -// 在本类的securityScheme方法中用于创建并返回一个ApiKey对象,用于设置API的授权方案。 import springfox.documentation.service.ApiKey; - -// 导入Swagger用于表示联系人信息的类,通过该类可以设置API的联系人姓名、联系方式、网址等信息, -// 在本类的apiInfo方法中用于创建并返回一个包含联系人信息的Contact对象,并设置到ApiInfo中。 import springfox.documentation.service.Contact; - -// 导入Swagger用于表示安全方案的类,它是一个通用的接口,用于定义不同类型的安全方案, -// 在本类的examApi方法中通过调用securityScheme方法获取具体的安全方案实现(如ApiKey)并设置到Docket中。 import springfox.documentation.service.SecurityScheme; - -// 导入Swagger用于表示文档类型的枚举类,目前主要有SWAGGER_2等类型, -// 在本类的examApi方法中用于指定创建Docket对象时所采用的文档类型为SWAGagger_2。 import springfox.documentation.spi.DocumentationType; - -// 导入Swagger用于生成Swagger文档的核心类,通过该类可以配置各种Swagger相关的设置,如API信息、路径选择、 -// 授权方案等,在本类的examApi方法中用于创建并配置Docket对象,以生成符合项目需求的Swagger文档。 import springfox.documentation.spring.web.plugins.Docket; - -// 导入用于启用Swagger 2的注解,通过在类上添加该注解,可以在项目中启用Swagger 2的功能, -// 使得Swagger能够为项目中的API生成详细的文档并提供交互界面,方便开发者和使用者查看和测试API。 import springfox.documentation.swagger2.annotations.EnableSwagger2; -// 导入Java标准库中的集合类,用于处理集合相关的操作,在本类的examApi方法中用于创建一个包含单个安全方案的列表, -// 以便将安全方案设置到Docket对象中。 import java.util.Collections; /** - * Swagger配置类,主要功能是配置Swagger在项目中的相关设置, - * 包括启用Swagger 2和Swagger Bootstrap UI功能,绑定以"swagger"为前缀的配置属性, - * 创建Docket对象并设置其API信息、分组名称、选择需要生成文档的API方法和路径、设置安全方案等, - * 以生成详细的API文档并提供友好的交互界面,方便对项目中的API进行查看、测试和使用。 + * Swagger配置 * @author bool * @date 2020/8/19 20:53 */ -@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 -@EnableSwagger2 // 使用该注解启用Swagger 2功能,使得Swagger能够为项目中的API生成详细的文档并提供交互界面。 -@EnableSwaggerBootstrapUI // 使用该注解启用Swagger Bootstrap UI功能,提供更友好的界面展示和交互功能。 -@ConfigurationProperties(prefix = "swagger") // 使用该注解将类的属性与以"swagger"为前缀的配置文件中的属性进行绑定, - // 以便在类中可以方便地使用这些配置属性来定制Swagger的设置。 - +@Configuration +@EnableSwagger2 +@EnableSwaggerBootstrapUI +@ConfigurationProperties(prefix = "swagger") public class SwaggerConfig { - /** - * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 - * 该方法用于创建并返回一个Docket对象,该对象是Swagger生成文档的核心组件, - * 通过对其进行一系列设置,可以定制生成的API文档的内容和展示方式。 - * - * @return 返回一个Docket对象,该对象经过了相关设置,包括API信息、分组名称、选择的API方法和路径、安全方案等。 - */ - @Bean // 将该方法返回的Docket对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 - public Docket examApi() { - return new Docket(DocumentationType.SWAGGER_2) // 创建一个新的Docket对象,并指定文档类型为SWAGGER_2, - // 这是目前较为常用的Swagger文档类型,用于生成详细的API文档。 - - .apiInfo(apiInfo()) // 调用apiInfo方法获取包含详细API信息的ApiInfo对象,并设置到Docket对象中, - // 以便在生成的Swagger文档中展示API的标题、描述、联系人、版本等信息。 - - .groupName("考试模块接口") // 设置Docket对象的分组名称为"考试模块接口", - // 这样可以将项目中的API按照不同的模块或功能进行分组展示,方便查看和管理。 - - .select() // 开始选择需要生成文档的API,通过一系列选择器来指定具体的选择条件。 - - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // 使用RequestHandlerSelectors的withMethodAnnotation方法选择带有ApiOperation注解的方法, - // 即只选择那些在方法上标注了ApiOperation注解的API方法进行文档生成, - // 这样可以确保只生成我们希望展示的重要API的文档。 - .paths(PathSelectors.ant("/exam/api/**")) // 使用PathSelectors的ant方法选择符合特定路径模式的API, - // 这里选择的路径模式是"/exam/api/**",表示只选择以"/exam/api/"开头的任意路径下的API进行文档生成, - // 进一步限定了生成文档的API范围,使其更加聚焦于项目中的特定部分(如考试模块相关的API)。 - - .build() // 完成上述选择条件的设置后,调用build方法构建Docket对象,使其生效并包含我们所设置的所有选择条件和信息。 - - .securitySchemes(Collections.singletonList(securityScheme())) // 创建一个包含单个安全方案的列表, - // 通过调用securityScheme方法获取具体的安全方案对象(如ApiKey), - // 并将其添加到列表中,然后设置到Docket对象中, - // 以便在Swagger文档中展示API的授权相关信息,如需要在请求头中传递的授权密钥等。 - - ; + @Bean + public Docket examApi() { + return new Docket(DocumentationType.SWAGGER_2) + .apiInfo(apiInfo()) + .groupName("考试模块接口") + .select() + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) + .paths(PathSelectors.ant("/exam/api/**")) + .build() + .securitySchemes(Collections.singletonList(securityScheme())); } - /** - * 用于创建并返回一个包含详细API信息的ApiInfo对象的方法。 - * 通过ApiInfoBuilder类可以方便地设置API的标题、描述、联系人、版本等信息。 - * - * @return 返回一个ApiInfo对象,该对象包含了API的标题、描述、联系人、版本等详细信息, - * 用于设置到Docket对象中,以便在Swagger文档中展示。 - */ - private ApiInfo apiInfo() { - return new ApiInfoBuilder().title("考试系统接口") // 使用ApiInfoBuilder的title方法设置API的标题为"考试系统接口", - // 这将在Swagger文档的顶部显著位置展示,让使用者快速了解该API所属的系统。 - - .description("考试系统接口") // 使用ApiInfoBuilder的description方法设置API的描述为"考试系统接口", - // 可以在这里详细描述API的功能、用途、特点等信息,方便使用者进一步了解API的具体情况。 - .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) // 使用ApiInfoBuilder的contact方法创建一个包含联系人信息的Contact对象, - // 并设置联系人姓名为"Van",网址为"https://exam.yfhl.net",邮箱为"18365918@qq.com", - // 这些信息将在Swagger文档中展示,方便使用者在有问题时能够联系到相关人员。 - .version("1.0.0") // 使用ApiInfoBuilder的version方法设置API的版本号为"1.0.0", - // 让使用者了解该API的版本情况,以便在不同版本之间进行对比和选择。 - - .build(); // 完成上述各项信息的设置后,调用build方法构建ApiInfo对象,使其生效并包含我们所设置的所有信息。 + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("考试系统接口") + .description("考试系统接口") + .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) + .version("1.0.0") + .build(); } + /** - * 用于创建并返回一个表示API密钥的ApiKey对象的方法,该对象用于设置API的授权方案。 - * - * @return 返回一个ApiKey对象,该对象定义了API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, - * 用于设置到Docket对象中,以便在Swagger文档中展示API的授权要求。 + * 授权头部 + * @return */ - @Bean // 将该方法返回的SecurityScheme对象(实际为ApiKey类型)声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 + @Bean SecurityScheme securityScheme() { - return new ApiKey("token", "token", "header"); // 创建一个新的ApiKey对象, - // 第一个参数"token"表示授权的键名,即客户端在请求时需要在指定位置(这里是请求头)传递的键名; - // 第二个参数"token"表示授权的值,这里简单设置为与键名相同,实际应用中可能是根据用户登录等情况生成的授权令牌; - // 第三个参数"header"表示授权的值应该放置的位置,这里指定为在请求头中传递。 + return new ApiKey("token", "token", "header"); } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java index 6adeb13..e5583f2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java @@ -1,144 +1,151 @@ -package com.yf.exam.modules.exam.controller; // 定义包名,控制器所在的包路径 - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页接口 -import com.yf.exam.core.api.ApiRest; // 导入自定义的API响应类 -import com.yf.exam.core.api.controller.BaseController; // 导入基控制器类 -import com.yf.exam.core.api.dto.BaseIdReqDTO; // 导入基础ID请求数据传输对象 -import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入基础IDs请求数据传输对象 -import com.yf.exam.core.api.dto.BaseStateReqDTO; // 导入基础状态请求数据传输对象 -import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入考试审核响应DTO -import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 -import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 -import io.swagger.annotations.Api; // 导入Swagger注解 -import io.swagger.annotations.ApiOperation; // 导入Swagger操作注解 -import org.apache.shiro.authz.annotation.RequiresRoles; // 导入Shiro权限注解 -import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 -import org.springframework.web.bind.annotation.RequestBody; // 导入Spring MVC的请求体注解 -import org.springframework.web.bind.annotation.RequestMapping; // 导入Spring MVC的请求映射注解 -import org.springframework.web.bind.annotation.RequestMethod; // 导入Spring MVC的请求方法注解 -import org.springframework.web.bind.annotation.RestController; // 导入Spring MVC的控制器注解 - -import java.util.Date; // 导入Java的日期类 +package com.yf.exam.modules.exam.controller; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdReqDTO; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.BaseStateReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.exam.dto.ExamDTO; +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; +import com.yf.exam.modules.exam.entity.Exam; +import com.yf.exam.modules.exam.service.ExamService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; /** - *

- * 考试控制器,处理与考试相关的请求 - *

- * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Api(tags={"考试"}) // Swagger注解,定义API的标签 -@RestController // Spring MVC注解,声明这是一个REST控制器 -@RequestMapping("/exam/api/exam/exam") // Spring MVC注解,定义请求的基础路径 -public class ExamController extends BaseController { // 声明控制器类,继承自基控制器 +*

+* 考试控制器 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Api(tags={"考试"}) +@RestController +@RequestMapping("/exam/api/exam/exam") +public class ExamController extends BaseController { @Autowired - private ExamService baseService; // 自动注入考试服务 + private ExamService baseService; /** - * 添加或修改考试信息 - * @param reqDTO 考试保存请求数据传输对象 - * @return ApiRest 返回操作结果 - */ - @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) - @ApiOperation(value = "添加或修改") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/save", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { // 定义添加或修改考试的方法 - // 复制参数并保存 - baseService.save(reqDTO); // 调用服务层保存考试信息 - return super.success(); // 返回成功响应 + * 添加或修改 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "添加或修改") + @RequestMapping(value = "/save", method = { RequestMethod.POST}) + public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { + //复制参数 + baseService.save(reqDTO); + return super.success(); } /** - * 批量删除考试 - * @param reqDTO 包含要删除的考试ID列表 - * @return ApiRest 返回操作结果 - */ - @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) - @ApiOperation(value = "批量删除") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { // 定义批量删除考试的方法 - // 根据ID删除考试 - baseService.removeByIds(reqDTO.getIds()); // 调用服务层根据ID列表删除考试 - return super.success(); // 返回成功响应 + * 批量删除 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { + //根据ID删除 + baseService.removeByIds(reqDTO.getIds()); + return super.success(); } /** - * 查找考试详情 - * @param reqDTO 包含考试ID - * @return ApiRest 返回考试详情 - */ - @ApiOperation(value = "查找详情") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { // 定义查找考试详情的方法 - ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); // 调用服务层查找考试详情 - return super.success(dto); // 返回成功响应和考试详情 + * 查找详情 + * @param reqDTO + * @return + */ + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { + ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); + return super.success(dto); } /** - * 更新考试状态 - * @param reqDTO 包含考试ID和新状态 - * @return ApiRest 返回操作结果 + * 查找详情 + * @param reqDTO + * @return */ - @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) - @ApiOperation(value = "更新考试状态") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/state", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { // 定义更新考试状态的方法 - // 创建查询条件 + @RequiresRoles("sa") + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/state", method = { RequestMethod.POST}) + public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { + QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().in(Exam::getId, reqDTO.getIds()); // 构造查询条件,查询指定ID的考试 - Exam exam = new Exam(); // 创建考试实体 - exam.setState(reqDTO.getState()); // 设置新状态 - exam.setUpdateTime(new Date()); // 设置更新时间为当前时间 + wrapper.lambda().in(Exam::getId, reqDTO.getIds()); + Exam exam = new Exam(); + exam.setState(reqDTO.getState()); + exam.setUpdateTime(new Date()); - baseService.update(exam, wrapper); // 调用服务层更新考试状态 - return super.success(); // 返回成功响应 + baseService.update(exam, wrapper); + return super.success(); } + /** - * 分页查找考试 - * @param reqDTO 分页请求数据传输对象 - * @return ApiRest> 返回分页考试列表 + * 分页查找 + * @param reqDTO + * @return */ - @ApiOperation(value = "考试视角") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 - // 分页查询并转换 - IPage page = baseService.onlinePaging(reqDTO); // 调用服务层进行分页查询 - return super.success(page); // 返回成功响应和分页结果 + @ApiOperation(value = "考试视角") + @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.onlinePaging(reqDTO); + return super.success(page); } /** - * 分页查找考试 - * @param reqDTO 分页请求数据传输对象 - * @return ApiRest> 返回分页考试列表 - */ - @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) - @ApiOperation(value = "分页查找") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 - // 分页查询并转换 - IPage page = baseService.paging(reqDTO); // 调用服务层进行分页查询 - return super.success(page); // 返回成功响应和分页结果 + * 分页查找 + * @param reqDTO + * @return + */ + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); } + /** - * 分页查找待阅试卷 - * @param reqDTO 分页请求数据传输对象 - * @return ApiRest> 返回分页待阅试卷列表 + * 分页查找 + * @param reqDTO + * @return */ - @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) - @ApiOperation(value = "待阅试卷") // Swagger注解,定义操作的描述 - @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 - public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找待阅试卷的方法 - // 分页查询并转换 - IPage page = baseService.reviewPaging(reqDTO); // 调用服务层进行分页查询 - return super.success(page); // 返回成功响应和分页结果 + @RequiresRoles("sa") + @ApiOperation(value = "待阅试卷") + @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) + public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { + //分页查询并转换 + IPage page = baseService.reviewPaging(reqDTO); + return super.success(page); } + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java index 8f9b69e..90f86f1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java @@ -1,93 +1,101 @@ -package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 +package com.yf.exam.modules.exam.dto; -import com.fasterxml.jackson.annotation.JsonFormat; // 导入Jackson库的注解,用于格式化日期 -import com.yf.exam.modules.paper.enums.ExamState; // 导入考试状态枚举 -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import org.springframework.format.annotation.DateTimeFormat; // 导入Spring的日期格式化注解 +import com.fasterxml.jackson.annotation.JsonFormat; +import com.yf.exam.modules.paper.enums.ExamState; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; -import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 -import java.util.Date; // 导入Java的日期类 +import java.io.Serializable; +import java.util.Date; /** - *

- * 考试数据传输类,封装考试的基本信息 - *

- * 此类用于封装考试的基本信息,以便在应用程序中传输。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="考试", description="考试") // Swagger注解,描述这个类的用途 -public class ExamDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 +*

+* 考试数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="考试", description="考试") +public class ExamDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String id; // 考试ID + private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "考试名称", required=true) // Swagger注解,描述字段的用途和是否必填 - private String title; // 考试名称 - @ApiModelProperty(value = "考试描述", required=true) // Swagger注解,描述字段的用途和是否必填 - private String content; // 考试描述 + @ApiModelProperty(value = "ID", required=true) + private String id; - @ApiModelProperty(value = "1公开2部门3定员", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer openType; // 开放类型,1表示公开,2表示部门,3表示定员 + @ApiModelProperty(value = "考试名称", required=true) + private String title; - @ApiModelProperty(value = "考试状态", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer state; // 考试状态 + @ApiModelProperty(value = "考试描述", required=true) + private String content; - @ApiModelProperty(value = "是否限时", required=true) // Swagger注解,描述字段的用途和是否必填 - private Boolean timeLimit; // 是否限时 + @ApiModelProperty(value = "1公开2部门3定员", required=true) + private Integer openType; - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 - @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 - @ApiModelProperty(value = "开始时间", required=true) // Swagger注解,描述字段的用途和是否必填 - private Date startTime; // 考试开始时间 + @ApiModelProperty(value = "考试状态", required=true) + private Integer state; - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 - @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 - @ApiModelProperty(value = "结束时间", required=true) // Swagger注解,描述字段的用途和是否必填 - private Date endTime; // 考试结束时间 + @ApiModelProperty(value = "是否限时", required=true) + private Boolean timeLimit; - @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述字段的用途和是否必填 - private Date createTime; // 创建时间 + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty(value = "开始时间", required=true) + private Date startTime; - @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述字段的用途和是否必填 - private Date updateTime; // 更新时间 + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") + @DateTimeFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty(value = "结束时间", required=true) + private Date endTime; + + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; + + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "总分数", required=true) + private Integer totalScore; + + @ApiModelProperty(value = "总时长(分钟)", required=true) + private Integer totalTime; + + @ApiModelProperty(value = "及格分数", required=true) + private Integer qualifyScore; - @ApiModelProperty(value = "总分数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer totalScore; // 总分数 - @ApiModelProperty(value = "总时长(分钟)", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer totalTime; // 总时长(分钟) - @ApiModelProperty(value = "及格分数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer qualifyScore; // 及格分数 /** - * 判断考试状态 - * 根据当前时间和考试的限时设置,返回考试的实际状态。 - * - * @return 当前考试状态 + * 是否结束 + * @return */ - public Integer getState() { - if (this.timeLimit != null && this.timeLimit) { - if (System.currentTimeMillis() < startTime.getTime()) { - return ExamState.READY_START; // 如果当前时间小于开始时间,状态为准备开始 + public Integer getState(){ + + if(this.timeLimit!=null && this.timeLimit){ + + if(System.currentTimeMillis() < startTime.getTime() ){ + return ExamState.READY_START; } - if (System.currentTimeMillis() > endTime.getTime()) { - return ExamState.OVERDUE; // 如果当前时间大于结束时间,状态为已过期 + + if(System.currentTimeMillis() > endTime.getTime()){ + return ExamState.OVERDUE; } - if (System.currentTimeMillis() > startTime.getTime() + + if(System.currentTimeMillis() > startTime.getTime() && System.currentTimeMillis() < endTime.getTime() - && !ExamState.DISABLED.equals(this.state)) { - return ExamState.ENABLE; // 如果当前时间在开始时间和结束时间之间,并且状态不是禁用,状态为正在进行 + && !ExamState.DISABLED.equals(this.state)){ + return ExamState.ENABLE; } + } - return this.state; // 如果不满足上述条件,返回当前状态 + + return this.state; } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java index 7710955..d0e54b7 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java @@ -1,32 +1,33 @@ -package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 +package com.yf.exam.modules.exam.dto; -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 +import java.io.Serializable; /** - *

- * 考试部门数据传输类,封装考试部门相关信息 - *

- * 此类用于封装与考试部门相关的数据,以便在应用程序中传输。 - * - * @author 聪明笨狗 - * @since 2020-09-03 17:24 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="考试部门", description="考试部门") // Swagger注解,描述这个类的用途 -public class ExamDepartDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 +*

+* 考试部门数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Data +@ApiModel(value="考试部门", description="考试部门") +public class ExamDepartDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - - @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String id; // 唯一标识符,标识考试部门记录的ID - - @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String examId; // 考试的唯一标识符,关联到具体的考试 - - @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String departId; // 部门的唯一标识符,关联到具体的部门 -} \ No newline at end of file + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "部门ID", required=true) + private String departId; + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java index 5cbc8a4..7244e9a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java @@ -1,50 +1,51 @@ -package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 +package com.yf.exam.modules.exam.dto; -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 +import java.io.Serializable; /** - *

- * 考试题库数据传输类,封装考试题库相关信息 - *

- * 此类用于封装考试题库的数据,以便在应用程序中传输。 - * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="考试题库", description="考试题库") // Swagger注解,描述这个类的用途 -public class ExamRepoDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - - @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String id; // 题库ID,唯一标识符 - - @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String examId; // 关联的考试ID,标识与哪个考试相关联 - - @ApiModelProperty(value = "题库ID", required=true) // Swagger注解,描述字段的用途和是否必填 - private String repoId; // 题库ID,标识具体的题库 - - @ApiModelProperty(value = "单选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer radioCount; // 单选题数量,表示题库中单选题的总数 - - @ApiModelProperty(value = "单选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer radioScore; // 单选题分数,表示单选题的总分 - - @ApiModelProperty(value = "多选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer multiCount; // 多选题数量,表示题库中多选题的总数 - - @ApiModelProperty(value = "多选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer multiScore; // 多选题分数,表示多选题的总分 - - @ApiModelProperty(value = "判断题数量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer judgeCount; // 判断题数量,表示题库中判断题的总数 - - @ApiModelProperty(value = "判断题分数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer judgeScore; // 判断题分数,表示判断题的总分 -} \ No newline at end of file +*

+* 考试题库数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@ApiModel(value="考试题库", description="考试题库") +public class ExamRepoDTO implements Serializable { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "ID", required=true) + private String id; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; + + @ApiModelProperty(value = "题库ID", required=true) + private String repoId; + + @ApiModelProperty(value = "单选题数量", required=true) + private Integer radioCount; + + @ApiModelProperty(value = "单选题分数", required=true) + private Integer radioScore; + + @ApiModelProperty(value = "多选题数量", required=true) + private Integer multiCount; + + @ApiModelProperty(value = "多选题分数", required=true) + private Integer multiScore; + + @ApiModelProperty(value = "判断题数量", required=true) + private Integer judgeCount; + + @ApiModelProperty(value = "判断题分数", required=true) + private Integer judgeScore; + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java index e1887c3..a566fec 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java @@ -1,30 +1,32 @@ -package com.yf.exam.modules.exam.dto.ext; // 定义包名,DTO扩展类所在的包路径 +package com.yf.exam.modules.exam.dto.ext; -import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库数据传输类 -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import com.yf.exam.modules.exam.dto.ExamRepoDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; /** - *

- * 考试题库数据传输类的扩展,包含额外的题库信息 - *

- * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") // Swagger注解,描述这个类的用途 -public class ExamRepoExtDTO extends ExamRepoDTO { // 声明类,继承自ExamRepoDTO +*

+* 考试题库数据传输类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") +public class ExamRepoExtDTO extends ExamRepoDTO { - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 + private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "单选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer totalRadio; // 单选题总量 - - @ApiModelProperty(value = "多选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer totalMulti; // 多选题总量 - - @ApiModelProperty(value = "判断题总量", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer totalJudge; // 判断题总量 + + @ApiModelProperty(value = "单选题总量", required=true) + private Integer totalRadio; + + @ApiModelProperty(value = "多选题总量", required=true) + private Integer totalMulti; + + @ApiModelProperty(value = "判断题总量", required=true) + private Integer totalJudge; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java index aa62266..5c1a95b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java @@ -1,30 +1,32 @@ -package com.yf.exam.modules.exam.dto.request; // 定义包名,请求DTO类所在的包路径 +package com.yf.exam.modules.exam.dto.request; -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO类 -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import com.yf.exam.modules.exam.dto.ExamDTO; +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.util.List; // 导入Java的List接口,用于定义列表类型的属性 +import java.util.List; /** - *

- * 考试保存请求类,封装考试保存请求的相关信息 - *

- * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="考试保存请求类", description="考试保存请求类") // Swagger注解,描述这个类的用途 -public class ExamSaveReqDTO extends ExamDTO { // 声明类,继承自ExamDTO - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 - - @ApiModelProperty(value = "题库列表", required=true) // Swagger注解,描述字段的用途和是否必填 - private List repoList; // 题库列表,存储与考试相关的题库信息 - - @ApiModelProperty(value = "考试部门列表", required=true) // Swagger注解,描述字段的用途和是否必填 - private List departIds; // 考试部门ID列表,存储与考试相关的部门ID -} \ No newline at end of file +*

+* 考试保存请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="考试保存请求类", description="考试保存请求类") +public class ExamSaveReqDTO extends ExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题库列表", required=true) + private List repoList; + + @ApiModelProperty(value = "考试部门列表", required=true) + private List departIds; + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java index ec344db..edbc5ce 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java @@ -1,21 +1,22 @@ -package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 +package com.yf.exam.modules.exam.dto.response; -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import com.yf.exam.modules.exam.dto.ExamDTO; +import io.swagger.annotations.ApiModel; +import lombok.Data; /** - *

- * 在线考试分页响应类,封装在线考试的分页响应信息 - *

- * 此类用于封装在线考试相关的分页数据,提供给前端展示。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") // Swagger注解,描述这个类的用途 -public class ExamOnlineRespDTO extends ExamDTO { // 声明类,继承自ExamDTO +*

+* 考试分页响应类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") +public class ExamOnlineRespDTO extends ExamDTO { - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 -} \ No newline at end of file + private static final long serialVersionUID = 1L; + + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java index 68d4236..7d9ad36 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java @@ -1,28 +1,31 @@ -package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 +package com.yf.exam.modules.exam.dto.response; -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 -import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 -import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import com.yf.exam.modules.exam.dto.ExamDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; /** - *

- * 阅卷分页响应类,封装阅卷相关的分页响应信息 - *

- * 此类用于封装阅卷相关的分页数据,提供给前端展示。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") // Swagger注解,描述这个类的用途 -public class ExamReviewRespDTO extends ExamDTO { // 声明类,继承自ExamDTO - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - - @ApiModelProperty(value = "考试人数", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer examUser; // 考试人数,表示参与考试的用户总数 - - @ApiModelProperty(value = "待阅试卷", required=true) // Swagger注解,描述字段的用途和是否必填 - private Integer unreadPaper; // 待阅试卷数量,表示尚未被阅卷的试卷数量 -} \ No newline at end of file +*

+* 考试分页响应类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") +public class ExamReviewRespDTO extends ExamDTO { + + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "考试人数", required=true) + private Integer examUser; + + @ApiModelProperty(value = "待阅试卷", required=true) + private Integer unreadPaper; + + + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java index cd2d284..e198c69 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java @@ -1,61 +1,100 @@ -package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 +package com.yf.exam.modules.exam.entity; -import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 -import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 -import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 -import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 -import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.util.Date; // 导入Java的日期类 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; +import java.util.Date; /** - *

- * 考试实体类,封装考试的基本信息 - *

- * 此类用于数据库操作,映射考试表的字段。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@TableName("el_exam") // MyBatis Plus注解,指定这个实体类对应的数据库表名 -public class Exam extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 - - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID - private String id; // 考试ID,唯一标识符 - - private String title; // 考试名称,描述考试的标题 - - private String content; // 考试描述,详细描述考试的内容 - - @TableField("open_type") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Integer openType; // 开放类型,表示考试的开放范围(1公开,2部门,3定员) - - private Integer state; // 考试状态,表示考试的当前状态(如:未开始、进行中、已结束) - - @TableField("time_limit") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Boolean timeLimit; // 是否限时,表示考试是否有时间限制 - - @TableField("start_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Date startTime; // 开始时间,表示考试的开始时间 - - @TableField("end_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Date endTime; // 结束时间,表示考试的结束时间 - - @TableField("create_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Date createTime; // 创建时间,表示记录的创建时间 - - @TableField("update_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Date updateTime; // 更新时间,表示记录的最后更新时间 - - @TableField("total_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Integer totalScore; // 总分数,表示考试的总分 - - @TableField("total_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Integer totalTime; // 总时长(分钟),表示考试的总时长 - - @TableField("qualify_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 - private Integer qualifyScore; // 及格分数,表示考试的及格分数线 -} \ No newline at end of file +*

+* 考试实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Data +@TableName("el_exam") +public class Exam extends Model { + + private static final long serialVersionUID = 1L; + + /** + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; + + /** + * 考试名称 + */ + private String title; + + /** + * 考试描述 + */ + private String content; + + /** + * 1公开2部门3定员 + */ + @TableField("open_type") + private Integer openType; + + /** + * 考试状态 + */ + private Integer state; + + /** + * 是否限时 + */ + @TableField("time_limit") + private Boolean timeLimit; + + /** + * 开始时间 + */ + @TableField("start_time") + private Date startTime; + + /** + * 结束时间 + */ + @TableField("end_time") + private Date endTime; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 总分数 + */ + @TableField("total_score") + private Integer totalScore; + + /** + * 总时长(分钟) + */ + @TableField("total_time") + private Integer totalTime; + + /** + * 及格分数 + */ + @TableField("qualify_score") + private Integer qualifyScore; + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java index b39d71c..19a4238 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java @@ -1,47 +1,42 @@ -package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 +package com.yf.exam.modules.exam.entity; -import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 -import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 -import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 -import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 -import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 - -import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; /** - *

- * 考试部门实体类,封装考试部门的基本信息 - *

- * 此类用于数据库操作,映射考试部门表的字段。 - * - * @author 聪明笨狗 - * @since 2020-09-03 17:24 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@TableName("el_exam_depart") // MyBatis Plus注解,指定这个实体类对应的数据库表名 -public class ExamDepart extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 +*

+* 考试部门实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Data +@TableName("el_exam_depart") +public class ExamDepart extends Model { + private static final long serialVersionUID = 1L; + /** - * ID - * 唯一标识符,用于标识考试部门记录。 - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) private String id; /** - * 考试ID - * 关联的考试ID,标识这个部门所属的考试。 - */ - @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 考试ID + */ + @TableField("exam_id") private String examId; /** - * 部门ID - * 关联的部门ID,标识参与考试的部门。 - */ - @TableField("depart_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 部门ID + */ + @TableField("depart_id") private String departId; -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java index 5249056..3884051 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java @@ -1,87 +1,78 @@ -package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 +package com.yf.exam.modules.exam.entity; -import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 -import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 -import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 -import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 -import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 -import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; /** - *

- * 考试题库实体类,封装考试题库的基本信息 - *

- * 此类用于数据库操作,映射考试题库表的字段。 - * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 -@TableName("el_exam_repo") // MyBatis Plus注解,指定这个实体类对应的数据库表名 -public class ExamRepo extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 - - private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 +*

+* 考试题库实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Data +@TableName("el_exam_repo") +public class ExamRepo extends Model { + private static final long serialVersionUID = 1L; + /** - * ID - * 唯一标识符,用于标识考试题库记录。 - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) private String id; /** - * 考试ID - * 关联的考试ID,标识这个题库所属的考试。 - */ - @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 考试ID + */ + @TableField("exam_id") private String examId; /** - * 题库ID - * 关联的题库ID,标识具体的题库。 - */ - @TableField("repo_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 题库ID + */ + @TableField("repo_id") private String repoId; /** - * 单选题数量 - * 题库中包含的单选题数量。 - */ - @TableField("radio_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 单选题数量 + */ + @TableField("radio_count") private Integer radioCount; /** - * 单选题分数 - * 单选题的总分。 - */ - @TableField("radio_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 单选题分数 + */ + @TableField("radio_score") private Integer radioScore; /** - * 多选题数量 - * 题库中包含的多选题数量。 - */ - @TableField("multi_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 多选题数量 + */ + @TableField("multi_count") private Integer multiCount; /** - * 多选题分数 - * 多选题的总分。 - */ - @TableField("multi_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 多选题分数 + */ + @TableField("multi_score") private Integer multiScore; /** - * 判断题数量 - * 题库中包含的判断题数量。 - */ - @TableField("judge_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 判断题数量 + */ + @TableField("judge_count") private Integer judgeCount; /** - * 判断题分数 - * 判断题的总分。 - */ - @TableField("judge_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + * 判断题分数 + */ + @TableField("judge_score") private Integer judgeScore; -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java index 60c30d2..0c1f39a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java @@ -1,17 +1,15 @@ -package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 -import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 +package com.yf.exam.modules.exam.mapper; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.exam.entity.ExamDepart; /** - *

- * 考试部门Mapper,提供考试部门的数据库操作接口 - *

- * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试部门表的数据库操作。 - * - * @author 聪明笨狗 - * @since 2020-09-03 17:24 - */ -public interface ExamDepartMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamDepart - // 继承BaseMapper,提供基本的CRUD操作(创建、读取、更新、删除) -} \ No newline at end of file +*

+* 考试部门Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +public interface ExamDepartMapper extends BaseMapper { + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java index f4908e8..1ce4504 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java @@ -1,52 +1,45 @@ -package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 +package com.yf.exam.modules.exam.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷分页响应DTO -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试分页响应DTO -import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 -import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.exam.dto.ExamDTO; +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; +import com.yf.exam.modules.exam.entity.Exam; +import org.apache.ibatis.annotations.Param; /** - *

- * 考试Mapper,提供考试的数据库操作接口 - *

- * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试表的数据库操作。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -public interface ExamMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为Exam +*

+* 考试Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +public interface ExamMapper extends BaseMapper { /** * 查找分页内容 - * 方法用于根据给定的分页对象和查询条件,查询考试数据的分页结果。 - * - * @param page 分页对象,包含分页信息,如当前页码和每页大小 - * @param query 查询条件,封装了考试查询的相关信息 - * @return IPage 返回包含考试DTO的分页结果 + * @param page + * @param query + * @return */ IPage paging(Page page, @Param("query") ExamDTO query); /** * 查找分页内容 - * 方法用于根据给定的分页对象和查询条件,查询阅卷数据的分页结果。 - * - * @param page 分页对象,包含分页信息,如当前页码和每页大小 - * @param query 查询条件,封装了考试查询的相关信息 - * @return IPage 返回包含阅卷分页响应DTO的分页结果 + * @param page + * @param query + * @return */ IPage reviewPaging(Page page, @Param("query") ExamDTO query); /** * 在线考试分页响应类-考生视角 - * 方法用于根据给定的分页对象和查询条件,查询在线考试数据的分页结果,从考生视角。 - * - * @param page 分页对象,包含分页信息,如当前页码和每页大小 - * @param query 查询条件,封装了考试查询的相关信息 - * @return IPage 返回包含在线考试分页响应DTO的分页结果 + * @param page + * @param query + * @return */ IPage online(Page page, @Param("query") ExamDTO query); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java index 69900d2..83407df 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java @@ -1,29 +1,26 @@ -package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 +package com.yf.exam.modules.exam.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO -import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 -import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +import com.yf.exam.modules.exam.entity.ExamRepo; +import org.apache.ibatis.annotations.Param; -import java.util.List; // 导入Java的List接口 +import java.util.List; /** - *

- * 考试题库Mapper,提供考试题库的数据库操作接口 - *

- * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试题库表的数据库操作。 - * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -public interface ExamRepoMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamRepo +*

+* 考试题库Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +public interface ExamRepoMapper extends BaseMapper { /** * 查找考试题库列表 - * 方法用于根据给定的考试ID,查询关联的考试题库列表,返回扩展的DTO对象。 - * - * @param examId 考试ID,用于指定查询哪个考试的题库列表 - * @return List 返回包含考试题库扩展信息的列表 + * @param examId + * @return */ - List listByExam(@Param("examId") String examId); // 使用MyBatis的@Param注解来指定方法参数的名称 -} \ No newline at end of file + List listByExam(@Param("examId") String examId); +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java index 068a6dc..301c010 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java @@ -1,36 +1,32 @@ -package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 +package com.yf.exam.modules.exam.service; -import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 -import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.modules.exam.entity.ExamDepart; -import java.util.List; // 导入Java的List接口 +import java.util.List; /** - *

- * 考试部门业务类,提供考试部门的业务逻辑 - *

- * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试部门相关的业务操作。 - * - * @author 聪明笨狗 - * @since 2020-09-03 17:24 - */ -public interface ExamDepartService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamDepart +*

+* 考试部门业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +public interface ExamDepartService extends IService { /** - * 保存全部部门信息 - * 方法用于根据给定的考试ID和部门ID列表,保存考试与部门的关联关系。 - * - * @param examId 考试ID,标识要关联的考试 - * @param departs 部门ID列表,包含要关联的部门ID + * 保存全部 + * @param examId + * @param departs */ void saveAll(String examId, List departs); + /** * 根据考试查找对应的部门 - * 方法用于根据给定的考试ID,查询与之关联的部门ID列表。 - * - * @param examId 考试ID,用于指定查询哪个考试的部门 - * @return List 返回部门ID列表,包含所有与考试关联的部门ID + * @param examId + * @return */ List listByExam(String examId); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java index 5758185..78b4ec1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java @@ -1,45 +1,40 @@ -package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 +package com.yf.exam.modules.exam.service; -import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO -import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +import com.yf.exam.modules.exam.entity.ExamRepo; -import java.util.List; // 导入Java的List接口 +import java.util.List; /** - *

- * 考试题库业务类,提供考试题库的业务逻辑 - *

- * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试题库相关的业务操作。 - * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -public interface ExamRepoService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamRepo +*

+* 考试题库业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +public interface ExamRepoService extends IService { + /** - * 保存全部题库信息 - * 方法用于根据给定的考试ID和题库列表,保存考试与题库的关联关系。 - * - * @param examId 考试ID,标识要关联的考试 - * @param list 题库列表,包含要关联的题库信息 + * 保存全部 + * @param examId + * @param list */ void saveAll(String examId, List list); /** * 查找考试题库列表 - * 方法用于根据给定的考试ID,查询与之关联的题库列表。 - * - * @param examId 考试ID,用于指定查询哪个考试的题库 - * @return List 返回题库列表,包含所有与考试关联的题库信息 + * @param examId + * @return */ List listByExam(String examId); /** * 清理脏数据 - * 方法用于清除与指定考试ID关联的题库数据,用于数据清理或重置场景。 - * - * @param examId 考试ID,用于指定要清理的考试关联的题库数据 + * @param examId */ void clear(String examId); -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java index 47d77b8..3f75664 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java @@ -1,75 +1,64 @@ -package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 +package com.yf.exam.modules.exam.service; -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 -import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 -import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO -import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.exam.dto.ExamDTO; +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; +import com.yf.exam.modules.exam.entity.Exam; /** - *

- * 考试业务类,提供考试的业务逻辑 - *

- * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试相关的业务操作。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -public interface ExamService extends IService { // 声明接口,继承自IService并指定操作的实体类为Exam +*

+* 考试业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +public interface ExamService extends IService { /** * 保存考试信息 - * 方法用于保存考试信息,包括考试的基本信息和相关联的题库、部门等。 - * - * @param reqDTO 考试保存请求数据传输对象,包含考试的详细信息 + * @param reqDTO */ void save(ExamSaveReqDTO reqDTO); /** * 查找考试详情 - * 方法用于根据考试ID查询考试的详细信息,包括考试的基本数据和相关联的部门、题库等。 - * - * @param id 考试ID,用于指定要查询的考试 - * @return ExamSaveReqDTO 返回考试详情,包含考试的详细信息 + * @param id + * @return */ ExamSaveReqDTO findDetail(String id); /** * 查找考试详情--简要信息 - * 方法用于根据考试ID查询考试的简要信息,通常用于列表展示。 - * - * @param id 考试ID,用于指定要查询的考试 - * @return ExamDTO 返回考试简要信息,包含考试的基本数据 + * @param id + * @return */ ExamDTO findById(String id); /** - * 分页查询数据 - * 方法用于分页查询考试数据,通常用于列表展示。 - * - * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 - * @return IPage 返回分页考试数据,包含考试列表和分页信息 - */ + * 分页查询数据 + * @param reqDTO + * @return + */ IPage paging(PagingReqDTO reqDTO); + /** * 在线考试分页响应类-考生视角 - * 方法用于分页查询在线考试数据,从考生视角,通常用于考生查看可参加的考试列表。 - * - * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 - * @return IPage 返回分页在线考试数据,包含在线考试列表和分页信息 + * @param reqDTO + * @return */ IPage onlinePaging(PagingReqDTO reqDTO); + /** * 待阅试卷列表 - * 方法用于分页查询待阅试卷数据,通常用于阅卷老师查看需要批改的试卷列表。 - * - * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 - * @return IPage 返回分页待阅试卷数据,包含待阅试卷列表和分页信息 + * @param reqDTO + * @return */ IPage reviewPaging(PagingReqDTO reqDTO); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java index 3460e7c..37ca2ff 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java @@ -1,64 +1,66 @@ -package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 +package com.yf.exam.modules.exam.service.impl; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 -import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 -import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 -import com.yf.exam.modules.exam.mapper.ExamDepartMapper; // 导入考试部门Mapper接口 -import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 -import org.springframework.stereotype.Service; // 导入Spring的服务注解 -import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.modules.exam.entity.ExamDepart; +import com.yf.exam.modules.exam.mapper.ExamDepartMapper; +import com.yf.exam.modules.exam.service.ExamDepartService; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; -import java.util.ArrayList; // 导入Java的ArrayList类 -import java.util.List; // 导入Java的List接口 +import java.util.ArrayList; +import java.util.List; /** - *

- * 考试部门业务实现类,提供考试部门的具体业务逻辑实现 - *

- * 此类实现了ExamDepartService接口,用于处理考试部门相关的业务逻辑。 - * - * @author 聪明笨狗 - * @since 2020-09-03 17:24 - */ -@Service // Spring注解,声明这是一个服务组件 -public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { // 声明类,继承自ServiceImpl并实现ExamDepartService接口 +*

+* 考试部门业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-03 17:24 +*/ +@Service +public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { @Override public void saveAll(String examId, List departs) { - // 先删除已有的部门 + + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 - this.remove(wrapper); // 根据条件删除部门 + wrapper.lambda().eq(ExamDepart::getExamId, examId); + this.remove(wrapper); - // 再增加新的部门 - if (CollectionUtils.isEmpty(departs)) { // 检查部门列表是否为空 - throw new ServiceException(1, "请至少选择选择一个部门!!"); // 如果为空,抛出异常 + // 再增加 + if(CollectionUtils.isEmpty(departs)){ + throw new ServiceException(1, "请至少选择选择一个部门!!"); } - List list = new ArrayList<>(); // 创建考试部门列表 + List list = new ArrayList<>(); - for (String id : departs) { - ExamDepart depart = new ExamDepart(); // 创建考试部门对象 - depart.setDepartId(id); // 设置部门ID - depart.setExamId(examId); // 设置考试ID - list.add(depart); // 添加到列表 + for(String id: departs){ + ExamDepart depart = new ExamDepart(); + depart.setDepartId(id); + depart.setExamId(examId); + list.add(depart); } - this.saveBatch(list); // 批量保存部门 + this.saveBatch(list); } @Override public List listByExam(String examId) { - // 查找考试对应的部门 + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 - List list = this.list(wrapper); // 根据条件查询部门列表 - List ids = new ArrayList<>(); // 创建部门ID列表 - if (!CollectionUtils.isEmpty(list)) { // 检查部门列表是否为空 - for (ExamDepart item : list) { - ids.add(item.getDepartId()); // 添加部门ID到列表 + wrapper.lambda().eq(ExamDepart::getExamId, examId); + List list = this.list(wrapper); + List ids = new ArrayList<>(); + if(!CollectionUtils.isEmpty(list)){ + for(ExamDepart item: list){ + ids.add(item.getDepartId()); } } - return ids; // 返回部门ID列表 + + return ids; + } -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java index e161f56..ea630e6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java @@ -1,63 +1,67 @@ -package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 -import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 -import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 -import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO -import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 -import com.yf.exam.modules.exam.mapper.ExamRepoMapper; // 导入考试题库Mapper接口 -import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 -import org.springframework.stereotype.Service; // 导入Spring的服务注解 -import org.springframework.transaction.annotation.Transactional; // 导入Spring的事务注解 -import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 - -import java.util.List; // 导入Java的List接口 +package com.yf.exam.modules.exam.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +import com.yf.exam.modules.exam.entity.ExamRepo; +import com.yf.exam.modules.exam.mapper.ExamRepoMapper; +import com.yf.exam.modules.exam.service.ExamRepoService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.List; /** - *

- * 考试题库业务实现类,提供考试题库的具体业务逻辑实现 - *

- * 此类实现了ExamRepoService接口,用于处理考试题库相关的业务逻辑。 - * - * @author 聪明笨狗 - * @since 2020-09-05 11:14 - */ -@Service // Spring注解,声明这是一个服务组件 -public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { // 声明类,继承自ServiceImpl并实现ExamRepoService接口 - - @Transactional(rollbackFor = Exception.class) // Spring事务注解,声明事务边界和回滚条件 +*

+* 考试题库业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-09-05 11:14 +*/ +@Service +public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { + + + @Transactional(rollbackFor = Exception.class) @Override public void saveAll(String examId, List list) { - // 先删除已有的题库 + + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 - this.remove(wrapper); // 根据条件删除题库 + wrapper.lambda().eq(ExamRepo::getExamId, examId); + this.remove(wrapper); - // 再增加新的题库 - if (CollectionUtils.isEmpty(list)) { // 检查题库列表是否为空 - throw new ServiceException(1, "必须选择题库!"); // 如果为空,抛出异常 + // 再增加 + if(CollectionUtils.isEmpty(list)){ + throw new ServiceException(1, "必须选择题库!"); } - List repos = BeanMapper.mapList(list, ExamRepo.class); // 使用BeanMapper将DTO列表转换为实体类列表 - for (ExamRepo item : repos) { - item.setExamId(examId); // 设置考试ID - item.setId(IdWorker.getIdStr()); // 使用IdWorker生成ID + List repos = BeanMapper.mapList(list, ExamRepo.class); + for(ExamRepo item: repos){ + item.setExamId(examId); + item.setId(IdWorker.getIdStr()); } - this.saveBatch(repos); // 批量保存题库 + this.saveBatch(repos); } @Override public List listByExam(String examId) { - return baseMapper.listByExam(examId); // 调用Mapper接口的方法,查找考试题库列表 + return baseMapper.listByExam(examId); } @Override public void clear(String examId) { - // 先删除已有的题库 + + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 - this.remove(wrapper); // 根据条件删除题库 + wrapper.lambda().eq(ExamRepo::getExamId, examId); + this.remove(wrapper); } -} \ No newline at end of file + + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java index 50ae151..7451bd9 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java @@ -1,173 +1,194 @@ -package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 - -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 -import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 -import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO -import com.yf.exam.core.enums.OpenType; // 导入开放类型枚举 -import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 -import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 -import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO -import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库DTO -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO -import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 -import com.yf.exam.modules.exam.mapper.ExamMapper; // 导入考试Mapper接口 -import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 -import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 -import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 -import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类 -import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 -import org.springframework.dao.DuplicateKeyException; // 导入Spring的重复键异常类 -import org.springframework.stereotype.Service; // 导入Spring的服务注解 - -import java.util.List; // 导入Java的List接口 +package com.yf.exam.modules.exam.service.impl; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.enums.OpenType; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.exam.dto.ExamDTO; +import com.yf.exam.modules.exam.dto.ExamRepoDTO; +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; +import com.yf.exam.modules.exam.entity.Exam; +import com.yf.exam.modules.exam.mapper.ExamMapper; +import com.yf.exam.modules.exam.service.ExamDepartService; +import com.yf.exam.modules.exam.service.ExamRepoService; +import com.yf.exam.modules.exam.service.ExamService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.stereotype.Service; + +import java.util.List; /** - *

- * 考试业务实现类 - *

- * 此类实现了ExamService接口,用于处理考试相关的业务逻辑。 - * - * @author 聪明笨狗 - * @since 2020-07-25 16:18 - */ -@Service // Spring注解,声明这是一个服务组件 -public class ExamServiceImpl extends ServiceImpl implements ExamService { // 声明类,继承自ServiceImpl并实现ExamService接口 +*

+* 考试业务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-07-25 16:18 +*/ +@Service +public class ExamServiceImpl extends ServiceImpl implements ExamService { + @Autowired - private ExamRepoService examRepoService; // 自动注入考试题库服务 + private ExamRepoService examRepoService; @Autowired - private ExamDepartService examDepartService; // 自动注入考试部门服务 + private ExamDepartService examDepartService; @Override public void save(ExamSaveReqDTO reqDTO) { + // ID String id = reqDTO.getId(); - if(StringUtils.isBlank(id)){ // 如果ID为空,则生成新的ID - id = IdWorker.getIdStr(); // 使用IdWorker生成ID + if(StringUtils.isBlank(id)){ + id = IdWorker.getIdStr(); } - // 复制参数 - Exam entity = new Exam(); // 创建考试实体 + //复制参数 + Exam entity = new Exam(); // 计算分值 - this.calcScore(reqDTO); // 调用方法计算分值 + this.calcScore(reqDTO); + // 复制基本数据 - BeanMapper.copy(reqDTO, entity); // 使用BeanMapper复制属性 - entity.setId(id); // 设置ID + BeanMapper.copy(reqDTO, entity); + entity.setId(id); // 修复状态 - if (reqDTO.getTimeLimit() != null + if (reqDTO.getTimeLimit()!=null && !reqDTO.getTimeLimit() - && reqDTO.getState() != null + && reqDTO.getState()!=null && reqDTO.getState() == 2) { - entity.setState(0); // 如果不限时且状态为2,则状态设置为0 + entity.setState(0); } else { - entity.setState(reqDTO.getState()); // 否则直接设置状态 + entity.setState(reqDTO.getState()); } // 题库组卷 try { - examRepoService.saveAll(id, reqDTO.getRepoList()); // 调用考试题库服务保存题库 + examRepoService.saveAll(id, reqDTO.getRepoList()); }catch (DuplicateKeyException e){ - throw new ServiceException(1, "不能选择重复的题库!"); // 如果出现重复键异常,则抛出服务异常 + throw new ServiceException(1, "不能选择重复的题库!"); } + // 开放的部门 - if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ // 如果开放类型为部门开放 - examDepartService.saveAll(id, reqDTO.getDepartIds()); // 调用考试部门服务保存部门 + if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ + examDepartService.saveAll(id, reqDTO.getDepartIds()); } - this.saveOrUpdate(entity); // 保存或更新考试实体 + this.saveOrUpdate(entity); + } @Override public ExamSaveReqDTO findDetail(String id) { - ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); // 创建响应DTO - Exam exam = this.getById(id); // 根据ID查询考试实体 - BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 + ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); + Exam exam = this.getById(id); + BeanMapper.copy(exam, respDTO); // 考试部门 - List departIds = examDepartService.listByExam(id); // 调用考试部门服务查询部门ID列表 - respDTO.setDepartIds(departIds); // 设置部门ID列表 + List departIds = examDepartService.listByExam(id); + respDTO.setDepartIds(departIds); // 题库 - List repos = examRepoService.listByExam(id); // 调用考试题库服务查询题库列表 - respDTO.setRepoList(repos); // 设置题库列表 + List repos = examRepoService.listByExam(id); + respDTO.setRepoList(repos); - return respDTO; // 返回响应DTO + return respDTO; } @Override public ExamDTO findById(String id) { - ExamDTO respDTO = new ExamDTO(); // 创建响应DTO - Exam exam = this.getById(id); // 根据ID查询考试实体 - BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 - return respDTO; // 返回响应DTO + ExamDTO respDTO = new ExamDTO(); + Exam exam = this.getById(id); + BeanMapper.copy(exam, respDTO); + return respDTO; } @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 - // 转换结果 - IPage pageData = baseMapper.paging(page, reqDTO.getParams()); // 调用Mapper接口的分页方法 - return pageData; // 返回分页结果 - } + //创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + + //转换结果 + IPage pageData = baseMapper.paging(page, reqDTO.getParams()); + return pageData; + } @Override public IPage onlinePaging(PagingReqDTO reqDTO) { + + // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 查找分页 - IPage pageData = baseMapper.online(page, reqDTO.getParams()); // 调用Mapper接口的在线考试分页方法 - return pageData; // 返回分页结果 + IPage pageData = baseMapper.online(page, reqDTO.getParams()); + + return pageData; } @Override public IPage reviewPaging(PagingReqDTO reqDTO) { // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 查找分页 - IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); // 调用Mapper接口的阅卷分页方法 - return pageData; // 返回分页结果 + IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); + + return pageData; } + /** * 计算分值 - * 方法用于计算考试的总分值,根据题库中的题目数量和分数。 - * - * @param reqDTO 考试保存请求DTO + * @param reqDTO */ - private void calcScore(ExamSaveReqDTO reqDTO) { + private void calcScore(ExamSaveReqDTO reqDTO){ + // 主观题分数 int objScore = 0; // 题库组卷 - List repoList = reqDTO.getRepoList(); // 获取题库列表 - - for(ExamRepoDTO item : repoList){ // 遍历题库列表 - if(item.getRadioCount() != null && item.getRadioCount() > 0 && item.getRadioScore() != null && item.getRadioScore() > 0){ - objScore += item.getRadioCount() * item.getRadioScore(); // 计算单选题分数 + List repoList = reqDTO.getRepoList(); + + for(ExamRepoDTO item: repoList){ + if(item.getRadioCount()!=null + && item.getRadioCount()>0 + && item.getRadioScore()!=null + && item.getRadioScore()>0){ + objScore+=item.getRadioCount()*item.getRadioScore(); } - if(item.getMultiCount() != null && item.getMultiCount() > 0 && item.getMultiScore() != null && item.getMultiScore() > 0){ - objScore += item.getMultiCount() * item.getMultiScore(); // 计算多选题分数 + if(item.getMultiCount()!=null + && item.getMultiCount()>0 + && item.getMultiScore()!=null + && item.getMultiScore()>0){ + objScore+=item.getMultiCount()*item.getMultiScore(); } - if(item.getJudgeCount() != null && item.getJudgeCount() > 0 && item.getJudgeScore() != null && item.getJudgeScore() > 0){ - objScore += item.getJudgeCount() * item.getJudgeScore(); // 计算判断题分数 + if(item.getJudgeCount()!=null + && item.getJudgeCount()>0 + && item.getJudgeScore()!=null + && item.getJudgeScore()>0){ + objScore+=item.getJudgeCount()*item.getJudgeScore(); } } - reqDTO.setTotalScore(objScore); // 设置总分值 + + + reqDTO.setTotalScore(objScore); } -} \ No newline at end of file + +} diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java b/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java index 5549670..a3ad8ed 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java @@ -1,13 +1,19 @@ -package com.yf.exam.modules.paper.controller; +package com.yf.exam.modules.paper.controller; // 定义当前类所在的包路径 +// 引入分页查询结果的接口 import com.baomidou.mybatisplus.core.metadata.IPage; +// 引入统一的API响应封装类 import com.yf.exam.core.api.ApiRest; +// 引入基础控制器类,提供通用的API响应方法 import com.yf.exam.core.api.controller.BaseController; +// 引入各种DTO类,用于请求和响应数据传输 import com.yf.exam.core.api.dto.BaseIdReqDTO; import com.yf.exam.core.api.dto.BaseIdRespDTO; import com.yf.exam.core.api.dto.BaseIdsReqDTO; import com.yf.exam.core.api.dto.PagingReqDTO; +// 引入工具类,用于对象之间的属性拷贝 import com.yf.exam.core.utils.BeanMapper; +// 引入试卷相关的DTO类 import com.yf.exam.modules.paper.dto.PaperDTO; import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; @@ -17,14 +23,22 @@ import com.yf.exam.modules.paper.dto.request.PaperQuQueryDTO; import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; +// 引入试卷实体类 import com.yf.exam.modules.paper.entity.Paper; +// 引入试卷相关的业务处理服务类 import com.yf.exam.modules.paper.service.PaperService; +// 引入用户工具类,获取当前登录用户信息 import com.yf.exam.modules.user.UserUtils; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +// 引入Shiro注解,用于角色权限管理 import org.apache.shiro.authz.annotation.RequiresRoles; +// 引入Spring的Bean工具类,用于属性复制 import org.springframework.beans.BeanUtils; +// 引入Spring的自动注入注解,用于自动注入服务 import org.springframework.beans.factory.annotation.Autowired; +// 引入Spring的Web注解,定义HTTP请求的映射方式 import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -34,123 +48,126 @@ import org.springframework.web.bind.annotation.RestController; *

* 试卷控制器 *

-* +* 提供有关试卷的操作,如分页查询、创建试卷、查看试卷详情等 * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Api(tags={"试卷"}) -@RestController -@RequestMapping("/exam/api/paper/paper") -public class PaperController extends BaseController { +@Api(tags={"试卷"}) // Swagger API 文档注解,用于描述该接口属于试卷相关操作 +@RestController // 标记为Spring的控制器,处理HTTP请求 +@RequestMapping("/exam/api/paper/paper") // 定义请求路径的基础路径 +public class PaperController extends BaseController { // 继承BaseController类,提供基本的API返回 - @Autowired + @Autowired // 自动注入PaperService,负责业务逻辑处理 private PaperService baseService; /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找试卷列表 + * @param reqDTO 包含分页信息和查询条件的请求数据 + * @return 分页后的试卷列表 */ - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + @ApiOperation(value = "分页查找") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - //分页查询并转换 + // 调用业务层进行分页查询 IPage page = baseService.paging(reqDTO); + // 返回成功响应,并附带查询结果 return super.success(page); } - - /** * 创建试卷 - * @param reqDTO - * @return + * @param reqDTO 创建试卷所需的请求数据 + * @return 返回创建成功后的试卷ID */ - @ApiOperation(value = "创建试卷") - @RequestMapping(value = "/create-paper", method = { RequestMethod.POST}) + @ApiOperation(value = "创建试卷") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/create-paper", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest save(@RequestBody PaperCreateReqDTO reqDTO) { - //复制参数 + // 调用业务层创建试卷,传入当前用户ID和考试ID String paperId = baseService.createPaper(UserUtils.getUserId(), reqDTO.getExamId()); + // 返回创建结果,包括试卷ID return super.success(new BaseIdRespDTO(paperId)); } /** - * 批量删除 - * @param reqDTO - * @return + * 获取试卷详情 + * @param reqDTO 请求参数,包含试卷ID + * @return 返回试卷的详细信息 */ - @ApiOperation(value = "试卷详情") - @RequestMapping(value = "/paper-detail", method = { RequestMethod.POST}) + @ApiOperation(value = "试卷详情") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/paper-detail", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest paperDetail(@RequestBody BaseIdReqDTO reqDTO) { - //根据ID删除 + // 调用业务层获取试卷详情 ExamDetailRespDTO respDTO = baseService.paperDetail(reqDTO.getId()); + // 返回成功响应,并附带试卷详情 return super.success(respDTO); } /** - * 批量删除 - * @param reqDTO - * @return + * 获取试题详情 + * @param reqDTO 请求参数,包含试卷ID和试题ID + * @return 返回试题的详细信息 */ - @ApiOperation(value = "试题详情") - @RequestMapping(value = "/qu-detail", method = { RequestMethod.POST}) + @ApiOperation(value = "试题详情") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/qu-detail", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest quDetail(@RequestBody PaperQuQueryDTO reqDTO) { - //根据ID删除 + // 调用业务层获取试题详情 PaperQuDetailDTO respDTO = baseService.findQuDetail(reqDTO.getPaperId(), reqDTO.getQuId()); + // 返回成功响应,并附带试题详情 return super.success(respDTO); } /** * 填充答案 - * @param reqDTO - * @return + * @param reqDTO 请求数据,包含填充的答案 + * @return 返回操作成功的响应 */ - @ApiOperation(value = "填充答案") - @RequestMapping(value = "/fill-answer", method = { RequestMethod.POST}) + @ApiOperation(value = "填充答案") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/fill-answer", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest fillAnswer(@RequestBody PaperAnswerDTO reqDTO) { - //根据ID删除 + // 调用业务层填充答案操作 baseService.fillAnswer(reqDTO); + // 返回成功响应 return super.success(); } - /** * 交卷操作 - * @param reqDTO - * @return + * @param reqDTO 请求数据,包含试卷ID + * @return 返回交卷操作成功的响应 */ - @ApiOperation(value = "交卷操作") - @RequestMapping(value = "/hand-exam", method = { RequestMethod.POST}) + @ApiOperation(value = "交卷操作") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/hand-exam", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest handleExam(@RequestBody BaseIdReqDTO reqDTO) { - //根据ID删除 + // 调用业务层进行交卷操作 baseService.handExam(reqDTO.getId()); + // 返回成功响应 return super.success(); } - /** - * 批量删除 - * @param reqDTO - * @return + * 获取试卷结果 + * @param reqDTO 请求数据,包含试卷ID + * @return 返回试卷的考试结果 */ - @ApiOperation(value = "试卷详情") - @RequestMapping(value = "/paper-result", method = { RequestMethod.POST}) + @ApiOperation(value = "试卷结果") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/paper-result", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest paperResult(@RequestBody BaseIdReqDTO reqDTO) { - //根据ID删除 + // 调用业务层获取试卷的考试结果 ExamResultRespDTO respDTO = baseService.paperResult(reqDTO.getId()); + // 返回成功响应,并附带试卷结果 return super.success(respDTO); } - /** * 检测用户有没有中断的考试 - * @return + * @return 返回用户未完成的考试信息 */ - @ApiOperation(value = "检测进行中的考试") - @RequestMapping(value = "/check-process", method = { RequestMethod.POST}) + @ApiOperation(value = "检测进行中的考试") // Swagger操作注解,用于描述接口 + @RequestMapping(value = "/check-process", method = { RequestMethod.POST}) // 定义POST请求路径 public ApiRest checkProcess() { - //复制参数 + // 调用业务层检测用户是否有未完成的考试 PaperDTO dto = baseService.checkProcess(UserUtils.getUserId()); + // 返回成功响应,并附带考试进程数据 return super.success(dto); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java index dcfb9ef..8b59dcb 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java @@ -1,79 +1,83 @@ -package com.yf.exam.modules.paper.dto; +package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +// 引入Dict注解,用于字典表的映射 import com.yf.exam.core.annon.Dict; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Serializable接口,用于对象序列化 import java.io.Serializable; +// 引入Date类,用于表示日期和时间 import java.util.Date; /** -*

-* 试卷请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@ApiModel(value="试卷", description="试卷") -public class PaperDTO implements Serializable { - - private static final long serialVersionUID = 1L; + *

+ * 试卷请求类 + *

+ * 该类用于传输试卷的基本信息,包含试卷的ID、考试规则、标题、时长、得分等字段。 + * 提供了试卷的详细信息,通常在查询和展示试卷时使用。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷", description="试卷") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "试卷ID", required=true) - private String id; + @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String id; // 试卷ID - @Dict(dictTable = "sys_user", dicText = "real_name", dicCode = "id") - @ApiModelProperty(value = "用户ID", required=true) - private String userId; + @Dict(dictTable = "sys_user", dicText = "real_name", dicCode = "id") // 字典表映射,映射用户表的姓名字段 + @ApiModelProperty(value = "用户ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String userId; // 用户ID - @Dict(dictTable = "sys_depart", dicText = "dept_name", dicCode = "id") - @ApiModelProperty(value = "部门ID", required=true) - private String departId; + @Dict(dictTable = "sys_depart", dicText = "dept_name", dicCode = "id") // 字典表映射,映射部门表的部门名称字段 + @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String departId; // 部门ID - @ApiModelProperty(value = "规则ID", required=true) - private String examId; + @ApiModelProperty(value = "规则ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String examId; // 规则ID,表示该试卷对应的考试规则 - @ApiModelProperty(value = "考试标题", required=true) - private String title; + @ApiModelProperty(value = "考试标题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String title; // 考试标题,表示试卷的名称 - @ApiModelProperty(value = "考试时长", required=true) - private Integer totalTime; + @ApiModelProperty(value = "考试时长", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer totalTime; // 考试时长(单位:分钟) - @ApiModelProperty(value = "用户时长", required=true) - private Integer userTime; + @ApiModelProperty(value = "用户时长", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer userTime; // 用户已使用的时间(单位:分钟) - @ApiModelProperty(value = "试卷总分", required=true) - private Integer totalScore; + @ApiModelProperty(value = "试卷总分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer totalScore; // 试卷总分 - @ApiModelProperty(value = "及格分", required=true) - private Integer qualifyScore; + @ApiModelProperty(value = "及格分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer qualifyScore; // 及格分数 - @ApiModelProperty(value = "客观分", required=true) - private Integer objScore; + @ApiModelProperty(value = "客观分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer objScore; // 客观题分数 - @ApiModelProperty(value = "主观分", required=true) - private Integer subjScore; + @ApiModelProperty(value = "主观分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer subjScore; // 主观题分数 - @ApiModelProperty(value = "用户得分", required=true) - private Integer userScore; + @ApiModelProperty(value = "用户得分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer userScore; // 用户得分 - @ApiModelProperty(value = "是否包含简答题", required=true) - private Boolean hasSaq; + @ApiModelProperty(value = "是否包含简答题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Boolean hasSaq; // 是否包含简答题,布尔类型,表示该试卷是否有简答题 - @ApiModelProperty(value = "试卷状态", required=true) - private Integer state; + @ApiModelProperty(value = "试卷状态", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer state; // 试卷状态,表示试卷的当前状态,如未开始、进行中、已结束等 - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; + @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Date createTime; // 创建时间,表示试卷的创建时间 - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; + @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Date updateTime; // 更新时间,表示试卷的最后更新时间 - @ApiModelProperty(value = "截止时间") - private Date limitTime; - + @ApiModelProperty(value = "截止时间") // Swagger注解,描述该字段在API文档中的含义 + private Date limitTime; // 截止时间,表示考试的最后提交时间 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java index e449e79..48672a7 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java @@ -1,48 +1,50 @@ -package com.yf.exam.modules.paper.dto; +package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Serializable接口,用于对象序列化 import java.io.Serializable; /** -*

-* 试卷考题备选答案请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") -public class PaperQuAnswerDTO implements Serializable { - - private static final long serialVersionUID = 1L; + *

+ * 试卷考题备选答案请求类 + *

+ * 该类用于表示试卷考题的备选答案,包含每个备选答案的ID、题目ID、选项标签、是否选中等信息。 + * 适用于考题答案的请求传输。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperQuAnswerDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "自增ID", required=true) - private String id; + @ApiModelProperty(value = "自增ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String id; // 自增ID,表示备选答案的唯一标识符 - @ApiModelProperty(value = "试卷ID", required=true) - private String paperId; + @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String paperId; // 试卷ID,表示该备选答案所属的试卷 - @ApiModelProperty(value = "回答项ID", required=true) - private String answerId; + @ApiModelProperty(value = "回答项ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String answerId; // 回答项ID,表示该备选答案的唯一标识符 - @ApiModelProperty(value = "题目ID", required=true) - private String quId; + @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String quId; // 题目ID,表示该备选答案所属的题目 - @ApiModelProperty(value = "是否正确项", required=true) - private Boolean isRight; + @ApiModelProperty(value = "是否正确项", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Boolean isRight; // 是否正确项,布尔值,表示该备选答案是否是正确答案 - @ApiModelProperty(value = "是否选中", required=true) - private Boolean checked; + @ApiModelProperty(value = "是否选中", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Boolean checked; // 是否选中,布尔值,表示该备选答案是否已被选中 - @ApiModelProperty(value = "排序", required=true) - private Integer sort; + @ApiModelProperty(value = "排序", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer sort; // 排序,表示该备选答案在题目中的排序位置 - @ApiModelProperty(value = "选项标签", required=true) - private String abc; - + @ApiModelProperty(value = "选项标签", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String abc; // 选项标签,通常为 A、B、C、D 等,表示该备选答案的标识符 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java index 349868e..05bf6d7 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java @@ -1,54 +1,55 @@ -package com.yf.exam.modules.paper.dto; +package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Serializable接口,用于对象序列化 import java.io.Serializable; /** -*

-* 试卷考题请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@ApiModel(value="试卷考题", description="试卷考题") -public class PaperQuDTO implements Serializable { - - private static final long serialVersionUID = 1L; + *

+ * 试卷考题请求类 + *

+ * 该类用于表示试卷中的每一道题目,包含题目的基本信息,如题目ID、试卷ID、题目类型、是否答对、得分等。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷考题", description="试卷考题") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperQuDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String id; // 题目ID,唯一标识符 - @ApiModelProperty(value = "试卷ID", required=true) - private String paperId; + @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String paperId; // 试卷ID,表示该题目所属的试卷 - @ApiModelProperty(value = "题目ID", required=true) - private String quId; + @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String quId; // 题目ID,唯一标识该题目 - @ApiModelProperty(value = "题目类型", required=true) - private Integer quType; + @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer quType; // 题目类型,表示题目的分类,如选择题、判断题、主观题等 - @ApiModelProperty(value = "是否已答", required=true) - private Boolean answered; + @ApiModelProperty(value = "是否已答", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Boolean answered; // 是否已答,布尔值,表示该题目是否已被回答 - @ApiModelProperty(value = "主观答案", required=true) - private String answer; + @ApiModelProperty(value = "主观答案", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String answer; // 主观答案,表示对该题目的回答内容(适用于主观题) - @ApiModelProperty(value = "问题排序", required=true) - private Integer sort; + @ApiModelProperty(value = "问题排序", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer sort; // 问题排序,表示该题目在试卷中的顺序 - @ApiModelProperty(value = "单题分分值", required=true) - private Integer score; + @ApiModelProperty(value = "单题分分值", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer score; // 单题分值,表示该题目的满分 - @ApiModelProperty(value = "实际得分(主观题)", required=true) - private Integer actualScore; + @ApiModelProperty(value = "实际得分(主观题)", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer actualScore; // 实际得分,表示用户在该题目中实际得到的分数(适用于主观题) - @ApiModelProperty(value = "是否答对", required=true) - private Boolean isRight; - + @ApiModelProperty(value = "是否答对", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Boolean isRight; // 是否答对,布尔值,表示用户是否答对了该题目 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java index 3124d9e..357808a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java @@ -1,29 +1,30 @@ -package com.yf.exam.modules.paper.dto.ext; +package com.yf.exam.modules.paper.dto.ext; // 定义该类所在的包路径 +// 引入试题答案DTO类,作为当前类的父类 import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** *

* 试卷考题备选答案请求类 *

-* +* 该类用于描述试卷考题的备选答案信息,继承自PaperQuAnswerDTO,扩展了额外的字段,如图片和内容。 * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data -@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") -public class PaperQuAnswerExtDTO extends PaperQuAnswerDTO { +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") // Swagger注解,描述模型信息,生成API文档时使用 +public class PaperQuAnswerExtDTO extends PaperQuAnswerDTO { // 继承自PaperQuAnswerDTO类,扩展了额外属性 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 - @ApiModelProperty(value = "试题图片", required=true) - private String image; + @ApiModelProperty(value = "试题图片", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String image; // 试题对应的图片内容 - @ApiModelProperty(value = "答案内容", required=true) - private String content; - - + @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String content; // 备选答案的具体内容 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java index ee1e998..e2d693b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java @@ -1,32 +1,35 @@ -package com.yf.exam.modules.paper.dto.ext; +package com.yf.exam.modules.paper.dto.ext; // 定义当前类所在的包路径 +// 引入试题DTO类,作为当前类的父类 import com.yf.exam.modules.paper.dto.PaperQuDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入List集合,用于存储多个备选答案 import java.util.List; /** *

* 试卷考题请求类 *

-* +* 该类用于描述试卷中每个考题的详细信息,继承自PaperQuDTO,扩展了试题的图片、内容和答案列表等字段。 * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data -@ApiModel(value="试卷题目详情类", description="试卷题目详情类") -public class PaperQuDetailDTO extends PaperQuDTO { +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷题目详情类", description="试卷题目详情类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperQuDetailDTO extends PaperQuDTO { // 继承自PaperQuDTO类,扩展了额外属性 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 - @ApiModelProperty(value = "图片", required=true) - private String image; + @ApiModelProperty(value = "图片", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String image; // 题目的图片内容 - @ApiModelProperty(value = "题目内容", required=true) - private String content; + @ApiModelProperty(value = "题目内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String content; // 试题的具体内容 - @ApiModelProperty(value = "答案内容", required=true) - List answerList; + @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List answerList; // 存储该题目的备选答案,使用List集合存储多个答案 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java index ccbe3ce..25df4c6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java @@ -1,22 +1,25 @@ -package com.yf.exam.modules.paper.dto.request; +package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入List集合,用于存储多个答案 import java.util.List; /** * @author bool + * 查找试卷题目详情请求类,用于接收查找试卷题目详情的请求数据。 + * 继承自PaperQuQueryDTO,扩展了回答列表和主观答案字段。 */ -@Data -@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") -public class PaperAnswerDTO extends PaperQuQueryDTO { - - @ApiModelProperty(value = "回答列表", required=true) - private List answers; +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperAnswerDTO extends PaperQuQueryDTO { // 继承自PaperQuQueryDTO类,扩展了额外属性 - @ApiModelProperty(value = "主观答案", required=true) - private String answer; + @ApiModelProperty(value = "回答列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List answers; // 存储多个选择题答案的列表 + @ApiModelProperty(value = "主观答案", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String answer; // 存储主观题的答案内容 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java index 6a8f8c5..22d11e9 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java @@ -1,22 +1,26 @@ -package com.yf.exam.modules.paper.dto.request; +package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +// 引入父类BaseDTO,用于继承基础字段和功能 import com.yf.exam.core.api.dto.BaseDTO; +// 引入Jackson注解,用于处理JSON序列化时忽略某些字段 import com.fasterxml.jackson.annotation.JsonIgnore; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** * @author bool + * 试卷创建请求类,用于接收试卷创建的请求数据,包含考试ID和用户ID等字段。 */ -@Data -@ApiModel(value="试卷创建请求类", description="试卷创建请求类") -public class PaperCreateReqDTO extends BaseDTO { +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷创建请求类", description="试卷创建请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperCreateReqDTO extends BaseDTO { // 继承自BaseDTO类,扩展了考试ID和用户ID字段 - @JsonIgnore - private String userId; - - @ApiModelProperty(value = "考试ID", required=true) - private String examId; + @JsonIgnore // Jackson注解,表示在进行JSON序列化/反序列化时忽略该字段 + private String userId; // 存储用户ID,通常用于标识发起请求的用户,但在JSON序列化中不会被传递 + @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String examId; // 存储考试ID,用于创建试卷时指定关联的考试 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java index c333241..a166dc8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java @@ -1,39 +1,40 @@ -package com.yf.exam.modules.paper.dto.request; +package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Serializable接口,用于对象序列化 import java.io.Serializable; /** *

* 试卷请求类 *

-* +* 该类用于接收请求数据,包含用户ID、部门ID、规则ID、用户昵称和试卷状态等信息, +* 用于查询试卷列表。 * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data -@ApiModel(value="试卷", description="试卷") -public class PaperListReqDTO implements Serializable { - - private static final long serialVersionUID = 1L; +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷", description="试卷") // Swagger注解,描述该类在API文档中的作用和说明 +public class PaperListReqDTO implements Serializable { // 实现Serializable接口,支持对象的序列化 - @ApiModelProperty(value = "用户ID", required=true) - private String userId; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 - @ApiModelProperty(value = "部门ID", required=true) - private String departId; + @ApiModelProperty(value = "用户ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String userId; // 存储请求发起者的用户ID,通常用于标识用户 - @ApiModelProperty(value = "规则ID", required=true) - private String examId; + @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String departId; // 存储请求者所在部门的ID,用于查询特定部门的试卷 - @ApiModelProperty(value = "用户昵称", required=true) - private String realName; + @ApiModelProperty(value = "规则ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String examId; // 存储与试卷相关的考试规则ID,用于标识试卷属于哪种考试 - @ApiModelProperty(value = "试卷状态", required=true) - private Integer state; + @ApiModelProperty(value = "用户昵称", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String realName; // 存储用户的真实姓名,用于标识请求者 - + @ApiModelProperty(value = "试卷状态", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private Integer state; // 存储试卷的状态,可能的值如:未开始、进行中、已完成等 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java index 48184b6..b91286c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java @@ -1,21 +1,25 @@ -package com.yf.exam.modules.paper.dto.request; +package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +// 引入父类BaseDTO,用于继承基础字段和功能 import com.yf.exam.core.api.dto.BaseDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** * @author bool + * 查找试卷题目详情请求类,用于接收试卷和题目详情查询的请求数据。 + * 包含试卷ID和题目ID字段。 */ -@Data -@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") -public class PaperQuQueryDTO extends BaseDTO { +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperQuQueryDTO extends BaseDTO { // 继承自BaseDTO类,扩展了试卷ID和题目ID字段 - @ApiModelProperty(value = "试卷ID", required=true) - private String paperId; - - @ApiModelProperty(value = "题目ID", required=true) - private String quId; + @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String paperId; // 存储试卷ID,用于查询特定试卷的题目详情 + @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String quId; // 存储题目ID,用于查询指定试卷中的某一道题目 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java index c307c84..12aecf2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java @@ -1,38 +1,48 @@ -package com.yf.exam.modules.paper.dto.response; +package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +// 引入父类PaperDTO,用于继承基础字段和功能 import com.yf.exam.modules.paper.dto.PaperDTO; +// 引入PaperQuDTO类,用于表示试题的DTO import com.yf.exam.modules.paper.dto.PaperQuDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Calendar类,用于时间计算 import java.util.Calendar; +// 引入List集合,用于存储试题列表 import java.util.List; -@Data -@ApiModel(value="考试详情", description="考试详情") -public class ExamDetailRespDTO extends PaperDTO { - +/** + *

+ * 考试详情响应类 + *

+ * 该类继承自PaperDTO,扩展了多个属性,包含单选题、多选题、判断题的列表, + * 以及计算剩余时间的方法,用于提供考试的详细信息。 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="考试详情", description="考试详情") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class ExamDetailRespDTO extends PaperDTO { // 继承自PaperDTO,表示考试详情响应DTO - @ApiModelProperty(value = "单选题列表", required=true) - private List radioList; + @ApiModelProperty(value = "单选题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List radioList; // 存储单选题的列表,使用PaperQuDTO表示单个试题 - @ApiModelProperty(value = "多选题列表", required=true) - private List multiList; + @ApiModelProperty(value = "多选题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List multiList; // 存储多选题的列表,使用PaperQuDTO表示单个试题 - @ApiModelProperty(value = "判断题", required=true) - private List judgeList; + @ApiModelProperty(value = "判断题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List judgeList; // 存储判断题的列表,使用PaperQuDTO表示单个试题 - - @ApiModelProperty(value = "剩余结束秒数", required=true) - public Long getLeftSeconds(){ + @ApiModelProperty(value = "剩余结束秒数", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + public Long getLeftSeconds(){ // 计算剩余时间的方法,返回剩余的秒数 // 结束时间 - Calendar cl = Calendar.getInstance(); - cl.setTime(this.getCreateTime()); - cl.add(Calendar.MINUTE, getTotalTime()); + Calendar cl = Calendar.getInstance(); // 获取当前时间的Calendar实例 + cl.setTime(this.getCreateTime()); // 设置Calendar的时间为试卷的创建时间 + cl.add(Calendar.MINUTE, getTotalTime()); // 在创建时间的基础上加上试卷的总时间(分钟) - return (cl.getTimeInMillis() - System.currentTimeMillis()) / 1000; + // 计算剩余时间(单位:秒) + return (cl.getTimeInMillis() - System.currentTimeMillis()) / 1000; // 返回剩余时间(当前时间到结束时间的差值,以秒为单位) } - } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java index 64af63d..26c9710 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java @@ -1,18 +1,29 @@ -package com.yf.exam.modules.paper.dto.response; +package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +// 引入父类PaperDTO,用于继承基础字段和功能 import com.yf.exam.modules.paper.dto.PaperDTO; +// 引入PaperQuDetailDTO类,用于表示试题详细信息 import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入List集合,用于存储试题列表 import java.util.List; -@Data -@ApiModel(value="考试结果展示响应类", description="考试结果展示响应类") -public class ExamResultRespDTO extends PaperDTO { +/** + *

+ * 考试结果展示响应类 + *

+ * 该类继承自PaperDTO,扩展了问题列表字段,用于展示考试结果的详细信息。 + * 包含试题的详细信息列表,返回考试时各个问题的答案或状态。 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="考试结果展示响应类", description="考试结果展示响应类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class ExamResultRespDTO extends PaperDTO { // 继承自PaperDTO,表示考试结果展示响应DTO - @ApiModelProperty(value = "问题列表", required=true) - private List quList; + @ApiModelProperty(value = "问题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private List quList; // 存储试题详细信息的列表,使用PaperQuDetailDTO表示每个试题的详细数据 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java index 9e003e4..379de39 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java @@ -1,26 +1,29 @@ -package com.yf.exam.modules.paper.dto.response; +package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +// 引入父类PaperDTO,用于继承基本的试卷信息 import com.yf.exam.modules.paper.dto.PaperDTO; +// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** -*

-* 试卷请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@ApiModel(value="试卷列表响应类", description="试卷列表响应类") -public class PaperListRespDTO extends PaperDTO { + *

+ * 试卷列表响应类 + *

+ * 该类继承自PaperDTO,扩展了人员(realName)字段,用于展示试卷列表响应数据。 + * 包含试卷的基本信息以及相关人员信息。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="试卷列表响应类", description="试卷列表响应类") // Swagger注解,用于描述该类在API文档中的作用和说明 +public class PaperListRespDTO extends PaperDTO { // 继承自PaperDTO,表示试卷列表响应DTO - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "人员", required=true) - private String realName; - - + @ApiModelProperty(value = "人员", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 + private String realName; // 存储人员姓名,用于表示与该试卷相关的人员信息 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java index e219471..f6baaac 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java @@ -1,125 +1,104 @@ -package com.yf.exam.modules.paper.entity; +package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; - +// 引入Date类,用于时间相关的字段 import java.util.Date; /** -*

-* 试卷实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@TableName("el_paper") -public class Paper extends Model { - - private static final long serialVersionUID = 1L; + *

+ * 试卷实体类 + *

+ * 该类对应数据库中的 `el_paper` 表,用于表示试卷的相关信息。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@TableName("el_paper") // MyBatis Plus注解,指定该实体类对应的数据库表名 +public class Paper extends Model { // 继承MyBatis Plus的Model类,提供了CRUD等基础操作 + + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 /** * 试卷ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 + private String id; // 试卷ID,唯一标识符 /** * 用户ID */ - @TableField("user_id") - private String userId; + @TableField("user_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String userId; // 用户ID,表示创建该试卷的用户 /** * 部门ID */ - @TableField("depart_id") - private String departId; + @TableField("depart_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String departId; // 部门ID,表示该试卷所属的部门 /** * 规则ID */ - @TableField("exam_id") - private String examId; + @TableField("exam_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String examId; // 规则ID,表示该试卷所属的考试规则 /** * 考试标题 */ - private String title; + private String title; // 考试标题,表示试卷的名称或标题 /** * 考试时长 */ - @TableField("total_time") - private Integer totalTime; + @TableField("total_time") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer totalTime; // 考试时长,单位为分钟 /** * 用户时长 */ - @TableField("user_time") - private Integer userTime; + @TableField("user_time") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer userTime; // 用户实际用时,单位为分钟 /** * 试卷总分 */ - @TableField("total_score") - private Integer totalScore; + @TableField("total_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer totalScore; // 试卷的总分数 /** * 及格分 */ - @TableField("qualify_score") - private Integer qualifyScore; + @TableField("qualify_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer qualifyScore; // 及格分数,表示通过该试卷的最低分数 /** * 客观分 */ - @TableField("obj_score") - private Integer objScore; + @TableField("obj_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer objScore; // 客观题部分的得分 /** * 主观分 */ - @TableField("subj_score") - private Integer subjScore; + @TableField("subj_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer subjScore; // 主观题部分的得分 /** * 用户得分 */ - @TableField("user_score") - private Integer userScore; + @TableField("user_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer userScore; // 用户在该试卷上的得分 /** * 是否包含简答题 */ - @TableField("has_saq") - private Boolean hasSaq; - - /** - * 试卷状态 - */ - private Integer state; - - /** - * 创建时间 - */ - @TableField("create_time") - private Date createTime; - - /** - * 更新时间 - */ - @TableField("update_time") - private Date updateTime; - - /** - * 截止时间 - */ - @TableField("limit_time") - private Date limitTime; -} + @TableField("has_saq") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java index 3723791..f6be46d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java @@ -1,80 +1,82 @@ -package com.yf.exam.modules.paper.entity; +package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** -*

-* 试卷考题实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@TableName("el_paper_qu") -public class PaperQu extends Model { + *

+ * 试卷考题实体类 + *

+ * 该类对应数据库中的 `el_paper_qu` 表,用于表示与试卷相关的考题信息。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@TableName("el_paper_qu") // MyBatis Plus注解,指定该实体类对应的数据库表名 +public class PaperQu extends Model { // 继承MyBatis Plus的Model类,提供了基础的CRUD等操作 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 /** * ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 + private String id; // 题目ID,唯一标识符 /** * 试卷ID */ - @TableField("paper_id") - private String paperId; + @TableField("paper_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String paperId; // 试卷ID,表示该题目所属的试卷ID /** * 题目ID */ - @TableField("qu_id") - private String quId; + @TableField("qu_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String quId; // 题目ID,唯一标识符 /** * 题目类型 */ - @TableField("qu_type") - private Integer quType; + @TableField("qu_type") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer quType; // 题目类型,表示该题目属于哪种类型(例如单选题、多选题、主观题等) /** * 是否已答 */ - private Boolean answered; + private Boolean answered; // 是否已经回答,布尔值,表示该题目是否已经被回答 /** * 主观答案 */ - private String answer; + private String answer; // 主观题的答案,保存用户的回答内容 /** * 问题排序 */ - private Integer sort; + private Integer sort; // 问题在试卷中的排序,决定题目的显示顺序 /** * 单题分分值 */ - private Integer score; + private Integer score; // 每道题的分值,表示该题目的得分值 /** * 实际得分(主观题) */ - @TableField("actual_score") - private Integer actualScore; + @TableField("actual_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Integer actualScore; // 主观题的实际得分,可能与用户给出的答案相关 /** * 是否答对 */ - @TableField("is_right") - private Boolean isRight; - + @TableField("is_right") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Boolean isRight; // 是否答对,布尔值,表示用户是否答对了该题目 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java index b3999da..78c17ce 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java @@ -1,68 +1,71 @@ -package com.yf.exam.modules.paper.entity; +package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; +// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** -*

-* 试卷考题备选答案实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 17:31 -*/ -@Data -@TableName("el_paper_qu_answer") -public class PaperQuAnswer extends Model { + *

+ * 试卷考题备选答案实体类 + *

+ * 该类对应数据库中的 `el_paper_qu_answer` 表,用于表示试卷考题的备选答案。 + * + * @author 聪明笨狗 + * @since 2020-05-25 17:31 + */ +@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 +@TableName("el_paper_qu_answer") // MyBatis Plus注解,指定该实体类对应的数据库表名 +public class PaperQuAnswer extends Model { // 继承MyBatis Plus的Model类,提供了基础的CRUD等操作 + private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 /** * 自增ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 + private String id; // 唯一标识符ID,数据库中的主键 /** * 试卷ID */ - @TableField("paper_id") - private String paperId; + @TableField("paper_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String paperId; // 该备选答案对应的试卷ID /** * 回答项ID */ - @TableField("answer_id") - private String answerId; + @TableField("answer_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String answerId; // 该备选答案的唯一标识符ID /** * 题目ID */ - @TableField("qu_id") - private String quId; + @TableField("qu_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private String quId; // 该备选答案所属的题目ID /** * 是否正确项 */ - @TableField("is_right") - private Boolean isRight; + @TableField("is_right") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 + private Boolean isRight; // 是否是正确答案,布尔值(true 表示正确,false 表示错误) /** * 是否选中 */ - private Boolean checked; + private Boolean checked; // 该备选答案是否被选中,布尔值(true 表示已选中,false 表示未选中) /** * 排序 */ - private Integer sort; + private Integer sort; // 备选答案的排序,决定该答案在选项中的位置 /** * 选项标签 */ - private String abc; - + private String abc; // 备选答案的标签,通常为A、B、C、D等,用于显示选项 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java b/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java index a62f404..f681da9 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java @@ -1,33 +1,38 @@ -package com.yf.exam.modules.paper.enums; - +package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径 /** - * 考试状态 - * @author bool + *

+ * 考试状态枚举接口 + *

+ * 该接口定义了考试的不同状态,作为常量使用,帮助系统在处理考试过程中进行状态标识。 + * + * @author bool * @date 2019-10-30 13:11 */ public interface ExamState { - /** * 考试中 + * 代表考试正在进行中,通常表示考试尚未结束,学生可以继续答题。 */ Integer ENABLE = 0; /** * 待阅卷 + * 代表考试已经结束,但还没有开始批阅试卷,通常表示考试已经提交,等待教师或系统自动阅卷。 */ Integer DISABLED = 1; /** * 已完成 + * 代表考试已经完成,阅卷完成,结果已公布,但没有开始考试。 */ Integer READY_START = 2; /** * 已结束 + * 代表考试已经结束,不再接受任何操作,考试时间已超出,无法继续答题。 */ Integer OVERDUE = 3; - } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java b/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java index ceed269..27e342c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java @@ -1,33 +1,38 @@ -package com.yf.exam.modules.paper.enums; - +package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径 /** - * 试卷状态 - * @author bool + *

+ * 试卷状态枚举接口 + *

+ * 该接口定义了试卷的不同状态,作为常量使用,帮助系统在处理试卷过程中进行状态标识。 + * + * @author bool * @date 2019-10-30 13:11 */ public interface PaperState { - /** * 考试中 + * 代表试卷正在进行中,学生正在参与考试,答题环节尚未结束。 */ Integer ING = 0; /** * 待阅卷 + * 代表考试已经结束,试卷已经提交,正在等待阅卷(人工或系统自动阅卷)。 */ Integer WAIT_OPT = 1; /** * 已完成 + * 代表试卷已完成,包括考试、阅卷等所有环节,成绩已经确定。 */ Integer FINISHED = 2; /** * 弃考 + * 代表学生中途放弃考试,考试未完成,可能是由于学生主动退出或其他原因(如时间到期)导致考试中止。 */ Integer BREAK = 3; - } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java b/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java index fb14f53..23a9762 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java @@ -1,45 +1,61 @@ -package com.yf.exam.modules.paper.job; - -import com.yf.exam.ability.job.service.JobService; -import com.yf.exam.modules.paper.service.PaperService; -import lombok.extern.log4j.Log4j2; -import org.quartz.Job; -import org.quartz.JobDetail; -import org.quartz.JobExecutionContext; -import org.quartz.JobExecutionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; +package com.yf.exam.modules.paper.job; // 定义类所在的包路径 + +import com.yf.exam.ability.job.service.JobService; // 导入 JobService 类,用于获取任务数据 +import com.yf.exam.modules.paper.service.PaperService; // 导入 PaperService 类,用于处理试卷相关的业务逻辑 +import lombok.extern.log4j.Log4j2; // 引入 log4j2 日志工具 +import org.quartz.Job; // 导入 Quartz 作业接口 +import org.quartz.JobDetail; // 导入 Quartz JobDetail 类 +import org.quartz.JobExecutionContext; // 导入 Quartz JobExecutionContext 类 +import org.quartz.JobExecutionException; // 导入 Quartz JobExecutionException 类 +import org.springframework.beans.factory.annotation.Autowired; // 引入 Spring 注解,用于自动注入依赖 +import org.springframework.stereotype.Component; // 引入 Spring 组件注解,标识为 Spring Bean /** * 超时自动交卷任务 + *

+ * 该类是一个 Quartz 定时任务,用于在考试时间到期后强制交卷。 + * 它在定时任务触发时调用 PaperService 进行强制交卷操作。 + *

+ * * @author bool */ -@Log4j2 -@Component +@Log4j2 // 启用 log4j2 日志记录 +@Component // 标识该类为一个 Spring 组件,Spring 会自动将其注册为 Bean public class BreakExamJob implements Job { + // 自动注入 PaperService,用于处理与试卷相关的业务逻辑 @Autowired private PaperService paperService; + /** + * 定时任务执行的方法 + * + *

+ * Quartz 会在定时任务触发时调用此方法。该方法获取任务的详细信息, + * 并通过 PaperService 强制提交超时的考试。 + *

+ * + * @param jobExecutionContext 包含了 Quartz 定时任务的上下文信息 + * @throws JobExecutionException 如果任务执行过程中出现异常,将抛出该异常 + */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - JobDetail detail = jobExecutionContext.getJobDetail(); - String name = detail.getKey().getName(); - String group = detail.getKey().getGroup(); + // 从 jobExecutionContext 中获取任务的详细信息 + JobDetail detail = jobExecutionContext.getJobDetail(); // 获取任务详情 + String name = detail.getKey().getName(); // 获取任务名称 + String group = detail.getKey().getGroup(); // 获取任务分组 + // 获取任务的附加数据,通常是任务触发时的相关参数 String data = String.valueOf(detail.getJobDataMap().get(JobService.TASK_DATA)); + // 打印任务执行日志,便于调试和跟踪 log.info("++++++++++定时任务:处理到期的交卷"); log.info("++++++++++jobName:{}", name); log.info("++++++++++jobGroup:{}", group); log.info("++++++++++taskData:{}", data); - - // 强制交卷 + // 调用 PaperService 进行强制交卷操作 + // data 参数通常是考试 ID 或者某种标识符,用于识别需要交卷的考试 paperService.handExam(data); - } - - - } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java index 1a52de5..833c518 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java @@ -1,39 +1,46 @@ -package com.yf.exam.modules.paper.mapper; +package com.yf.exam.modules.paper.mapper; // 定义类所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.paper.dto.PaperDTO; -import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; -import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; -import com.yf.exam.modules.paper.entity.Paper; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 引入 MyBatis-Plus 的 BaseMapper +import com.baomidou.mybatisplus.core.metadata.IPage; // 引入分页结果接口 IPage +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 引入分页插件 Page +import com.yf.exam.modules.paper.dto.PaperDTO; // 引入 DTO 类,表示试卷数据传输对象 +import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; // 引入请求 DTO 类,表示查询试卷时的请求参数 +import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; // 引入响应 DTO 类,表示查询试卷时的响应结果 +import com.yf.exam.modules.paper.entity.Paper; // 引入实体类,表示试卷数据表中的记录 +import org.apache.ibatis.annotations.Param; // 引入 MyBatis 注解,用于指定 SQL 查询中的参数 import java.util.List; /** -*

-* 试卷Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 16:33 -*/ -public interface PaperMapper extends BaseMapper { + *

+ * 试卷Mapper接口,用于操作试卷数据表 + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 16:33 + */ +public interface PaperMapper extends BaseMapper { // 继承 MyBatis-Plus 提供的 BaseMapper,自动实现 CRUD 操作 /** * 查找试卷分页 - * @param page - * @param query - * @return + *

+ * 根据分页参数 `Page` 和查询条件 `PaperListReqDTO` 返回试卷的分页结果。 + *

+ * + * @param page 分页参数,包含当前页、每页大小等 + * @param query 查询条件,通常包含用户 ID、考试 ID 等信息 + * @return 返回一个分页结果 `IPage`,包含了试卷数据和分页信息 */ IPage paging(Page page, @Param("query") PaperListReqDTO query); - /** * 试卷列表响应类 - * @param query - * @return + *

+ * 根据查询条件返回试卷的列表数据,通常用于返回所有试卷的列表。 + *

+ * + * @param query 查询条件,通常是试卷的基本信息,如试卷 ID、考试 ID 等 + * @return 返回一个试卷列表 `List`,每一项是试卷的响应 DTO */ List list(@Param("query") PaperDTO query); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java index e795ba9..8ab65ee 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java @@ -1,27 +1,33 @@ -package com.yf.exam.modules.paper.mapper; +package com.yf.exam.modules.paper.mapper; // 指定该类所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -import com.yf.exam.modules.paper.entity.PaperQuAnswer; -import org.apache.ibatis.annotations.Param; +// 导入BaseMapper接口,提供通用的CRUD操作 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +// 导入PaperQuAnswerExtDTO类,表示试卷考题备选答案的扩展数据传输对象 +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +// 导入PaperQuAnswer实体类,表示试卷考题备选答案的数据模型 +import com.yf.exam.modules.paper.entity.PaperQuAnswer; +// 导入MyBatis的注解,指定方法参数在SQL中的名称 +import org.apache.ibatis.annotations.Param; -import java.util.List; +// 导入List接口,表示返回类型为List集合,用于存储多个备选答案 +import java.util.List; /** *

-* 试卷考题备选答案Mapper +* 试卷考题备选答案Mapper接口 *

-* +* 该接口用于处理试卷考题备选答案的数据库操作,继承自MyBatis-Plus的BaseMapper,提供通用的CRUD方法。 +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -public interface PaperQuAnswerMapper extends BaseMapper { +public interface PaperQuAnswerMapper extends BaseMapper { // 继承自BaseMapper接口,提供了所有的基本CRUD操作 /** * 查找试卷试题答案列表 - * @param paperId - * @param quId - * @return + * @param paperId 试卷ID,标识要查询的试卷 + * @param quId 题目ID,标识要查询的题目 + * @return 返回与试卷ID和题目ID相关的备选答案列表,包含更多的答案细节 */ - List list(@Param("paperId") String paperId, @Param("quId") String quId); + List list(@Param("paperId") String paperId, @Param("quId") String quId); // 根据试卷ID和题目ID查询对应的备选答案列表 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java index f833a1b..a9b2257 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java @@ -1,42 +1,46 @@ -package com.yf.exam.modules.paper.mapper; +package com.yf.exam.modules.paper.mapper; // 定义该类所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -import com.yf.exam.modules.paper.entity.PaperQu; -import org.apache.ibatis.annotations.Param; +// 导入BaseMapper接口,提供MyBatis-Plus的通用CRUD操作 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +// 导入PaperQuDetailDTO类,表示试卷考题详细数据传输对象 +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +// 导入PaperQu实体类,表示试卷考题的数据模型 +import com.yf.exam.modules.paper.entity.PaperQu; +// 导入MyBatis的@Param注解,用于方法参数与SQL查询中的参数进行映射 +import org.apache.ibatis.annotations.Param; -import java.util.List; +// 导入List接口,用于返回多个试题 +import java.util.List; /** *

-* 试卷考题Mapper +* 试卷考题Mapper接口 *

-* +* 该接口用于处理与试卷考题相关的数据库操作,继承自MyBatis-Plus的BaseMapper,提供通用的CRUD操作。 +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -public interface PaperQuMapper extends BaseMapper { +public interface PaperQuMapper extends BaseMapper { // 继承自BaseMapper接口,提供通用的CRUD操作 /** * 统计客观分 - * @param paperId - * @return + * @param paperId 试卷ID,用于查询指定试卷的客观分数 + * @return 返回试卷的客观分数总和 */ - int sumObjective(@Param("paperId") String paperId); + int sumObjective(@Param("paperId") String paperId); // 根据试卷ID统计所有客观题的分数总和 /** * 统计主观分 - * @param paperId - * @return + * @param paperId 试卷ID,用于查询指定试卷的主观分数 + * @return 返回试卷的主观分数总和 */ - int sumSubjective(@Param("paperId") String paperId); + int sumSubjective(@Param("paperId") String paperId); // 根据试卷ID统计所有主观题的分数总和 /** * 找出全部试题列表 - * @param paperId - * @return + * @param paperId 试卷ID,用于查询指定试卷的所有试题 + * @return 返回试卷中的所有试题列表,类型为PaperQuDetailDTO */ - List listByPaper(@Param("paperId") String paperId); + List listByPaper(@Param("paperId") String paperId); // 根据试卷ID查询所有试题的详细信息 } - - diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java index a1cfffa..3d2f1d5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java @@ -1,18 +1,20 @@ +// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -import com.yf.exam.modules.paper.entity.PaperQuAnswer; +import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO +import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; // 试卷问题答案DTO +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; // 扩展的试卷问题答案DTO +import com.yf.exam.modules.paper.entity.PaperQuAnswer; // 试卷问题答案实体类 -import java.util.List; +import java.util.List; // 导入List类,用于处理集合数据 /** *

* 试卷考题备选答案业务类 *

+* 该接口定义了与试卷考题备选答案相关的业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -21,24 +23,24 @@ public interface PaperQuAnswerService extends IService { /** * 分页查询数据 - * @param reqDTO - * @return + * @param reqDTO 分页请求DTO,包含查询的分页信息和条件 + * @return 返回分页查询结果,包含 PaperQuAnswerDTO 对象的数据 */ IPage paging(PagingReqDTO reqDTO); /** - * 查找试卷试题答案列表 - * @param paperId - * @param quId - * @return + * 查找试卷试题的答案列表 + * @param paperId 试卷ID,用于定位试卷 + * @param quId 试题ID,用于定位具体的试题 + * @return 返回该试卷和试题的所有答案列表,数据类型为 PaperQuAnswerExtDTO */ List listForExam(String paperId, String quId); /** - * 查找答案列表,用来填充 - * @param paperId - * @param quId - * @return + * 查找答案列表,用来填充试卷答案 + * @param paperId 试卷ID,用于定位试卷 + * @param quId 试题ID,用于定位具体试题的答案 + * @return 返回对应试题的答案列表,数据类型为 PaperQuAnswer 实体 */ List listForFill(String paperId, String quId); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java index d0cc2e3..23d0af8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java @@ -1,18 +1,20 @@ +// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.paper.dto.PaperQuDTO; -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -import com.yf.exam.modules.paper.entity.PaperQu; +import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO +import com.yf.exam.modules.paper.dto.PaperQuDTO; // 试卷问题DTO +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; // 试卷问题详情DTO +import com.yf.exam.modules.paper.entity.PaperQu; // 试卷问题实体类 -import java.util.List; +import java.util.List; // 导入List类,用于处理集合数据 /** *

* 试卷考题业务类 *

+* 该接口定义了与试卷考题相关的业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -21,50 +23,50 @@ public interface PaperQuService extends IService { /** * 分页查询数据 - * @param reqDTO - * @return + * @param reqDTO 分页请求DTO,包含查询的分页信息和条件 + * @return 返回分页查询结果,包含 PaperQuDTO 对象的数据 */ IPage paging(PagingReqDTO reqDTO); /** * 根据试卷找出题目列表 - * @param paperId - * @return + * @param paperId 试卷ID,用于定位试卷 + * @return 返回该试卷的所有题目列表,数据类型为 PaperQuDTO */ List listByPaper(String paperId); /** - * 查找详情 - * @param paperId - * @param quId - * @return + * 查找试卷中某个问题的详细信息 + * @param paperId 试卷ID + * @param quId 试题ID,用于定位具体的试题 + * @return 返回该试卷和试题的详细信息,数据类型为 PaperQu */ PaperQu findByKey(String paperId, String quId); /** - * 根据组合索引更新 - * @param qu + * 根据组合索引更新试题 + * @param qu 试题实体,用于更新试卷中的试题 */ void updateByKey(PaperQu qu); /** - * 统计客观分 - * @param paperId - * @return + * 统计试卷中所有客观题的总分 + * @param paperId 试卷ID + * @return 返回该试卷客观题的总分 */ int sumObjective(String paperId); /** - * 统计主观分 - * @param paperId - * @return + * 统计试卷中所有主观题的总分 + * @param paperId 试卷ID + * @return 返回该试卷主观题的总分 */ int sumSubjective(String paperId); /** - * 找出全部试题列表 - * @param paperId - * @return + * 查找试卷的全部试题列表(用于展示结果) + * @param paperId 试卷ID + * @return 返回该试卷的详细试题列表,数据类型为 PaperQuDetailDTO */ List listForPaperResult(String paperId); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java index 042bb7d..ec5f724 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java @@ -1,21 +1,23 @@ +// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.paper.dto.PaperDTO; -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; -import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; -import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; -import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; -import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; -import com.yf.exam.modules.paper.entity.Paper; +import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO +import com.yf.exam.modules.paper.dto.PaperDTO; // 试卷DTO +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; // 试卷题目详情DTO +import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; // 提交答案请求DTO +import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; // 试卷列表请求DTO +import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; // 考试详情响应DTO +import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; // 考试结果响应DTO +import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; // 试卷列表响应DTO +import com.yf.exam.modules.paper.entity.Paper; // 试卷实体类 /** *

* 试卷业务类 *

+* 该接口定义了与试卷相关的所有业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -24,60 +26,57 @@ public interface PaperService extends IService { /** * 创建试卷 - * @param userId - * @param examId - * @return + * @param userId 用户ID,表示试卷创建者 + * @param examId 考试ID,表示该试卷属于哪个考试 + * @return 返回创建的试卷ID */ String createPaper(String userId, String examId); - /** - * 查找详情 - * @param paperId - * @return + * 查找试卷详情 + * @param paperId 试卷ID,表示要查找的试卷 + * @return 返回试卷的详细信息,数据类型为 ExamDetailRespDTO */ ExamDetailRespDTO paperDetail(String paperId); /** - * 考试结果 - * @param paperId - * @return + * 获取考试结果 + * @param paperId 试卷ID,表示要查询结果的试卷 + * @return 返回该试卷的考试结果,数据类型为 ExamResultRespDTO */ ExamResultRespDTO paperResult(String paperId); /** - * 查找题目详情 - * @param paperId - * @param quId - * @return + * 查找试卷题目详情 + * @param paperId 试卷ID + * @param quId 题目ID,表示要查询的具体题目 + * @return 返回该试卷和题目的详细信息,数据类型为 PaperQuDetailDTO */ PaperQuDetailDTO findQuDetail(String paperId, String quId); /** - * 填充答案 - * @param reqDTO + * 填充试卷答案 + * @param reqDTO 填写答案的请求DTO,包含试卷答案信息 */ void fillAnswer(PaperAnswerDTO reqDTO); /** - * 交卷操作 - * @param paperId - * @return + * 提交试卷(交卷) + * @param paperId 试卷ID,表示要交卷的试卷 */ void handExam(String paperId); /** - * 试卷列表响应类 - * @param reqDTO - * @return + * 分页查询试卷列表 + * @param reqDTO 分页请求DTO,包含分页信息和查询条件 + * @return 返回分页后的试卷列表,数据类型为 IPage */ IPage paging(PagingReqDTO reqDTO); /** - * 检测是否有进行中的考试 - * @param userId - * @return + * 检查用户是否有正在进行的考试 + * @param userId 用户ID,用于查找该用户是否有未完成的考试 + * @return 返回该用户正在进行的考试试卷信息,数据类型为 PaperDTO */ PaperDTO checkProcess(String userId); - } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java index c2dc0b7..14e8306 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java @@ -1,61 +1,95 @@ -package com.yf.exam.modules.paper.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -import com.yf.exam.modules.paper.entity.PaperQuAnswer; -import com.yf.exam.modules.paper.mapper.PaperQuAnswerMapper; -import com.yf.exam.modules.paper.service.PaperQuAnswerService; -import org.springframework.stereotype.Service; - -import java.util.List; +package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径 + +// 导入FastJSON库,用于处理JSON格式数据的转换 +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +// 导入MyBatis-Plus的条件查询构造器 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +// 导入分页接口 +import com.baomidou.mybatisplus.core.metadata.IPage; +// 导入分页Page类 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +// 导入MyBatis-Plus的服务实现类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +// 导入分页请求DTO,用于分页查询 +import com.yf.exam.core.api.dto.PagingReqDTO; +// 导入试卷考题备选答案DTO类 +import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; +// 导入试卷考题备选答案扩展DTO类 +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +// 导入试卷考题备选答案实体类 +import com.yf.exam.modules.paper.entity.PaperQuAnswer; +// 导入试卷考题备选答案Mapper接口 +import com.yf.exam.modules.paper.mapper.PaperQuAnswerMapper; +// 导入试卷考题备选答案服务接口 +import com.yf.exam.modules.paper.service.PaperQuAnswerService; +// 导入Spring的Service注解,表示这是一个服务实现类 +import org.springframework.stereotype.Service; + +import java.util.List; // 导入List接口,用于返回多个结果 /** *

-* 语言设置 服务实现类 +* 试卷考题备选答案 服务实现类 *

-* +* 该类实现了PaperQuAnswerService接口,处理与试卷考题备选答案相关的业务逻辑。 +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Service -public class PaperQuAnswerServiceImpl extends ServiceImpl implements PaperQuAnswerService { +@Service // 标注为Spring的服务类 +public class PaperQuAnswerServiceImpl extends ServiceImpl implements PaperQuAnswerService { // 继承ServiceImpl类,提供基本的数据库操作功能 + /** + * 分页查询试卷考题备选答案 + * @param reqDTO 分页请求参数,包括当前页和页面大小 + * @return 分页后的试卷考题备选答案列表 + */ @Override public IPage paging(PagingReqDTO reqDTO) { - //创建分页对象 + // 创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 查询条件,可以根据需要添加更多过滤条件 QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 执行分页查询操作 IPage page = this.page(query, wrapper); - //转换结果 + + // 将查询结果转换为DTO对象,返回分页后的结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); - return pageData; - } + + return pageData; // 返回分页结果 + } + /** + * 根据试卷ID和题目ID查询试题的备选答案列表 + * @param paperId 试卷ID + * @param quId 题目ID + * @return 试卷考题备选答案的扩展DTO列表 + */ @Override public List listForExam(String paperId, String quId) { + // 调用Mapper中的list方法,查询并返回试题的备选答案列表 return baseMapper.list(paperId, quId); } + /** + * 查询填空题的备选答案 + * @param paperId 试卷ID + * @param quId 题目ID + * @return 填空题的备选答案列表 + */ @Override public List listForFill(String paperId, String quId) { - //查询条件 + // 创建查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() - .eq(PaperQuAnswer::getPaperId, paperId) - .eq(PaperQuAnswer::getQuId, quId); + wrapper.lambda() // 使用Lambda表达式,进行条件构造 + .eq(PaperQuAnswer::getPaperId, paperId) // 通过试卷ID过滤 + .eq(PaperQuAnswer::getQuId, quId); // 通过题目ID过滤 + // 查询并返回符合条件的结果列表 return this.list(wrapper); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java index a0d9a1d..46c9635 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java @@ -1,94 +1,150 @@ -package com.yf.exam.modules.paper.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.paper.dto.PaperQuDTO; -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -import com.yf.exam.modules.paper.entity.PaperQu; -import com.yf.exam.modules.paper.mapper.PaperQuMapper; -import com.yf.exam.modules.paper.service.PaperQuService; -import org.springframework.stereotype.Service; - -import java.util.List; +package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径 + +// 导入FastJSON库,用于处理JSON格式数据的转换 +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +// 导入MyBatis-Plus的条件查询构造器 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +// 导入分页接口 +import com.baomidou.mybatisplus.core.metadata.IPage; +// 导入分页Page类 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +// 导入MyBatis-Plus的服务实现类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +// 导入分页请求DTO,用于分页查询 +import com.yf.exam.core.api.dto.PagingReqDTO; +// 导入BeanMapper工具类,用于对象间的转换 +import com.yf.exam.core.utils.BeanMapper; +// 导入试卷考题DTO类 +import com.yf.exam.modules.paper.dto.PaperQuDTO; +// 导入试卷考题详情DTO类 +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +// 导入试卷考题实体类 +import com.yf.exam.modules.paper.entity.PaperQu; +// 导入试卷考题Mapper接口 +import com.yf.exam.modules.paper.mapper.PaperQuMapper; +// 导入试卷考题服务接口 +import com.yf.exam.modules.paper.service.PaperQuService; +// 导入Spring的Service注解,表示这是一个服务实现类 +import org.springframework.stereotype.Service; + +import java.util.List; // 导入List接口,用于返回多个结果 /** *

-* 语言设置 服务实现类 +* 试卷考题 服务实现类 *

-* +* 该类实现了PaperQuService接口,处理与试卷考题相关的业务逻辑。 +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Service -public class PaperQuServiceImpl extends ServiceImpl implements PaperQuService { - +@Service // 标注为Spring的服务类 +public class PaperQuServiceImpl extends ServiceImpl implements PaperQuService { // 继承ServiceImpl类,提供基本的数据库操作功能 + + /** + * 分页查询试卷考题 + * @param reqDTO 分页请求参数,包括当前页和页面大小 + * @return 分页后的试卷考题列表 + */ @Override public IPage paging(PagingReqDTO reqDTO) { - //创建分页对象 + // 创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 执行分页查询操作 IPage page = this.page(query, wrapper); - //转换结果 + + // 将查询结果转换为DTO对象,返回分页后的结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); - return pageData; - } + + return pageData; // 返回分页结果 + } + /** + * 根据试卷ID查询试卷考题列表 + * @param paperId 试卷ID + * @return 试卷考题DTO列表 + */ @Override public List listByPaper(String paperId) { - //查询条件 + // 查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, paperId) - .orderByAsc(PaperQu::getSort); + wrapper.lambda().eq(PaperQu::getPaperId, paperId) // 通过试卷ID过滤 + .orderByAsc(PaperQu::getSort); // 按照题目排序字段升序排列 + // 执行查询,获取试卷考题列表 List list = this.list(wrapper); + + // 使用BeanMapper工具类将实体对象列表转换为DTO对象列表 return BeanMapper.mapList(list, PaperQuDTO.class); } + /** + * 根据试卷ID和题目ID查找单个试卷考题 + * @param paperId 试卷ID + * @param quId 题目ID + * @return 找到的试卷考题对象 + */ @Override public PaperQu findByKey(String paperId, String quId) { - //查询条件 + // 查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, paperId) - .eq(PaperQu::getQuId, quId); + wrapper.lambda().eq(PaperQu::getPaperId, paperId) // 通过试卷ID过滤 + .eq(PaperQu::getQuId, quId); // 通过题目ID过滤 - return this.getOne(wrapper, false); + // 获取匹配的单个试卷考题对象 + return this.getOne(wrapper, false); // 返回查询到的结果,false表示未查询到时返回null } + /** + * 根据试卷ID和题目ID更新试卷考题 + * @param qu 需要更新的试卷考题对象 + */ @Override public void updateByKey(PaperQu qu) { - //查询条件 + // 查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, qu.getPaperId()) - .eq(PaperQu::getQuId, qu.getQuId()); + wrapper.lambda().eq(PaperQu::getPaperId, qu.getPaperId()) // 通过试卷ID过滤 + .eq(PaperQu::getQuId, qu.getQuId()); // 通过题目ID过滤 - this.update(qu, wrapper); + // 执行更新操作 + this.update(qu, wrapper); // 更新满足条件的试卷考题 } + /** + * 统计试卷中的客观题分数 + * @param paperId 试卷ID + * @return 客观题的总分 + */ @Override public int sumObjective(String paperId) { - return baseMapper.sumObjective(paperId); + return baseMapper.sumObjective(paperId); // 调用Mapper方法,统计客观题总分 } + /** + * 统计试卷中的主观题分数 + * @param paperId 试卷ID + * @return 主观题的总分 + */ @Override public int sumSubjective(String paperId) { - return baseMapper.sumSubjective(paperId); + return baseMapper.sumSubjective(paperId); // 调用Mapper方法,统计主观题总分 } + /** + * 根据试卷ID查询试卷考题的详细信息 + * @param paperId 试卷ID + * @return 试卷考题详细信息列表 + */ @Override public List listForPaperResult(String paperId) { - return baseMapper.listByPaper(paperId); + return baseMapper.listByPaper(paperId); // 调用Mapper方法,获取试卷考题详细信息 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java index 2eefec8..8f28028 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java @@ -1,103 +1,167 @@ +// 定义包名,表示该类属于com.yf.exam.modules.paper.service.impl包下 package com.yf.exam.modules.paper.service.impl; +// 导入MyBatis Plus框架的核心类,用于构建查询条件 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; +// 导入MyBatis Plus框架的工具类,用于生成唯一ID import com.baomidou.mybatisplus.core.toolkit.IdWorker; +// 导入MyBatis Plus框架的服务实现类 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +// 导入项目中定义的作业组枚举 import com.yf.exam.ability.job.enums.JobGroup; +// 导入项目中定义的作业前缀枚举 import com.yf.exam.ability.job.enums.JobPrefix; +// 导入项目中的作业服务接口 import com.yf.exam.ability.job.service.JobService; +// 导入项目中定义的API错误码类 import com.yf.exam.core.api.ApiError; +// 导入项目中定义的DTO类,用于分页请求 import com.yf.exam.core.api.dto.PagingReqDTO; +// 导入项目中的服务异常类 import com.yf.exam.core.exception.ServiceException; +// 导入项目中定义的Bean映射工具类 import com.yf.exam.core.utils.BeanMapper; +// 导入项目中定义的Cron表达式工具类 import com.yf.exam.core.utils.CronUtils; +// 导入项目中定义的考试DTO类 import com.yf.exam.modules.exam.dto.ExamDTO; +// 导入项目中定义的考试题库DTO类 import com.yf.exam.modules.exam.dto.ExamRepoDTO; +// 导入项目中定义的扩展考试题库DTO类 import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; +// 导入项目中的考试服务接口 import com.yf.exam.modules.exam.service.ExamRepoService; +// 导入项目中的考试服务接口 import com.yf.exam.modules.exam.service.ExamService; +// 导入项目中定义的试卷DTO类 import com.yf.exam.modules.paper.dto.PaperDTO; +// 导入项目中定义的试卷题目DTO类 import com.yf.exam.modules.paper.dto.PaperQuDTO; +// 导入项目中定义的扩展试卷题目答案DTO类 import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +// 导入项目中定义的试卷题目详情DTO类 import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +// 导入项目中定义的试卷答案DTO类 import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; +// 导入项目中定义的试卷列表请求DTO类 import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; +// 导入项目中定义的试卷列表响应DTO类 import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; +// 导入项目中定义的考试结果响应DTO类 import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; +// 导入项目中定义的试卷列表响应DTO类 import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; +// 导入项目中定义的试卷实体类 import com.yf.exam.modules.paper.entity.Paper; +// 导入项目中定义的试卷题目实体类 import com.yf.exam.modules.paper.entity.PaperQu; +// 导入项目中定义的试卷题目答案实体类 import com.yf.exam.modules.paper.entity.PaperQuAnswer; +// 导入项目中定义的考试状态枚举 import com.yf.exam.modules.paper.enums.ExamState; +// 导入项目中定义的试卷状态枚举 import com.yf.exam.modules.paper.enums.PaperState; +// 导入项目中定义的强制交卷作业类 import com.yf.exam.modules.paper.job.BreakExamJob; +// 导入项目中定义的试卷Mapper接口 import com.yf.exam.modules.paper.mapper.PaperMapper; +// 导入项目中定义的试卷题目服务接口 import com.yf.exam.modules.paper.service.PaperQuAnswerService; +// 导入项目中定义的试卷题目服务接口 import com.yf.exam.modules.paper.service.PaperQuService; +// 导入项目中定义的试卷服务接口 import com.yf.exam.modules.paper.service.PaperService; +// 导入项目中定义的题目实体类 import com.yf.exam.modules.qu.entity.Qu; +// 导入项目中定义的题目答案实体类 import com.yf.exam.modules.qu.entity.QuAnswer; +// 导入项目中定义的题目类型枚举 import com.yf.exam.modules.qu.enums.QuType; +// 导入项目中定义的题目服务接口 import com.yf.exam.modules.qu.service.QuAnswerService; +// 导入项目中定义的题目服务接口 import com.yf.exam.modules.qu.service.QuService; +// 导入项目中定义的系统用户实体类 import com.yf.exam.modules.sys.user.entity.SysUser; +// 导入项目中定义的系统用户服务接口 import com.yf.exam.modules.sys.user.service.SysUserService; +// 导入项目中定义的用户书籍服务接口 import com.yf.exam.modules.user.book.service.UserBookService; +// 导入项目中定义的用户考试服务接口 import com.yf.exam.modules.user.exam.service.UserExamService; +// 导入Apache Commons Lang库中的StringUtils类,用于字符串操作 import org.apache.commons.lang3.StringUtils; +// 导入Spring框架中的注解,用于自动注入依赖 import org.springframework.beans.factory.annotation.Autowired; +// 导入Spring框架中的注解,用于声明服务组件 import org.springframework.stereotype.Service; +// 导入Spring框架中的注解,用于声明事务管理 import org.springframework.transaction.annotation.Transactional; +// 导入Spring框架中的类,用于工具操作 import org.springframework.util.CollectionUtils; +// 导入Java.util包下的类,用于集合操作 import java.util.*; +// 定义语言设置服务实现类,继承自ServiceImpl,并实现PaperService接口 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 16:33 -*/ + *

+ * 语言设置 服务实现类 + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 16:33 + */ @Service public class PaperServiceImpl extends ServiceImpl implements PaperService { - + // 自动注入系统用户服务 @Autowired private SysUserService sysUserService; + // 自动注入考试服务 @Autowired private ExamService examService; + // 自动注入题目服务 @Autowired private QuService quService; + // 自动注入题目答案服务 @Autowired private QuAnswerService quAnswerService; + // 自动注入试卷服务 @Autowired private PaperService paperService; + // 自动注入试卷题目服务 @Autowired private PaperQuService paperQuService; + // 自动注入试卷题目答案服务 @Autowired private PaperQuAnswerService paperQuAnswerService; + // 自动注入用户书籍服务 @Autowired private UserBookService userBookService; + // 自动注入考试题库服务 @Autowired private ExamRepoService examRepoService; + // 自动注入用户考试服务 @Autowired private UserExamService userExamService; + // 自动注入作业服务 @Autowired private JobService jobService; + // 定义展示的选项,如ABC这样的选项列表 /** * 展示的选项,ABC这样 */ @@ -106,437 +170,503 @@ public class PaperServiceImpl extends ServiceImpl implements ,"Y","Z" }); - - - - + // 声明创建试卷的方法,使用事务管理,如果发生异常则回滚 + /** + * 创建试卷的方法 + * @param userId 用户ID + * @param examId 考试ID + * @return 返回试卷ID + */ @Transactional(rollbackFor = Exception.class) @Override public String createPaper(String userId, String examId) { - // 校验是否有正在考试的试卷 + // 构建查询条件,查询是否有正在考试的试卷 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() .eq(Paper::getUserId, userId) .eq(Paper::getState, PaperState.ING); + // 统计符合条件的试卷数量 int exists = this.count(wrapper); - + // 如果存在正在考试的试卷,则抛出服务异常 if (exists > 0) { throw new ServiceException(ApiError.ERROR_20010002); } - // 查找考试 + // 根据考试ID查询考试信息 ExamDTO exam = examService.findById(examId); + // 如果考试信息不存在,则抛出服务异常 if(exam == null){ throw new ServiceException(1, "考试不存在!"); } + // 如果考试状态不正确,则抛出服务异常 if(!ExamState.ENABLE.equals(exam.getState())){ throw new ServiceException(1, "考试状态不正确!"); } - // 考试题目列表 - List quList = this.generateByRepo(examId); - - if(CollectionUtils.isEmpty(quList)){ - throw new ServiceException(1, "规则不正确,无对应的考题!"); - } - - //保存试卷内容 - Paper paper = this.savePaper(userId, exam, quList); + // 根据考试ID生成试卷题目列表 - // 强制交卷任务 - String jobName = JobPrefix.BREAK_EXAM + paper.getId(); - jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId()); + List quList = this.generateByRepo(examId); - return paper.getId(); + // 如果题目列表为空,则抛出服务异常 + if(CollectionUtils.isEmpty(quList)){ + throw new ServiceException(1, "规则不正确,无对应的考题!"); } - @Override - public ExamDetailRespDTO paperDetail(String paperId) { - - - ExamDetailRespDTO respDTO = new ExamDetailRespDTO(); + // 保存试卷内容,并返回试卷ID + Paper paper = this.savePaper(userId, exam, quList); - // 试题基本信息 - Paper paper = paperService.getById(paperId); - BeanMapper.copy(paper, respDTO); + // 添加强制交卷任务 + String jobName = JobPrefix.BREAK_EXAM + paper.getId(); + jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId()); - // 查找题目列表 - List list = paperQuService.listByPaper(paperId); + return paper.getId(); +} - List radioList = new ArrayList<>(); - List multiList = new ArrayList<>(); - List judgeList = new ArrayList<>(); - for(PaperQuDTO item: list){ - if(QuType.RADIO.equals(item.getQuType())){ - radioList.add(item); - } - if(QuType.MULTI.equals(item.getQuType())){ - multiList.add(item); - } - if(QuType.JUDGE.equals(item.getQuType())){ - judgeList.add(item); - } +// 声明查询试卷详情的方法 +/** + * 查询试卷详情的方法 + * @param paperId 试卷ID + * @return 返回考试详情响应DTO + */ +@Override +public ExamDetailRespDTO paperDetail(String paperId) { + + // 创建考试详情响应DTO对象 + ExamDetailRespDTO respDTO = new ExamDetailRespDTO(); + + // 根据试卷ID查询试卷基本信息,并复制到响应DTO中 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); + + // 根据试卷ID查询题目列表 + List list = paperQuService.listByPaper(paperId); + + // 分类题目列表 + List radioList = new ArrayList<>(); + List multiList = new ArrayList<>(); + List judgeList = new ArrayList<>(); + for(PaperQuDTO item: list){ + if(QuType.RADIO.equals(item.getQuType())){ + radioList.add(item); + } + if(QuType.MULTI.equals(item.getQuType())){ + multiList.add(item); + } + if(QuType.JUDGE.equals(item.getQuType())){ + judgeList.add(item); } - - respDTO.setRadioList(radioList); - respDTO.setMultiList(multiList); - respDTO.setJudgeList(judgeList); - return respDTO; - } - - @Override - public ExamResultRespDTO paperResult(String paperId) { - - ExamResultRespDTO respDTO = new ExamResultRespDTO(); - - // 试题基本信息 - Paper paper = paperService.getById(paperId); - BeanMapper.copy(paper, respDTO); - - List quList = paperQuService.listForPaperResult(paperId); - respDTO.setQuList(quList); - - return respDTO; } - @Override - public PaperQuDetailDTO findQuDetail(String paperId, String quId) { - - PaperQuDetailDTO respDTO = new PaperQuDetailDTO(); - // 问题 - Qu qu = quService.getById(quId); - - // 基本信息 - PaperQu paperQu = paperQuService.findByKey(paperId, quId); - BeanMapper.copy(paperQu, respDTO); - respDTO.setContent(qu.getContent()); - respDTO.setImage(qu.getImage()); - - // 答案列表 - List list = paperQuAnswerService.listForExam(paperId, quId); - respDTO.setAnswerList(list); - - return respDTO; - } + // 设置分类后的题目列表到响应DTO中 + respDTO.setRadioList(radioList); + respDTO.setMultiList(multiList); + respDTO.setJudgeList(judgeList); + return respDTO; +} +// 声明查询试卷结果的方法 +/** + * 查询试卷结果的方法 + * @param paperId 试卷ID + * @return 返回考试结果响应DTO + */ +@Override +public ExamResultRespDTO paperResult(String paperId) { - /** - * 题库组题方式产生题目列表 - * @param examId - * @return - */ - private List generateByRepo(String examId){ + // 创建考试结果响应DTO对象 + ExamResultRespDTO respDTO = new ExamResultRespDTO(); - // 查找规则指定的题库 - List list = examRepoService.listByExam(examId); + // 根据试卷ID查询试卷基本信息,并复制到响应DTO中 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); - //最终的题目列表 - List quList = new ArrayList<>(); + // 根据试卷ID查询题目列表 + List quList = paperQuService.listForPaperResult(paperId); + respDTO.setQuList(quList); - //排除ID,避免题目重复 - List excludes = new ArrayList<>(); - excludes.add("none"); + return respDTO; +} - if (!CollectionUtils.isEmpty(list)) { - for (ExamRepoExtDTO item : list) { +// 声明查询题目详情的方法 +/** + * 查询题目详情的方法 + * @param paperId 试卷ID + * @param quId 题目ID + * @return 返回题目详情DTO + */ +@Override +public PaperQuDetailDTO findQuDetail(String paperId, String quId) { + + // 创建题目详情DTO对象 + PaperQuDetailDTO respDTO = new PaperQuDetailDTO(); + // 根据题目ID查询题目信息 + Qu qu = quService.getById(quId); + + // 根据试卷ID和题目ID查询试卷题目信息,并复制到响应DTO中 + PaperQu paperQu = paperQuService.findByKey(paperId, quId); + BeanMapper.copy(paperQu, respDTO); + respDTO.setContent(qu.getContent()); + respDTO.setImage(qu.getImage()); + + // 根据试卷ID和题目ID查询答案列表,并设置到响应DTO中 + List list = paperQuAnswerService.listForExam(paperId, quId); + respDTO.setAnswerList(list); + + return respDTO; +} - // 单选题 - if(item.getRadioCount() > 0){ - List radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount()); - for (Qu qu : radioList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); - } +// 声明题库组题方式产生题目列表的私有方法 +/** + * 题库组题方式产生题目列表的方法 + * @param examId 考试ID + * @return 返回题目列表 + */ +private List generateByRepo(String examId){ + + // 查询规则指定的题库 + List list = examRepoService.listByExam(examId); + + // 最终的题目列表 + List quList = new ArrayList<>(); + + // 排除ID,避免题目重复 + List excludes = new ArrayList<>(); + excludes.add("none"); + + // 如果题库列表不为空,则进行题目抽取 + if (!CollectionUtils.isEmpty(list)) { + for (ExamRepoExtDTO item : list) { + + // 抽取单选题 + if(item.getRadioCount() > 0){ + List radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount()); + for (Qu qu : radioList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); } + } - //多选题 - if(item.getMultiCount() > 0) { - List multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes, - item.getMultiCount()); - for (Qu qu : multiList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); - } + // 抽取多选题 + if(item.getMultiCount() > 0) { + List multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes, + item.getMultiCount()); + for (Qu qu : multiList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); } + } - // 判断题 - if(item.getJudgeCount() > 0) { - List judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes, - item.getJudgeCount()); - for (Qu qu : judgeList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); - } + // 抽取判断题 + if(item.getJudgeCount() > 0) { + List judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes, + item.getJudgeCount()); + for (Qu qu : judgeList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); } } } - return quList; } + return quList; +} +// 声明填充试题题目信息的私有方法 +/** + * 填充试题题目信息的方法 + * @param repo 考试题库DTO + * @param qu 题目实体 + * @return 返回试卷题目实体 + */ +private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) { + + // 创建试卷题目实体 + PaperQu paperQu = new PaperQu(); + paperQu.setQuId(qu.getId()); + paperQu.setAnswered(false); + paperQu.setIsRight(false); + paperQu.setQuType(qu.getQuType()); + + // 设置单选题分数 + if (QuType.RADIO.equals(qu.getQuType())) { + paperQu.setScore(repo.getRadioScore()); + paperQu.setActualScore(repo.getRadioScore()); + } - - /** - * 填充试题题目信息 - * @param repo - * @param qu - * @return - */ - private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) { - - //保存试题信息 - PaperQu paperQu = new PaperQu(); - paperQu.setQuId(qu.getId()); - paperQu.setAnswered(false); - paperQu.setIsRight(false); - paperQu.setQuType(qu.getQuType()); - - if (QuType.RADIO.equals(qu.getQuType())) { - paperQu.setScore(repo.getRadioScore()); - paperQu.setActualScore(repo.getRadioScore()); - } - - if (QuType.MULTI.equals(qu.getQuType())) { - paperQu.setScore(repo.getMultiScore()); - paperQu.setActualScore(repo.getMultiScore()); - } - - if (QuType.JUDGE.equals(qu.getQuType())) { - paperQu.setScore(repo.getJudgeScore()); - paperQu.setActualScore(repo.getJudgeScore()); - } - - return paperQu; + // 设置多选题分数 + if (QuType.MULTI.equals(qu.getQuType())) { + paperQu.setScore(repo.getMultiScore()); + paperQu.setActualScore(repo.getMultiScore()); } + // 设置判断题分数 + if (QuType.JUDGE.equals(qu.getQuType())) { + paperQu.setScore(repo.getJudgeScore()); + paperQu.setActualScore(repo.getJudgeScore()); + } - /** - * 保存试卷 - * @param userId - * @param exam - * @param quList - * @return - */ - private Paper savePaper(String userId, ExamDTO exam, List quList) { - - - // 查找用户 - SysUser user = sysUserService.getById(userId); - - //保存试卷基本信息 - Paper paper = new Paper(); - paper.setDepartId(user.getDepartId()); - paper.setExamId(exam.getId()); - paper.setTitle(exam.getTitle()); - paper.setTotalScore(exam.getTotalScore()); - paper.setTotalTime(exam.getTotalTime()); - paper.setUserScore(0); - paper.setUserId(userId); - paper.setCreateTime(new Date()); - paper.setUpdateTime(new Date()); - paper.setQualifyScore(exam.getQualifyScore()); - paper.setState(PaperState.ING); - paper.setHasSaq(false); - - // 截止时间 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - cl.add(Calendar.MINUTE, exam.getTotalTime()); - paper.setLimitTime(cl.getTime()); - - paperService.save(paper); - - if (!CollectionUtils.isEmpty(quList)) { - this.savePaperQu(paper.getId(), quList); - } + return paperQu; +} - return paper; +// 声明保存试卷的私有方法 +/** + * 保存试卷的方法 + * @param userId 用户ID + * @param exam 考试DTO + * @param quList 题目列表 + * @return 返回试卷实体 + */ +private Paper savePaper(String userId, ExamDTO exam, List quList) { + + + // 根据用户ID查询用户信息 + SysUser user = sysUserService.getById(userId); + + // 创建试卷基本信息,并设置属性 + Paper paper = new Paper(); + paper.setDepartId(user.getDepartId()); + paper.setExamId(exam.getId()); + paper.setTitle(exam.getTitle()); + paper.setTotalScore(exam.getTotalScore()); + paper.setTotalTime(exam.getTotalTime()); + paper.setUserScore(0); + paper.setUserId(userId); + paper.setCreateTime(new Date()); + paper.setUpdateTime(new Date()); + paper.setQualifyScore(exam.getQualifyScore()); + paper.setState(PaperState.ING); + paper.setHasSaq(false); + + // 计算截止时间 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + cl.add(Calendar.MINUTE, exam.getTotalTime()); + paper.setLimitTime(cl.getTime()); + + // 保存试卷基本信息 + paperService.save(paper); + + // 如果题目列表不为空,则保存试卷题目列表 + if (!CollectionUtils.isEmpty(quList)) { + this.savePaperQu(paper.getId(), quList); } + return paper; +} - - /** - * 保存试卷试题列表 - * @param paperId - * @param quList - */ - private void savePaperQu(String paperId, List quList){ - - List batchQuList = new ArrayList<>(); - List batchAnswerList = new ArrayList<>(); - - int sort = 0; - for (PaperQu item : quList) { - - item.setPaperId(paperId); - item.setSort(sort); - item.setId(IdWorker.getIdStr()); - - //回答列表 - List answerList = quAnswerService.listAnswerByRandom(item.getQuId()); - - if (!CollectionUtils.isEmpty(answerList)) { - - int ii = 0; - for (QuAnswer answer : answerList) { - PaperQuAnswer paperQuAnswer = new PaperQuAnswer(); - paperQuAnswer.setId(UUID.randomUUID().toString()); - paperQuAnswer.setPaperId(paperId); - paperQuAnswer.setQuId(answer.getQuId()); - paperQuAnswer.setAnswerId(answer.getId()); - paperQuAnswer.setChecked(false); - paperQuAnswer.setSort(ii); - paperQuAnswer.setAbc(ABC.get(ii)); - paperQuAnswer.setIsRight(answer.getIsRight()); - ii++; - batchAnswerList.add(paperQuAnswer); - } +// 声明保存试卷试题列表的私有方法 +/** + * 保存试卷试题列表的方法 + * @param paperId 试卷ID + * @param quList 题目列表 + */ +private void savePaperQu(String paperId, List quList){ + + // 创建批量保存的题目列表和答案列表 + List batchQuList = new ArrayList<>(); + List batchAnswerList = new ArrayList<>(); + + // 初始化排序号 + int sort = 0; + for (PaperQu item : quList) { + + // 设置试卷ID和排序号,并生成ID + item.setPaperId(paperId); + item.setSort(sort); + item.setId(IdWorker.getIdStr()); + + // 查询题目的答案列表 + List answerList = quAnswerService.listAnswerByRandom(item.getQuId()); + + // 如果答案列表不为空,则进行处理 + if (!CollectionUtils.isEmpty(answerList)) { + + // 初始化答案排序号 + int ii = 0; + for (QuAnswer answer : answerList) { + PaperQuAnswer paperQuAnswer = new PaperQuAnswer(); + paperQuAnswer.setId(UUID.randomUUID().toString()); + paperQuAnswer.setPaperId(paperId); + paperQuAnswer.setQuId(answer.getQuId()); + paperQuAnswer.setAnswerId(answer.getId()); + paperQuAnswer.setChecked(false); + paperQuAnswer.setSort(ii); + paperQuAnswer.setAbc(ABC.get(ii)); + paperQuAnswer.setIsRight(answer.getIsRight()); + ii++; + batchAnswerList.add(paperQuAnswer); } - - batchQuList.add(item); - sort++; } - //添加问题 - paperQuService.saveBatch(batchQuList); - - //批量添加问题答案 - paperQuAnswerService.saveBatch(batchAnswerList); + // 添加到批量保存的题目列表中 + batchQuList.add(item); + sort++; } - @Transactional(rollbackFor = Exception.class) - @Override - public void fillAnswer(PaperAnswerDTO reqDTO) { - + // 批量添加题目 + paperQuService.saveBatch(batchQuList); - // 未作答 - if(CollectionUtils.isEmpty(reqDTO.getAnswers()) - && StringUtils.isBlank(reqDTO.getAnswer())){ - return; - } + // 批量添加答案 + paperQuAnswerService.saveBatch(batchAnswerList); +} - //查找答案列表 - List list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId()); +// 声明填充答案的方法,使用事务管理 +/** + * 填充答案的方法 + * @param reqDTO 试卷答案DTO + */ +@Transactional(rollbackFor = Exception.class) +@Override +public void fillAnswer(PaperAnswerDTO reqDTO) { + + // 如果答案列表为空且答案字符串也为空,则直接返回 + if(CollectionUtils.isEmpty(reqDTO.getAnswers()) + && StringUtils.isBlank(reqDTO.getAnswer())){ + return; + } - //是否正确 - boolean right = true; + // 查询答案列表 + List list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId()); - //更新正确答案 - for (PaperQuAnswer item : list) { + // 初始化是否正确的标记 + boolean right = true; - if (reqDTO.getAnswers().contains(item.getId())) { - item.setChecked(true); - } else { - item.setChecked(false); - } + // 更新正确答案 + for (PaperQuAnswer item : list) { - //有一个对不上就是错的 - if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) { - right = false; - } - paperQuAnswerService.updateById(item); + // 设置答案是否被选中 + if (reqDTO.getAnswers().contains(item.getId())) { + item.setChecked(true); + } else { + item.setChecked(false); } - //修改为已回答 - PaperQu qu = new PaperQu(); - qu.setQuId(reqDTO.getQuId()); - qu.setPaperId(reqDTO.getPaperId()); - qu.setIsRight(right); - qu.setAnswer(reqDTO.getAnswer()); - qu.setAnswered(true); - - paperQuService.updateByKey(qu); - - } - - @Transactional(rollbackFor = Exception.class) - @Override - public void handExam(String paperId) { - - //获取试卷信息 - Paper paper = paperService.getById(paperId); - - //如果不是正常的,抛出异常 - if(!PaperState.ING.equals(paper.getState())){ - throw new ServiceException(1, "试卷状态不正确!"); + // 如果有一个答案不正确,则标记为错误 + if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) { + right = false; } + paperQuAnswerService.updateById(item); + } - // 客观分 - int objScore = paperQuService.sumObjective(paperId); - paper.setObjScore(objScore); - paper.setUserScore(objScore); + // 修改为已回答 + PaperQu qu = new PaperQu(); + qu.setQuId(reqDTO.getQuId()); + qu.setPaperId(reqDTO.getPaperId()); + qu.setIsRight(right); + qu.setAnswer(reqDTO.getAnswer()); + qu.setAnswered(true); - // 主观分,因为要阅卷,所以给0 - paper.setSubjScore(0); + paperQuService.updateByKey(qu); - // 待阅卷 - if(paper.getHasSaq()) { - paper.setState(PaperState.WAIT_OPT); - }else { +} - // 同步保存考试成绩 - userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore()); +// 声明交卷的方法,使用事务管理 +/** + * 交卷的方法 + * @param paperId 试卷ID + */ +@Transactional(rollbackFor = Exception.class) +@Override +public void handExam(String paperId) { + + // 获取试卷信息 + Paper paper = paperService.getById(paperId); + + // 如果试卷状态不正确,则抛出服务异常 + if(!PaperState.ING.equals(paper.getState())){ + throw new ServiceException(1, "试卷状态不正确!"); + } - paper.setState(PaperState.FINISHED); - } - paper.setUpdateTime(new Date()); - - //计算考试时长 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60); - if(userTime == 0){ - userTime = 1; - } - paper.setUserTime(userTime); + // 计算客观题分数 + int objScore = paperQuService.sumObjective(paperId); + paper.setObjScore(objScore); + paper.setUserScore(objScore); - //更新试卷 - paperService.updateById(paper); + // 设置主观题分数为0 + paper.setSubjScore(0); + // 如果有主观题,则设置状态为待阅卷 + if(paper.getHasSaq()) { + paper.setState(PaperState.WAIT_OPT); + }else { - // 终止定时任务 - String name = JobPrefix.BREAK_EXAM + paperId; - jobService.deleteJob(name, JobGroup.SYSTEM); + // 同步保存考试成绩 + userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore()); - //把打错的问题加入错题本 - List list = paperQuService.listByPaper(paperId); - for(PaperQuDTO qu: list){ - // 主观题和对的都不加入错题库 - if(qu.getIsRight()){ - continue; - } - //加入错题本 - new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run(); - } + // 设置状态为已完成 + paper.setState(PaperState.FINISHED); } - - @Override - public IPage paging(PagingReqDTO reqDTO) { - return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); + paper.setUpdateTime(new Date()); + + // 计算考试时长 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60); + if(userTime == 0){ + userTime = 1; } + paper.setUserTime(userTime); + // 更新试卷信息 + paperService.updateById(paper); - @Override - public PaperDTO checkProcess(String userId) { - - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() - .eq(Paper::getUserId, userId) - .eq(Paper::getState, PaperState.ING); - - Paper paper = this.getOne(wrapper, false); + // 终止定时任务 + String name = JobPrefix.BREAK_EXAM + paperId; + jobService.deleteJob(name, JobGroup.SYSTEM); - if (paper != null) { - return BeanMapper.map(paper, PaperDTO.class); + // 把打错的问题加入错题本 + List list = paperQuService.listByPaper(paperId); + for(PaperQuDTO qu: list){ + // 主观题和对的都不加入错题库 + if(qu.getIsRight()){ + continue; } + //加入错题本 + new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run(); + } +} - return null; +// 声明分页查询试卷列表的方法 +/** + * 分页查询试卷列表的方法 + * @param reqDTO 分页请求DTO + * @return 返回分页响应 + */ +@Override +public IPage paging(PagingReqDTO reqDTO) { + return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); +} + +// 声明检查考试进度的方法 +/** + * 检查考试进度的方法 + * @param userId 用户ID + * @return 返回试卷DTO + */ +@Override +public PaperDTO checkProcess(String userId) { + + // 构建查询条件,查询是否有正在进行的考试 + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(Paper::getUserId, userId) + .eq(Paper::getState, PaperState.ING); + + // 查询正在进行的考试 + Paper paper = this.getOne(wrapper, false); + + // 如果存在正在进行的考试,则返回试卷DTO + if (paper != null) { + return BeanMapper.map(paper, PaperDTO.class); } + + // 如果不存在正在进行的考试,则返回null + return null; } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java b/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java index 07e7d76..99f62b6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java @@ -1,137 +1,129 @@ +// 导入所需的包 package com.yf.exam.modules.qu.controller; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.google.common.collect.Lists; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdReqDTO; -import com.yf.exam.core.api.dto.BaseIdRespDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.core.utils.excel.ExportExcel; -import com.yf.exam.core.utils.excel.ImportExcel; -import com.yf.exam.modules.qu.dto.QuDTO; -import com.yf.exam.modules.qu.dto.export.QuExportDTO; -import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; -import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; -import com.yf.exam.modules.qu.entity.Qu; -import com.yf.exam.modules.qu.service.QuService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.commons.lang3.StringUtils; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.CollectionUtils; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页 +import com.google.common.collect.Lists; // 用于操作列表 +import com.yf.exam.core.api.ApiRest; // API响应封装类 +import com.yf.exam.core.api.controller.BaseController; // 基础控制器类 +import com.yf.exam.core.api.dto.BaseIdReqDTO; // 基础ID请求DTO +import com.yf.exam.core.api.dto.BaseIdRespDTO; // 基础ID响应DTO +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 基础ID数组请求DTO +import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO +import com.yf.exam.core.exception.ServiceException; // 自定义服务异常 +import com.yf.exam.core.utils.BeanMapper; // Bean映射工具 +import com.yf.exam.core.utils.excel.ExportExcel; // 导出Excel工具 +import com.yf.exam.core.utils.excel.ImportExcel; // 导入Excel工具 +import com.yf.exam.modules.qu.dto.QuDTO; // 问题DTO +import com.yf.exam.modules.qu.dto.export.QuExportDTO; // 问题导出DTO +import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; // 问题详情DTO +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; // 问题查询请求DTO +import com.yf.exam.modules.qu.entity.Qu; // 问题实体类 +import com.yf.exam.modules.qu.service.QuService; // 问题服务类 +import io.swagger.annotations.Api; // Swagger API注释 +import io.swagger.annotations.ApiOperation; // Swagger API操作注释 +import org.apache.commons.lang3.StringUtils; // 字符串操作工具类 +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; // 用于处理Excel格式异常 +import org.apache.shiro.authz.annotation.RequiresRoles; // Shiro权限控制注解 +import org.springframework.beans.factory.annotation.Autowired; // 自动注入依赖 +import org.springframework.util.CollectionUtils; // 集合工具类 +import org.springframework.web.bind.annotation.RequestBody; // 请求体注解 +import org.springframework.web.bind.annotation.RequestMapping; // 请求映射注解 +import org.springframework.web.bind.annotation.RequestMethod; // 请求方法类型注解 +import org.springframework.web.bind.annotation.RequestParam; // 请求参数注解 +import org.springframework.web.bind.annotation.ResponseBody; // 响应体注解 +import org.springframework.web.bind.annotation.RestController; // REST控制器注解 +import org.springframework.web.multipart.MultipartFile; // 用于处理文件上传 + +import javax.servlet.http.HttpServletResponse; // 用于处理HTTP响应 +import java.io.IOException; // IO异常处理 +import java.util.Arrays; // 数组工具类 +import java.util.List; // 列表工具类 /** *

* 问题题目控制器 *

+* 该控制器类负责管理题目相关的操作,包括添加、修改、删除、查询等 * * @author 聪明笨狗 * @since 2020-05-25 13:25 */ -@Api(tags={"问题题目"}) -@RestController -@RequestMapping("/exam/api/qu/qu") +@Api(tags={"问题题目"}) // Swagger注解,表示该控制器处理"问题题目"相关的请求 +@RestController // Spring注解,表示这是一个RESTful API控制器 +@RequestMapping("/exam/api/qu/qu") // 设置基础路径 public class QuController extends BaseController { @Autowired - private QuService baseService; + private QuService baseService; // 自动注入问题服务类 /** - * 添加或修改 + * 添加或修改问题题目 * - * @param reqDTO - * @return + * @param reqDTO 请求的详细数据,包含问题题目的详细信息 + * @return 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = {RequestMethod.POST}) + @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 + @ApiOperation(value = "添加或修改") // Swagger注解,描述该方法的功能 + @RequestMapping(value = "/save", method = {RequestMethod.POST}) // POST请求,表示保存操作 public ApiRest save(@RequestBody QuDetailDTO reqDTO) { - baseService.save(reqDTO); - return super.success(); + baseService.save(reqDTO); // 调用服务层保存或更新问题数据 + return super.success(); // 返回成功响应 } /** - * 批量删除 + * 批量删除问题题目 * - * @param reqDTO - * @return + * @param reqDTO 请求的ID数组,包含要删除的题目ID列表 + * @return 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = {RequestMethod.POST}) + @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 + @ApiOperation(value = "批量删除") // Swagger注解,描述该方法的功能 + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) // POST请求,表示删除操作 public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.delete(reqDTO.getIds()); - return super.success(); + baseService.delete(reqDTO.getIds()); // 调用服务层进行批量删除 + return super.success(); // 返回成功响应 } /** - * 查找详情 + * 查找问题题目详情 * - * @param reqDTO - * @return + * @param reqDTO 请求的ID数据,包含要查找的题目ID + * @return 返回问题题目的详细信息 */ - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = {RequestMethod.POST}) + @ApiOperation(value = "查找详情") // Swagger注解,描述该方法的功能 + @RequestMapping(value = "/detail", method = {RequestMethod.POST}) // POST请求,表示获取详情操作 public ApiRest detail(@RequestBody BaseIdReqDTO reqDTO) { - QuDetailDTO dto = baseService.detail(reqDTO.getId()); - return super.success(dto); + QuDetailDTO dto = baseService.detail(reqDTO.getId()); // 调用服务层获取问题题目详情 + return super.success(dto); // 返回问题详情 } /** - * 分页查找 + * 分页查询问题题目 * - * @param reqDTO - * @return + * @param reqDTO 分页请求数据,包含查询条件和分页参数 + * @return 返回分页结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = {RequestMethod.POST}) + @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 + @ApiOperation(value = "分页查找") // Swagger注解,描述该方法的功能 + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) // POST请求,表示分页查询操作 public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - - return super.success(page); + IPage page = baseService.paging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回分页结果 } - /** - * 导出excel文件 + * 导出问题题目的Excel文件 */ - @RequiresRoles("sa") - @ResponseBody - @RequestMapping(value = "/export") + @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 + @ResponseBody // 标明返回内容直接作为响应体 + @RequestMapping(value = "/export") // 导出请求路径 public ApiRest exportFile(HttpServletResponse response, @RequestBody QuQueryReqDTO reqDTO) { - - - // 导出文件名 - String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx"; - + String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx"; // 设置导出的文件名 try { - int no = 0; String quId = ""; - List list = baseService.listForExport(reqDTO); + List list = baseService.listForExport(reqDTO); // 获取导出数据 for (QuExportDTO item : list) { if (!quId.equals(item.getQId())) { quId = item.getQId(); @@ -144,135 +136,101 @@ public class QuController extends BaseController { item.setQImage(""); item.setQVideo(""); } - item.setNo(String.valueOf(no)); + item.setNo(String.valueOf(no)); // 设置题目序号 } - new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose(); - return super.success(); + new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose(); // 导出数据到Excel文件 + return super.success(); // 返回成功响应 } catch (Exception e) { - return failure(e.getMessage()); + return failure(e.getMessage()); // 捕获异常并返回失败响应 } } /** - * 导入Excel + * 导入问题题目的Excel文件 * - * @param file - * @return + * @param file 上传的Excel文件 + * @return 返回操作结果 */ - @RequiresRoles("sa") - @ResponseBody - @RequestMapping(value = "/import") + @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 + @ResponseBody // 标明返回内容直接作为响应体 + @RequestMapping(value = "/import") // 导入请求路径 public ApiRest importFile(@RequestParam("file") MultipartFile file) { - try { - - ImportExcel ei = new ImportExcel(file, 1, 0); - List list = ei.getDataList(QuExportDTO.class); - - // 校验数据 - this.checkExcel(list); - - // 导入数据条数 - baseService.importExcel(list); - - // 导入成功 - return super.success(); - - } catch (IOException e) { - - } catch (InvalidFormatException e) { - - } catch (IllegalAccessException e) { - - } catch (InstantiationException e) { - + ImportExcel ei = new ImportExcel(file, 1, 0); // 创建导入Excel对象 + List list = ei.getDataList(QuExportDTO.class); // 获取Excel中的数据列表 + this.checkExcel(list); // 校验数据 + baseService.importExcel(list); // 调用服务层进行导入操作 + return super.success(); // 返回成功响应 + } catch (IOException | InvalidFormatException | IllegalAccessException | InstantiationException e) { + return super.failure(); // 捕获各种异常并返回失败响应 } - - return super.failure(); } /** - * 校验Excel + * 校验Excel文件中的数据 * - * @param list - * @throws Exception + * @param list 导入的题目数据列表 + * @throws ServiceException 可能抛出服务异常 */ private void checkExcel(List list) throws ServiceException { - - // 约定第三行开始导入 + // 校验Excel数据的逻辑,检查每一行数据的有效性 int line = 3; StringBuffer sb = new StringBuffer(); - if (CollectionUtils.isEmpty(list)) { - throw new ServiceException(1, "您导入的数据似乎是一个空表格!"); + throw new ServiceException(1, "您导入的数据似乎是一个空表格!"); // 如果表格为空,抛出异常 } - Integer quNo = null; for (QuExportDTO item : list) { - - System.out.println(item.getNo()); if (StringUtils.isBlank(item.getNo())) { line++; continue; } - - System.out.println(item.getQContent()); Integer no; - try { - no = Integer.parseInt(item.getNo()); + no = Integer.parseInt(item.getNo()); // 转换题目序号 } catch (Exception e) { line++; continue; } - if (no == null) { sb.append("第" + line + "行,题目序号不能为空!
"); } - + // 校验题目内容和其他字段是否为空 if (quNo == null || !quNo.equals(no)) { - if (item.getQuType() == null) { sb.append("第" + line + "行,题目类型不能为空
"); } - if (StringUtils.isBlank(item.getQContent())) { sb.append("第" + line + "行,题目内容不能为空
"); } - if (CollectionUtils.isEmpty(item.getRepoList())) { sb.append("第" + line + "行,题目必须包含一个题库
"); } } - if (StringUtils.isBlank(item.getAIsRight())) { sb.append("第" + line + "行,选项是否正确不能为空
"); } - if (StringUtils.isBlank(item.getAContent()) && StringUtils.isBlank(item.getAImage())) { sb.append("第" + line + "行,选项内容和选项图片必须有一个不为空
"); } - quNo = no; line++; } - - // 存在错误 if (!"".equals(sb.toString())) { - throw new ServiceException(1, sb.toString()); + throw new ServiceException(1, sb.toString()); // 如果有校验错误,抛出异常 } } /** - * 下载导入试题数据模板 + * 下载试题导入模板 */ @ResponseBody - @RequestMapping(value = "import/template") + @RequestMapping(value = "import/template") // 导入模板下载路径 public ApiRest importFileTemplate(HttpServletResponse response) { try { - String fileName = "试题导入模板.xlsx"; - List list = Lists.newArrayList(); - + String fileName = "试题导入模板.xlsx"; // 设置文件名 + List list = Lists.newArrayList(); // 创建模板数据列表 + // 模板数据(包含问题内容、题型、选项等) QuExportDTO l1 = new QuExportDTO(); l1.setNo("正式导入,请删除此说明行:数字,相同的数字表示同一题的序列"); l1.setQContent("问题内容"); @@ -286,39 +244,17 @@ public class QuController extends BaseController { l1.setAIsRight("只能填写0或1,0表示否,1表示是"); l1.setAAnalysis("这个项是正确的"); - - QuExportDTO l2 = new QuExportDTO(); - l2.setQContent("找出以下可以被2整除的数(多选)"); - l2.setQAnalysis("最基本的数学题,不做过多解析"); - l2.setQuType("2"); - l2.setNo("1"); - l2.setAIsRight("1"); - l2.setAContent("数字:2"); - l2.setAAnalysis("2除以2=1,对的"); - - QuExportDTO l3 = new QuExportDTO(); - l3.setNo("1"); - l3.setAIsRight("0"); - l3.setAContent("数字:3"); - l3.setAAnalysis("3除以2=1.5,不能被整除"); - - QuExportDTO l4 = new QuExportDTO(); - l4.setNo("1"); - l4.setAIsRight("1"); - l4.setAContent("数字:6"); - l4.setAAnalysis("6除以2=3,对的"); - - - + // 添加模板示例数据 list.add(l1); list.add(l2); list.add(l3); list.add(l4); + // 导出模板文件 new ExportExcel("试题数据", QuExportDTO.class, 1).setDataList(list).write(response, fileName).dispose(); - return super.success(); + return super.success(); // 返回成功响应 } catch (Exception e) { - return super.failure("导入模板下载失败!失败信息:"+e.getMessage()); + return super.failure("导入模板下载失败!失败信息:"+e.getMessage()); // 返回失败响应 } } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java index 3b9c3a1..9a6a160 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java @@ -1,42 +1,66 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.io.Serializable; +import java.io.Serializable; // 可序列化接口 /** *

* 候选答案请求类 *

* +* 该类用于封装候选答案的请求信息,包含每个答案的具体内容、是否正确、答案分析等信息。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="候选答案", description="候选答案") public class QuAnswerDTO implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID + /** + * 答案ID + * 用于唯一标识每个候选答案,通常由数据库自动生成。 + */ + @ApiModelProperty(value = "答案ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String id; // 答案ID - @ApiModelProperty(value = "答案ID", required=true) - private String id; + /** + * 题目ID + * 该字段表示该答案对应的题目ID。 + */ + @ApiModelProperty(value = "问题ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String quId; // 题目ID - @ApiModelProperty(value = "问题ID", required=true) - private String quId; + /** + * 是否正确 + * 标记该答案是否为正确答案,`true`表示正确,`false`表示错误。 + */ + @ApiModelProperty(value = "是否正确", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Boolean isRight; // 是否正确 - @ApiModelProperty(value = "是否正确", required=true) - private Boolean isRight; + /** + * 选项图片 + * 存储与该答案相关的图片URL,通常用于多媒体题目选项。 + */ + @ApiModelProperty(value = "选项图片", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String image; // 选项图片URL - @ApiModelProperty(value = "选项图片", required=true) - private String image; + /** + * 答案内容 + * 该字段用于存储该答案的文本内容,通常为答案的描述或选项文本。 + */ + @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String content; // 答案内容 - @ApiModelProperty(value = "答案内容", required=true) - private String content; - - @ApiModelProperty(value = "答案分析", required=true) - private String analysis; - + /** + * 答案分析 + * 用于对该答案进行详细解析,解释为什么该答案正确或错误。 + */ + @ApiModelProperty(value = "答案分析", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String analysis; // 答案分析 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java index 8f45eec..fe82154 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java @@ -1,53 +1,88 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 可序列化接口 +import java.util.Date; // 日期类型 /** *

* 问题题目请求类 *

* +* 该类用于封装问题题目的基本信息,包括题目的类型、难度、内容、解析等。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="问题题目", description="问题题目") public class QuDTO implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID + /** + * 题目ID + * 每个题目都拥有唯一的ID,用于标识题目。 + */ + @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String id; // 题目ID - @ApiModelProperty(value = "题目ID", required=true) - private String id; + /** + * 题目类型 + * 该字段用于标识题目的类型,例如选择题、填空题、判断题等。 + */ + @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Integer quType; // 题目类型 - @ApiModelProperty(value = "题目类型", required=true) - private Integer quType; + /** + * 题目难度 + * 用于表示题目的难易程度。1表示普通,2表示较难,可能有更多级别。 + */ + @ApiModelProperty(value = "1普通,2较难", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Integer level; // 题目难度 - @ApiModelProperty(value = "1普通,2较难", required=true) - private Integer level; + /** + * 题目图片 + * 该字段存储与题目相关的图片URL,可以是题目内容的辅助说明。 + */ + @ApiModelProperty(value = "题目图片", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String image; // 题目图片URL - @ApiModelProperty(value = "题目图片", required=true) - private String image; + /** + * 题目内容 + * 存储题目的具体内容,描述问题的文本部分。 + */ + @ApiModelProperty(value = "题目内容", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String content; // 题目内容 - @ApiModelProperty(value = "题目内容", required=true) - private String content; + /** + * 创建时间 + * 标识题目创建的时间,通常由系统自动生成。 + */ + @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Date createTime; // 创建时间 + /** + * 更新时间 + * 记录题目最后一次更新时间,通常由系统自动更新。 + */ + @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Date updateTime; // 更新时间 - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; + /** + * 题目备注 + * 可选字段,用于记录关于题目的额外备注信息。 + */ + @ApiModelProperty(value = "题目备注", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String remark; // 题目备注 - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; - - @ApiModelProperty(value = "题目备注", required=true) - private String remark; - - @ApiModelProperty(value = "整题解析", required=true) - private String analysis; - + /** + * 整题解析 + * 提供该题目的完整解析,帮助用户理解解题思路及过程。 + */ + @ApiModelProperty(value = "整题解析", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String analysis; // 整题解析 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java index 6e689b8..0fa058e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java @@ -1,38 +1,58 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.io.Serializable; +import java.io.Serializable; // 可序列化接口 /** *

* 试题题库请求类 *

* +* 该类用于封装题库与题目之间的关联信息,包含题目的ID、题库ID、题目类型等信息。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="试题题库", description="试题题库") public class QuRepoDTO implements Serializable { - private static final long serialVersionUID = 1L; - - - private String id; - - @ApiModelProperty(value = "试题", required=true) - private String quId; - - @ApiModelProperty(value = "归属题库", required=true) - private String repoId; - - @ApiModelProperty(value = "题目类型", required=true) - private Integer quType; - - @ApiModelProperty(value = "排序", required=true) - private Integer sort; - -} \ No newline at end of file + private static final long serialVersionUID = 1L; // 序列化版本UID + + /** + * 试题ID + * 唯一标识一道试题。 + */ + private String id; // 试题ID + + /** + * 题目ID + * 与题目ID进行关联,表示该试题属于某个具体题目。 + */ + @ApiModelProperty(value = "试题", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String quId; // 题目ID + + /** + * 题库ID + * 标识该题目所属的题库。 + */ + @ApiModelProperty(value = "归属题库", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private String repoId; // 题库ID + + /** + * 题目类型 + * 表示该题目在题库中的类型,例如选择题、填空题等。 + */ + @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Integer quType; // 题目类型 + + /** + * 排序 + * 表示该题目在题库中的显示顺序,数字越小,顺序越靠前。 + */ + @ApiModelProperty(value = "排序", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Integer sort; // 排序 +} diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java index fe94dac..fff01c5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java @@ -1,45 +1,59 @@ package com.yf.exam.modules.qu.dto.export; -import com.yf.exam.core.utils.excel.annotation.ExcelField; -import com.yf.exam.core.utils.excel.fieldtype.ListType; -import lombok.Data; +import com.yf.exam.core.utils.excel.annotation.ExcelField; // Excel导出注解 +import com.yf.exam.core.utils.excel.fieldtype.ListType; // 用于处理List类型字段的特殊注解 +import lombok.Data; // Lombok注解,用于自动生成getter、setter、toString等方法 -import java.util.List; +import java.util.List; // 用于表示列表类型的字段 /** * 用于导出的数据结构 + * + * 该类是导出试题相关数据时所使用的DTO(数据传输对象),包含了题目序号、题目内容、题目解析、选项内容等信息。 + * 主要用于Excel导出时的数据映射。 + * * @author bool */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 public class QuExportDTO { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID /** - * + * 题目ID */ - private String qId; - - @ExcelField(title="题目序号", align=2, sort=1) - private String no; - @ExcelField(title="题目类型", align=2, sort=2) - private String quType; - @ExcelField(title="题目内容", align=2, sort=3) - private String qContent; - @ExcelField(title="整体解析", align=2, sort=4) - private String qAnalysis; - @ExcelField(title="题目图片", align=2, sort=5) - private String qImage; - @ExcelField(title="题目视频", align=2, sort=6) - private String qVideo; - @ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class) - private List repoList; - @ExcelField(title="是否正确项", align=2, sort=8) - private String aIsRight; - @ExcelField(title="选项内容", align=2, sort=9) - private String aContent; - @ExcelField(title="选项解析", align=2, sort=10) - private String aAnalysis; - @ExcelField(title="选项图片", align=2, sort=11) - private String aImage; + private String qId; // 题目的唯一标识符 + + @ExcelField(title="题目序号", align=2, sort=1) // 导出Excel时的列标题和排序,align为居中对齐,sort为排序位置 + private String no; // 题目序号,表示题目的编号 + + @ExcelField(title="题目类型", align=2, sort=2) // Excel导出列的标题和排序 + private String quType; // 题目类型,可能是单选题、多选题等 + + @ExcelField(title="题目内容", align=2, sort=3) // Excel导出列的标题和排序 + private String qContent; // 题目内容,包含问题的具体描述 + + @ExcelField(title="整体解析", align=2, sort=4) // Excel导出列的标题和排序 + private String qAnalysis; // 整个题目的解析说明 + + @ExcelField(title="题目图片", align=2, sort=5) // Excel导出列的标题和排序 + private String qImage; // 题目图片,存储图片URL或路径 + + @ExcelField(title="题目视频", align=2, sort=6) // Excel导出列的标题和排序 + private String qVideo; // 题目视频,存储视频URL或路径 + + @ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class) // 题库列表,支持导出多个题库 + private List repoList; // 题目所属的题库列表 + + @ExcelField(title="是否正确项", align=2, sort=8) // Excel导出列的标题和排序 + private String aIsRight; // 是否为正确选项(0或1) + + @ExcelField(title="选项内容", align=2, sort=9) // Excel导出列的标题和排序 + private String aContent; // 选项内容,表示答案的具体内容 + + @ExcelField(title="选项解析", align=2, sort=10) // Excel导出列的标题和排序 + private String aAnalysis; // 选项解析,说明该选项的正确性或相关分析 + + @ExcelField(title="选项图片", align=2, sort=11) // Excel导出列的标题和排序 + private String aImage; // 选项图片,存储图片URL或路径 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java index 4ac03c0..79aa0fe 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java @@ -1,23 +1,56 @@ package com.yf.exam.modules.qu.dto.export; -import com.yf.exam.modules.qu.dto.QuAnswerDTO; -import lombok.Data; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 导入的选项答案DTO +import lombok.Data; // Lombok注解,用于自动生成getter、setter、toString等方法 -import java.util.List; +import java.util.List; // 用于表示列表类型的字段 /** * 用于导出的数据结构 + * + * 该类用于导入试题数据时的DTO(数据传输对象),包含了题目类型、题目内容、解析、题目图片等信息。 + * 同时还包含了该题目的多个答案选项。 + * * @author bool */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 public class QuImportDTO { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID - private String quType; - private String qContent; - private String qAnalysis; - private String qImage; - private String repoName; - private List answerList; + /** + * 题目类型 + * 例如:1代表单选题,2代表多选题,3代表判断题,4代表主观题等 + */ + private String quType; // 题目类型,表示题目的类别 + + /** + * 题目内容 + * 例如:问题的具体描述 + */ + private String qContent; // 题目内容,表示题目的实际问题 + + /** + * 题目解析 + * 例如:题目解析或解释说明 + */ + private String qAnalysis; // 题目解析,解释题目的答案或相关说明 + + /** + * 题目图片 + * 例如:题目相关的图片URL + */ + private String qImage; // 题目图片,存储图片URL或路径 + + /** + * 题库名称 + * 例如:题目所属的题库名称 + */ + private String repoName; // 题目所属的题库名称 + + /** + * 答案选项列表 + * 该字段存储了该题目的多个答案选项及其相关信息。 + */ + private List answerList; // 答案选项列表,包含该题目的所有答案选项 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java index b36a4e8..0035a89 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java @@ -1,33 +1,43 @@ package com.yf.exam.modules.qu.dto.ext; -import com.yf.exam.modules.qu.dto.QuAnswerDTO; -import com.yf.exam.modules.qu.dto.QuDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 引入选项答案DTO +import com.yf.exam.modules.qu.dto.QuDTO; // 引入问题题目DTO +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.util.List; +import java.util.List; // 用于表示列表类型的字段 /** *

* 问题题目请求类 *

* +* 该类用于表示问题的详细信息,继承自 `QuDTO`,包括题目的详细信息如备选项、题库列表等。 +* 主要用于在前后端交互时,传递包含问题详细信息的请求或响应数据。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="问题题目详情", description="问题题目详情") public class QuDetailDTO extends QuDTO { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID - - @ApiModelProperty(value = "备选项列表", required=true) - private List answerList; - - @ApiModelProperty(value = "题库列表", required=true) - private List repoIds; + /** + * 备选项列表 + * 该字段包含了该题目的所有答案选项列表。 + * 每个选项都包含了选项内容、是否为正确答案、解析等信息。 + */ + @ApiModelProperty(value = "备选项列表", required=true) // Swagger注解,用于生成文档 + private List answerList; // 备选项列表,包含该题目的所有答案选项 - + /** + * 题库列表 + * 该字段包含了该题目所属的多个题库ID。 + * 用于标识该题目属于哪些题库,可能有多个题库关联。 + */ + @ApiModelProperty(value = "题库列表", required=true) // Swagger注解,用于生成文档 + private List repoIds; // 题库列表,存储题库ID的列表 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java index a927e9e..989cb8e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java @@ -1,38 +1,54 @@ package com.yf.exam.modules.qu.dto.request; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.io.Serializable; -import java.util.List; +import java.io.Serializable; // 可序列化接口 +import java.util.List; // 用于表示列表类型的字段 /** *

* 问题题目请求类 *

* +* 该类用于封装前端请求查询题目的参数。通过该请求类,前端可以传递多个查询条件, +* 如题目类型、题库ID、题目内容等,以便进行题目的筛选和查询。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="题目查询请求类", description="题目查询请求类") public class QuQueryReqDTO implements Serializable { - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "题目类型") - private Integer quType; - - @ApiModelProperty(value = "归属题库") - private List repoIds; - - @ApiModelProperty(value = "题目内容") - private String content; - - @ApiModelProperty(value = "排除ID列表") - private List excludes; - - + private static final long serialVersionUID = 1L; // 序列化版本UID + + /** + * 题目类型 + * 用于指定查询的题目类型。例如,单选题、多选题、判断题等。 + */ + @ApiModelProperty(value = "题目类型") // Swagger注解,描述字段信息 + private Integer quType; // 题目类型,通常是数字表示不同题型 + + /** + * 归属题库 + * 用于指定题目所属的题库ID列表。如果该字段不为空,查询会限制在指定的题库中。 + */ + @ApiModelProperty(value = "归属题库") // Swagger注解,描述字段信息 + private List repoIds; // 题库ID列表,题目可以归属于多个题库 + + /** + * 题目内容 + * 用于进行模糊查询,匹配包含特定内容的题目。 + */ + @ApiModelProperty(value = "题目内容") // Swagger注解,描述字段信息 + private String content; // 题目内容,支持模糊查询 + + /** + * 排除ID列表 + * 用于指定在查询中排除的题目ID列表,这些ID的题目不会出现在查询结果中。 + */ + @ApiModelProperty(value = "排除ID列表") // Swagger注解,描述字段信息 + private List excludes; // 排除的题目ID列表 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java index 3ca148d..0628495 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java @@ -1,34 +1,47 @@ package com.yf.exam.modules.qu.dto.request; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 +import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.io.Serializable; -import java.util.List; +import java.io.Serializable; // 可序列化接口 +import java.util.List; // 用于表示列表类型的字段 /** *

-* 问题题目请求类 +* 试题题库批量操作请求类 *

* +* 该类用于封装前端请求批量操作题目和题库关联的参数。 +* 通过该请求类,前端可以执行批量新增或移除题目与题库的关联操作。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data +@Data // Lombok注解,自动生成getter、setter等方法 @ApiModel(value="试题题库批量操作类", description="试题题库批量操作类") public class QuRepoBatchReqDTO implements Serializable { - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "题目ID", required=true) - private List quIds; - - @ApiModelProperty(value = "题目类型", required=true) - private List repoIds; - - @ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true) - private Boolean remove; - + private static final long serialVersionUID = 1L; // 序列化版本UID + + /** + * 题目ID列表 + * 用于指定要操作的题目ID集合,可以是多个题目。 + */ + @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private List quIds; // 要操作的题目ID列表 + + /** + * 题库ID列表 + * 用于指定题目与之关联的题库ID集合,可以是多个题库。 + */ + @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private List repoIds; // 题库ID列表 + + /** + * 是否移除标志 + * 如果为 `true`,表示从题库中移除题目;如果为 `false`,表示新增题目到题库中。 + */ + @ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 + private Boolean remove; // `true`表示移除,`false`表示新增 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java index 2380cdc..ccb4579 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java @@ -1,75 +1,85 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 +import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 -import java.util.Date; +import java.util.Date; // 日期类型 /** *

* 问题题目实体类 *

* +* 该类用于映射问题题目的数据结构,通过MyBatis-Plus框架进行数据库操作。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data -@TableName("el_qu") +@Data // Lombok注解,自动生成getter、setter等方法 +@TableName("el_qu") // MyBatis Plus注解,指定与数据库表的映射关系 public class Qu extends Model { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID /** * 题目ID + * 主键,唯一标识一道题目。 */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID + private String id; // 题目ID /** * 题目类型 + * 表示该题目是选择题、判断题等类型。 */ - @TableField("qu_type") - private Integer quType; + @TableField("qu_type") // MyBatis Plus注解,指定字段名与数据库表字段名映射 + private Integer quType; // 题目类型 /** - * 1普通,2较难 + * 题目难度 + * 1表示普通,2表示较难。 */ - private Integer level; + private Integer level; // 题目难度,1普通,2较难 /** * 题目图片 + * 题目相关的图片资源,存储图片URL或路径。 */ - private String image; + private String image; // 题目图片 /** * 题目内容 + * 存储题目的实际内容,例如选择题或填空题的文本。 */ - private String content; + private String content; // 题目内容 /** * 创建时间 + * 记录该题目创建的时间戳。 */ - @TableField("create_time") - private Date createTime; + @TableField("create_time") // MyBatis Plus注解,映射数据库中的字段 + private Date createTime; // 创建时间 /** * 更新时间 + * 记录该题目最后更新时间戳。 */ - @TableField("update_time") - private Date updateTime; + @TableField("update_time") // MyBatis Plus注解,映射数据库中的字段 + private Date updateTime; // 更新时间 /** * 题目备注 + * 对题目附加的说明或备注。 */ - private String remark; + private String remark; // 题目备注 /** * 整题解析 + * 对该题目的详细解析,包括答案解析、解题思路等。 */ - private String analysis; - + private String analysis; // 整题解析 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java index 45e9bf4..6c01005 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java @@ -1,58 +1,64 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 +import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 /** *

* 候选答案实体类 *

* +* 该类用于映射候选答案的数据结构,通过MyBatis-Plus框架进行数据库操作。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data -@TableName("el_qu_answer") +@Data // Lombok注解,自动生成getter、setter等方法 +@TableName("el_qu_answer") // MyBatis Plus注解,指定与数据库表的映射关系 public class QuAnswer extends Model { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID /** * 答案ID + * 主键,唯一标识一个答案。 */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID + private String id; // 答案ID /** * 问题ID + * 关联的题目ID,表示这个答案是属于哪道题目的。 */ - @TableField("qu_id") - private String quId; + @TableField("qu_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 + private String quId; // 问题ID /** * 是否正确 + * 该答案是否为正确答案,true表示正确,false表示错误。 */ - @TableField("is_right") - private Boolean isRight; + @TableField("is_right") // MyBatis Plus注解,映射数据库中的字段 + private Boolean isRight; // 是否正确 /** * 选项图片 + * 答案相关的图片资源,存储图片URL或路径。 */ - private String image; + private String image; // 选项图片 /** * 答案内容 + * 存储该选项的文本内容。 */ - private String content; - + private String content; // 答案内容 /** * 答案分析 + * 对该答案的详细分析,包括为什么是正确或错误的解析。 */ - private String analysis; - + private String analysis; // 答案分析 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java index baade9a..aa26d34 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java @@ -1,50 +1,59 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 +import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 +import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 /** *

* 试题题库实体类 *

* +* 该类用于映射试题和题库之间的关系,表示一道题目属于某个题库,并可能具有排序。 +* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data -@TableName("el_qu_repo") +@Data // Lombok注解,自动生成getter、setter等方法 +@TableName("el_qu_repo") // MyBatis Plus注解,指定与数据库表的映射关系 public class QuRepo extends Model { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本UID - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + /** + * 试题题库关系ID + * 主键,唯一标识一条题目与题库的关联记录。 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID + private String id; // 试题题库关系ID /** - * 试题 + * 试题ID + * 关联的题目ID,表示某道题目属于哪个题库。 */ - @TableField("qu_id") - private String quId; + @TableField("qu_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 + private String quId; // 试题ID /** - * 归属题库 + * 题库ID + * 关联的题库ID,表示该题目属于哪个题库。 */ - @TableField("repo_id") - private String repoId; + @TableField("repo_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 + private String repoId; // 题库ID /** * 题目类型 + * 用于描述该题目所属的类型(例如:选择题、填空题等)。 */ - @TableField("qu_type") - private Integer quType; + @TableField("qu_type") // MyBatis Plus注解,映射数据库中的字段 + private Integer quType; // 题目类型 /** * 排序 + * 用于对题库中的题目进行排序。 */ - private Integer sort; - + private Integer sort; // 排序 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java b/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java index 70e2ee1..4e5f342 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java @@ -1,8 +1,10 @@ package com.yf.exam.modules.qu.enums; - /** - * 题目类型 + * 题目类型接口 + * + * 该接口定义了不同类型的题目标识常量,适用于题库系统中对题目类型的区分。 + * * @author bool * @date 2019-10-30 13:11 */ @@ -10,16 +12,19 @@ public interface QuType { /** * 单选题 + * 表示一道题目是单选题,用户只能选择一个答案。 */ Integer RADIO = 1; /** * 多选题 + * 表示一道题目是多选题,用户可以选择多个答案。 */ Integer MULTI = 2; /** * 判断题 + * 表示一道题目是判断题,通常是选择“正确”或“错误”两种答案。 */ Integer JUDGE = 3; diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java index 23699ce..5fb575e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java @@ -4,13 +4,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yf.exam.modules.qu.entity.QuAnswer; /** -*

-* 候选答案Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ + *

+ * 候选答案Mapper + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 13:23 + */ public interface QuAnswerMapper extends BaseMapper { } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java index 14069a2..2ab579e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java @@ -1,15 +1,15 @@ -package com.yf.exam.modules.qu.mapper; +package com.yf.exam.modules.qu.mapper; // 定义包名,用于存放与问题题目相关的 Mapper 类 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.qu.dto.QuDTO; -import com.yf.exam.modules.qu.dto.export.QuExportDTO; -import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; -import com.yf.exam.modules.qu.entity.Qu; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper,用于提供通用的 CRUD 方法 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入分页接口 IPage,用于处理分页结果 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入分页插件的 Page 类,用于分页查询 +import com.yf.exam.modules.qu.dto.QuDTO; // 导入 QuDTO 数据传输对象,用于封装题目数据 +import com.yf.exam.modules.qu.dto.export.QuExportDTO; // 导入 QuExportDTO 用于题目导出的数据结构 +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; // 导入 QuQueryReqDTO 用于封装查询条件 +import com.yf.exam.modules.qu.entity.Qu; // 导入 Qu 实体类,表示题目表的对应数据 +import org.apache.ibatis.annotations.Param; // 导入 MyBatis 的 Param 注解,用于 SQL 查询中的参数传递 -import java.util.List; +import java.util.List; // 导入 List,用于返回多个对象的集合 /** *

@@ -19,38 +19,34 @@ import java.util.List; * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -public interface QuMapper extends BaseMapper { - - +public interface QuMapper extends BaseMapper { // QuMapper 继承自 BaseMapper,提供基本的 CRUD 操作 /** * 随机抽取题库的数据 - * @param repoId - * @param quType - * @param level + * @param repoId 题库ID + * @param quType 题目类型 + * @param level 题目难度 * @param excludes 要排除的ID列表 - * @param size - * @return + * @param size 抽取题目的数量 + * @return 随机抽取的题目列表 */ - List listByRandom(@Param("repoId") String repoId, - @Param("quType") Integer quType, - @Param("excludes") List excludes, - @Param("size") Integer size); + List listByRandom(@Param("repoId") String repoId, // 题库ID + @Param("quType") Integer quType, // 题目类型 + @Param("excludes") List excludes, // 要排除的题目ID列表 + @Param("size") Integer size); // 抽取的题目数量 /** * 查找导出列表 - * @param query - * @return + * @param query 查询条件对象 + * @return 返回符合条件的题目列表,用于导出 */ - List listForExport(@Param("query") QuQueryReqDTO query); + List listForExport(@Param("query") QuQueryReqDTO query); // 根据查询条件查找导出数据 /** * 分页查找 - * @param page - * @param query - * @return + * @param page 分页参数,包含当前页和每页大小 + * @param query 查询条件对象 + * @return 返回分页的题目数据 */ - IPage paging(Page page, @Param("query") QuQueryReqDTO query); - - + IPage paging(Page page, @Param("query") QuQueryReqDTO query); // 分页查询题目数据,返回 QuDTO 类型的数据 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java index 1015448..84fa2cb 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java @@ -1,7 +1,7 @@ -package com.yf.exam.modules.qu.mapper; +package com.yf.exam.modules.qu.mapper; // 定义包名,用于存放与试题题库相关的 Mapper 类 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.qu.entity.QuRepo; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper,用于提供通用的 CRUD 方法 +import com.yf.exam.modules.qu.entity.QuRepo; // 导入 QuRepo 实体类,表示试题题库表的数据 /** *

@@ -11,6 +11,5 @@ import com.yf.exam.modules.qu.entity.QuRepo; * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -public interface QuRepoMapper extends BaseMapper { - +public interface QuRepoMapper extends BaseMapper { // QuRepoMapper 继承自 BaseMapper,提供基本的 CRUD 操作 } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java index 4062e95..f6329f5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java @@ -10,7 +10,7 @@ import java.util.List; /** *

-* 候选答案业务类 +* 候选答案业务类接口,定义了与试题答案相关的业务操作 *

* * @author 聪明笨狗 @@ -19,30 +19,30 @@ import java.util.List; public interface QuAnswerService extends IService { /** - * 分页查询数据 - * @param reqDTO - * @return + * 分页查询答案数据 + * @param reqDTO 请求的分页和查询参数 + * @return 分页的答案数据 */ IPage paging(PagingReqDTO reqDTO); /** - * 根据题目ID查询答案并随机 - * @param quId - * @return + * 根据题目ID查询答案,并进行随机排序 + * @param quId 题目ID + * @return 随机排序后的答案列表 */ List listAnswerByRandom(String quId); /** - * 根据问题查找答案 - * @param quId - * @return + * 根据题目ID查询所有的答案 + * @param quId 题目ID + * @return 该题目的答案列表 */ List listByQu(String quId); /** - * 保存试题 - * @param quId - * @param list + * 保存所有选项数据 + * @param quId 题目ID + * @param list 题目的所有答案选项 */ void saveAll(String quId, List list); } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java index f528759..a53ebb1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java @@ -1,59 +1,66 @@ +// 定义包名,表示该接口属于com.yf.exam.modules.qu.service包下 package com.yf.exam.modules.qu.service; +// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; +// 导入MyBatis Plus框架的服务接口 import com.baomidou.mybatisplus.extension.service.IService; +// 导入项目中定义的分页请求DTO类 import com.yf.exam.core.api.dto.PagingReqDTO; +// 导入项目中定义的题库DTO类 import com.yf.exam.modules.qu.dto.QuRepoDTO; +// 导入项目中定义的批量请求DTO类 import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; +// 导入项目中定义的题库实体类 import com.yf.exam.modules.qu.entity.QuRepo; - +// 导入Java.util包下的List接口,用于操作列表 import java.util.List; /** -*

-* 试题题库业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ + *

+ * 试题题库业务接口,定义了题库相关的业务操作 + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 13:23 + */ public interface QuRepoService extends IService { /** - * 分页查询数据 - * @param reqDTO - * @return - */ + * 分页查询题库数据的方法 + * @param reqDTO 分页请求DTO,包含分页信息和查询条件 + * @return 返回分页响应,包含题库数据和分页信息 + */ IPage paging(PagingReqDTO reqDTO); /** - * 保存全部列表 - * @param quId - * @param quType - * @param ids + * 保存全部列表的方法,用于保存题目与题库的关系 + * @param quId 题目ID + * @param quType 题目类型 + * @param ids 题库ID列表 */ void saveAll(String quId, Integer quType, List ids); /** - * 根据问题查找题库 - * @param quId - * @return + * 根据题目查找题库的方法 + * @param quId 题目ID + * @return 返回与题目关联的题库ID列表 */ List listByQu(String quId); /** - * 根据题库查找题目ID列表 - * @param repoId - * @param quType - * @param rand - * @return + * 根据题库查找题目ID列表的方法 + * @param repoId 题库ID + * @param quType 题目类型 + * @param rand 是否随机选择 + * @return 返回题目ID列表 */ List listByRepo(String repoId, Integer quType, boolean rand); /** - * 批量操作 - * @param reqDTO + * 批量操作的方法,用于执行批量业务操作 + * @param reqDTO 批量请求DTO,包含批量操作信息 */ void batchAction(QuRepoBatchReqDTO reqDTO); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java index 81f43b0..51fe835 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java @@ -1,46 +1,55 @@ +// 定义包名,表示该接口属于com.yf.exam.modules.qu.service包下 package com.yf.exam.modules.qu.service; +// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; +// 导入MyBatis Plus框架的服务接口 import com.baomidou.mybatisplus.extension.service.IService; +// 导入项目中定义的分页请求DTO类 import com.yf.exam.core.api.dto.PagingReqDTO; +// 导入项目中定义的题目DTO类 import com.yf.exam.modules.qu.dto.QuDTO; +// 导入项目中定义的题目导出DTO类 import com.yf.exam.modules.qu.dto.export.QuExportDTO; +// 导入项目中定义的扩展题目详情DTO类 import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; +// 导入项目中定义的题目查询请求DTO类 import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +// 导入项目中定义的题目实体类 import com.yf.exam.modules.qu.entity.Qu; - +// 导入Java.util包下的List接口,用于操作列表 import java.util.List; /** -*

-* 问题题目业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ + *

+ * 问题题目业务接口,定义了题目相关的业务操作 + *

+ * + * @author 聪明笨狗 + * @since 2020-05-25 13:23 + */ public interface QuService extends IService { /** - * 分页查询数据 - * @param reqDTO - * @return + * 分页查询题目数据的方法 + * @param reqDTO 分页请求DTO,包含分页信息和查询条件 + * @return 返回分页响应,包含题目数据和分页信息 */ IPage paging(PagingReqDTO reqDTO); /** - * 删除试题 - * @param ids + * 删除题目的方法 + * @param ids 题目ID列表 */ void delete(List ids); /** - * 随机抽取题库的数据 - * @param repoId - * @param quType + * 随机抽取题库中的数据的方法 + * @param repoId 题库ID + * @param quType 题目类型 * @param excludes 要排除的ID列表 - * @param size - * @return + * @param size 抽取的数量 + * @return 返回随机抽取的题目列表 */ List listByRandom(String repoId, Integer quType, @@ -48,29 +57,29 @@ public interface QuService extends IService { Integer size); /** - * 问题详情 - * @param id - * @return + * 查询题目详情的方法 + * @param id 题目ID + * @return 返回题目详情DTO */ QuDetailDTO detail(String id); /** - * 保存试题 - * @param reqDTO + * 保存题目的方法 + * @param reqDTO 题目详情DTO */ void save(QuDetailDTO reqDTO); /** - * 查找导出列表 - * @param query - * @return + * 查找导出列表的方法 + * @param query 题目查询请求DTO + * @return 返回题目导出列表 */ List listForExport(QuQueryReqDTO query); /** - * 导入Excel - * @param dtoList - * @return + * 导入Excel数据的方法 + * @param dtoList 题目导出DTO列表 + * @return 返回导入的结果,影响的行数 */ int importExcel(List dtoList); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java index 2fd66cf..1c31577 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java @@ -1,24 +1,24 @@ -package com.yf.exam.modules.qu.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.qu.dto.QuAnswerDTO; -import com.yf.exam.modules.qu.entity.QuAnswer; -import com.yf.exam.modules.qu.mapper.QuAnswerMapper; -import com.yf.exam.modules.qu.service.QuAnswerService; -import com.yf.exam.modules.qu.utils.ImageCheckUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; +package com.yf.exam.modules.qu.service.impl; // 定义包名,表示这是实现类部分,专注于处理与试题答案相关的逻辑 + +import com.alibaba.fastjson.JSON; // 导入 fastjson 库,用于 JSON 序列化和反序列化 +import com.alibaba.fastjson.TypeReference; // 导入 fastjson 库的 TypeReference,用于处理泛型类型 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构造查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页 Page 类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 基类 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象类 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象之间的映射 +import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 导入试题答案的 DTO 类 +import com.yf.exam.modules.qu.entity.QuAnswer; // 导入试题答案的实体类 +import com.yf.exam.modules.qu.mapper.QuAnswerMapper; // 导入试题答案的 Mapper 接口 +import com.yf.exam.modules.qu.service.QuAnswerService; // 导入试题答案的服务接口 +import com.yf.exam.modules.qu.utils.ImageCheckUtils; // 导入图片校验工具类 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 的注解,自动注入依赖 +import org.springframework.stereotype.Service; // 导入 Spring 的服务注解,标识这是一个服务类 +import org.springframework.util.CollectionUtils; // 导入 Spring 的集合工具类,用于检查集合是否为空 + +import java.util.ArrayList; // 导入 ArrayList,用于动态数组 +import java.util.List; // 导入 List 接口,作为列表类型 /** *

@@ -28,65 +28,77 @@ import java.util.List; * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Service +@Service // 表示这是一个服务类,Spring 会自动扫描并管理该类 public class QuAnswerServiceImpl extends ServiceImpl implements QuAnswerService { @Autowired - private ImageCheckUtils imageCheckUtils; + private ImageCheckUtils imageCheckUtils; // 自动注入图片校验工具类,用于校验图片地址是否合法 @Override public IPage paging(PagingReqDTO reqDTO) { - - //创建分页对象 + // 创建分页对象,传入当前页和每页大小 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 执行分页查询,获取分页结果 IPage page = this.page(query, wrapper); - //转换结果 + + // 将查询结果转换为 QuAnswerDTO 类型的分页结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); return pageData; - } + } @Override public List listAnswerByRandom(String quId) { + // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); + // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); + // 使用 SQL 的随机排序来随机获取答案 wrapper.last(" ORDER BY RAND() "); + // 执行查询并返回结果 return this.list(wrapper); } @Override public List listByQu(String quId) { + // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); + // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); + // 执行查询,获取答案列表 List list = this.list(wrapper); if(!CollectionUtils.isEmpty(list)){ + // 将 QuAnswer 实体对象列表转换为 QuAnswerDTO 对象列表 return BeanMapper.mapList(list, QuAnswerDTO.class); } + // 如果没有找到记录,返回 null return null; } - /** * 查找已存在的列表 - * @param quId - * @return + * @param quId 试题ID + * @return 已存在答案的 ID 列表 */ public List findExistsList(String quId) { - //返回结果 + // 创建空的结果列表 List ids = new ArrayList<>(); + // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper(); + // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); + // 执行查询,获取答案列表 List list = this.list(wrapper); if (!CollectionUtils.isEmpty(list)) { + // 将已有的答案 ID 添加到结果列表 for (QuAnswer item : list) { ids.add(item.getId()); } @@ -96,49 +108,49 @@ public class QuAnswerServiceImpl extends ServiceImpl i @Override public void saveAll(String quId, List list) { - - //最终要保存的列表 + // 创建保存的答案列表 List saveList = new ArrayList<>(); - //已存在的标签列表 + // 获取已有的答案 ID 列表 List ids = this.findExistsList(quId); + // 如果答案列表不为空,则进行处理 if(!CollectionUtils.isEmpty(list)){ for(QuAnswerDTO item: list){ - // 校验图片地址 + // 校验选项图片地址是否合法 imageCheckUtils.checkImage(item.getImage(), "选项图片地址错误!"); - //标签ID + // 获取答案 ID String id = item.getId(); QuAnswer answer = new QuAnswer(); + // 将 DTO 转换为实体类 BeanMapper.copy(item, answer); - answer.setQuId(quId); + answer.setQuId(quId); // 设置试题 ID - //补全ID避免新增 + // 如果该答案已存在,则从 IDs 列表中移除 if(ids.contains(id)){ ids.remove(id); } + // 添加答案到保存列表 saveList.add(answer); } - //保存标签列表 + // 如果有待保存的答案,则批量保存或更新 if(!CollectionUtils.isEmpty(saveList)) { this.saveOrUpdateBatch(saveList); } - //删除已移除 + // 如果有被移除的答案,则批量删除 if(!ids.isEmpty()){ this.removeByIds(ids); } }else{ - + // 如果答案列表为空,则删除所有与该试题 ID 相关的答案 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuAnswer::getQuId, quId); this.remove(wrapper); } } - - } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java index b7de030..c0e8f29 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java @@ -1,175 +1,182 @@ -package com.yf.exam.modules.qu.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.qu.dto.QuRepoDTO; -import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; -import com.yf.exam.modules.qu.entity.Qu; -import com.yf.exam.modules.qu.entity.QuRepo; -import com.yf.exam.modules.qu.mapper.QuMapper; -import com.yf.exam.modules.qu.mapper.QuRepoMapper; -import com.yf.exam.modules.qu.service.QuRepoService; -import com.yf.exam.modules.repo.service.RepoService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; +package com.yf.exam.modules.qu.service.impl; // 定义包名,表示这是服务实现类,负责处理与试题题库相关的业务逻辑 + +import com.alibaba.fastjson.JSON; // 导入 fastjson 库,用于 JSON 序列化和反序列化 +import com.alibaba.fastjson.TypeReference; // 导入 fastjson 库的 TypeReference,用于处理泛型类型 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构造查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页 Page 类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 基类 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象类 +import com.yf.exam.modules.qu.dto.QuRepoDTO; // 导入试题题库的 DTO 类 +import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; // 导入试题题库批量操作请求类 +import com.yf.exam.modules.qu.entity.Qu; // 导入试题实体类 +import com.yf.exam.modules.qu.entity.QuRepo; // 导入试题题库实体类 +import com.yf.exam.modules.qu.mapper.QuMapper; // 导入试题的 Mapper 接口 +import com.yf.exam.modules.qu.mapper.QuRepoMapper; // 导入试题题库的 Mapper 接口 +import com.yf.exam.modules.qu.service.QuRepoService; // 导入试题题库服务接口 +import com.yf.exam.modules.repo.service.RepoService; // 导入题库服务接口 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 的注解,自动注入依赖 +import org.springframework.stereotype.Service; // 导入 Spring 的服务注解,标识这是一个服务类 +import org.springframework.util.CollectionUtils; // 导入 Spring 的集合工具类,用于检查集合是否为空 + +import java.util.ArrayList; // 导入 ArrayList,用于动态数组 +import java.util.List; // 导入 List 接口,作为列表类型 /** *

-* 语言设置 服务实现类 +* 试题题库 服务实现类 *

* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Service +@Service // 表示这是一个 Spring 服务类,Spring 会自动扫描并管理该类 public class QuRepoServiceImpl extends ServiceImpl implements QuRepoService { - @Autowired - private QuMapper quMapper; + private QuMapper quMapper; // 自动注入试题的 Mapper 接口 @Autowired - private RepoService repoService; + private RepoService repoService; // 自动注入题库服务接口 @Override public IPage paging(PagingReqDTO reqDTO) { - - //创建分页对象 + // 创建分页对象,传入当前页和每页大小 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 执行分页查询,获取分页结果 IPage page = this.page(query, wrapper); - //转换结果 + + // 将查询结果转换为 QuRepoDTO 类型的分页结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); return pageData; - } + } @Override public void saveAll(String quId, Integer quType, List ids) { - // 先删除 + // 先删除已有的试题题库记录 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getQuId, quId); this.remove(wrapper); - // 保存全部 + // 如果题库 ID 列表不为空,保存新的记录 if(!CollectionUtils.isEmpty(ids)){ List list = new ArrayList<>(); for(String id: ids){ QuRepo ref = new QuRepo(); - ref.setQuId(quId); - ref.setRepoId(id); - ref.setQuType(quType); + ref.setQuId(quId); // 设置试题 ID + ref.setRepoId(id); // 设置题库 ID + ref.setQuType(quType); // 设置题目类型 list.add(ref); } + // 批量保存试题题库记录 this.saveBatch(list); - + // 对每个题库进行排序 for(String id: ids){ this.sortRepo(id); } } - - } @Override public List listByQu(String quId) { - // 先删除 + // 根据试题 ID 查找题库记录 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getQuId, quId); List list = this.list(wrapper); List ids = new ArrayList<>(); if(!CollectionUtils.isEmpty(list)){ + // 提取题库 ID 列表 for(QuRepo item: list){ ids.add(item.getRepoId()); } } - return ids; + return ids; // 返回题库 ID 列表 } @Override public List listByRepo(String repoId, Integer quType, boolean rand) { + // 根据题库 ID 和题目类型查询题库记录 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() - .eq(QuRepo::getRepoId, repoId); + wrapper.lambda().eq(QuRepo::getRepoId, repoId); - if(quType!=null){ + // 如果有题目类型,添加过滤条件 + if(quType != null){ wrapper.lambda().eq(QuRepo::getQuType, quType); } + // 根据是否需要随机排序决定排序方式 if(rand){ - wrapper.orderByAsc(" RAND() "); + wrapper.orderByAsc(" RAND() "); // 随机排序 }else{ - wrapper.lambda().orderByAsc(QuRepo::getSort); + wrapper.lambda().orderByAsc(QuRepo::getSort); // 按照排序字段排序 } + // 执行查询,获取题库记录列表 List list = this.list(wrapper); List ids = new ArrayList<>(); if(!CollectionUtils.isEmpty(list)){ + // 提取试题 ID 列表 for(QuRepo item: list){ ids.add(item.getQuId()); } } - return ids; + return ids; // 返回试题 ID 列表 } @Override public void batchAction(QuRepoBatchReqDTO reqDTO) { - - // 移除的 - if(reqDTO.getRemove()!=null && reqDTO.getRemove()){ + // 如果需要移除记录 + if(reqDTO.getRemove() != null && reqDTO.getRemove()){ + // 删除满足条件的题库记录 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() .in(QuRepo::getRepoId, reqDTO.getRepoIds()) .in(QuRepo::getQuId, reqDTO.getQuIds()); this.remove(wrapper); }else{ - - // 新增的 + // 如果是新增记录,处理新增逻辑 for(String quId : reqDTO.getQuIds()){ + // 根据试题 ID 查询试题类型 Qu q = quMapper.selectById(quId); + // 保存新的题库记录 this.saveAll(quId, q.getQuType(), reqDTO.getRepoIds()); } } + // 对每个题库进行排序 for(String id: reqDTO.getRepoIds()){ this.sortRepo(id); } - } - /** * 单个题库进行排序 - * @param repoId + * @param repoId 题库 ID */ private void sortRepo(String repoId){ - + // 查询题库下的所有试题 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getRepoId, repoId); - List list = this.list(wrapper); + + // 如果题库下没有试题,返回 if(CollectionUtils.isEmpty(list)){ return; } + // 按照顺序设置每个试题的排序值 int sort = 1; for(QuRepo item: list){ item.setSort(sort); sort++; } + + // 批量更新排序值 this.updateBatchById(list); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java index f9ae656..3594ff6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java @@ -1,9 +1,12 @@ package com.yf.exam.modules.qu.service.impl; +// 导入MyBatis Plus相关类 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; + +// 导入其他相关类 import com.yf.exam.ability.upload.config.UploadConfig; import com.yf.exam.core.api.dto.PagingReqDTO; import com.yf.exam.core.exception.ServiceException; @@ -23,6 +26,7 @@ import com.yf.exam.modules.qu.service.QuRepoService; import com.yf.exam.modules.qu.service.QuService; import com.yf.exam.modules.qu.utils.ImageCheckUtils; import com.yf.exam.modules.repo.service.RepoService; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -37,7 +41,7 @@ import java.util.Map; /** *

- * 语言设置 服务实现类 + * 题目管理服务实现类 *

* * @author 聪明笨狗 @@ -46,125 +50,136 @@ import java.util.Map; @Service public class QuServiceImpl extends ServiceImpl implements QuService { + // 注入QuAnswerService服务 @Autowired private QuAnswerService quAnswerService; + // 注入QuRepoService服务 @Autowired private QuRepoService quRepoService; + // 注入图片校验工具类 @Autowired private ImageCheckUtils imageCheckUtils; + // 分页查询题目列表 @Override public IPage paging(PagingReqDTO reqDTO) { - //创建分页对象 + // 创建分页对象 Page page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //转换结果 + // 调用baseMapper的分页查询方法,获取分页数据 IPage pageData = baseMapper.paging(page, reqDTO.getParams()); return pageData; } + // 删除题目、答案和题库绑定 @Transactional(rollbackFor = Exception.class) @Override public void delete(List ids) { - // 移除题目 + // 删除题目 this.removeByIds(ids); - // 移除选项 + // 删除与题目相关的选项 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().in(QuAnswer::getQuId, ids); quAnswerService.remove(wrapper); - // 移除题库绑定 + // 删除题库与题目的绑定 QueryWrapper wrapper1 = new QueryWrapper<>(); wrapper1.lambda().in(QuRepo::getQuId, ids); quRepoService.remove(wrapper1); } + // 随机获取题目 @Override public List listByRandom(String repoId, Integer quType, List excludes, Integer size) { return baseMapper.listByRandom(repoId, quType, excludes, size); } + // 获取题目的详细信息 @Override public QuDetailDTO detail(String id) { QuDetailDTO respDTO = new QuDetailDTO(); + // 获取题目信息 Qu qu = this.getById(id); BeanMapper.copy(qu, respDTO); + // 获取题目的选项信息 List answerList = quAnswerService.listByQu(id); respDTO.setAnswerList(answerList); + // 获取题目所属的题库 List repoIds = quRepoService.listByQu(id); respDTO.setRepoIds(repoIds); return respDTO; } - + // 保存题目信息 @Transactional(rollbackFor = Exception.class) @Override public void save(QuDetailDTO reqDTO) { - - // 校验数据 + // 校验题目信息 this.checkData(reqDTO, ""); Qu qu = new Qu(); + // 将题目详情复制到实体类 BeanMapper.copy(reqDTO, qu); - // 校验图片地址 + // 校验图片地址是否正确 imageCheckUtils.checkImage(qu.getImage(), "题干图片地址错误!"); - // 更新 + // 保存或更新题目信息 this.saveOrUpdate(qu); - // 保存全部问题 + // 保存题目的选项 quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList()); - // 保存到题库 + // 保存题目与题库的绑定 quRepoService.saveAll(qu.getId(), qu.getQuType(), reqDTO.getRepoIds()); - } + // 获取题目导出的列表 @Override public List listForExport(QuQueryReqDTO query) { return baseMapper.listForExport(query); } + // 导入Excel数据 @Override public int importExcel(List dtoList) { - //根据题目名称分组 + // 根据题目名称分组 Map> anMap = new HashMap<>(16); - //题目本体信息 + // 存储题目信息 Map quMap = new HashMap<>(16); - //数据分组 + // 分组数据 for (QuExportDTO item : dtoList) { - // 空白的ID + // 如果题目ID为空,跳过 if (StringUtils.isEmpty(item.getNo())) { continue; } Integer key; - //序号 + // 获取题目序号 try { key = Integer.parseInt(item.getNo()); } catch (Exception e) { continue; } - //如果已经有题目了,直接处理选项 + // 如果题目已存在,直接处理选项 if (anMap.containsKey(key)) { anMap.get(key).add(item); } else { - //如果没有,将题目内容和选项一起 + // 如果没有,将题目内容和选项一起放入 List subList = new ArrayList<>(); subList.add(item); anMap.put(key, subList); @@ -174,49 +189,46 @@ public class QuServiceImpl extends ServiceImpl implements QuServic int count = 0; try { - - //循环题目插入 + // 遍历题目插入 for (Integer key : quMap.keySet()) { QuExportDTO im = quMap.get(key); - //题目基本信息 + // 处理题目的基本信息 QuDetailDTO qu = new QuDetailDTO(); qu.setContent(im.getQContent()); qu.setAnalysis(im.getQAnalysis()); qu.setQuType(Integer.parseInt(im.getQuType())); qu.setCreateTime(new Date()); - //设置回答列表 + // 设置题目的回答列表 List answerList = this.processAnswerList(anMap.get(key)); - //设置题目 qu.setAnswerList(answerList); - //设置引用题库 + + // 设置题目所属的题库 qu.setRepoIds(im.getRepoList()); - // 保存答案 + + // 保存题目 this.save(qu); count++; } } catch (ServiceException e) { e.printStackTrace(); + // 异常处理,抛出导入失败的异常 throw new ServiceException(1, "导入出现问题,行:" + count + "," + e.getMessage()); } return count; } - /** - * 处理回答列表 - * - * @param importList - * @return - */ + // 处理题目的回答列表 private List processAnswerList(List importList) { List list = new ArrayList<>(16); for (QuExportDTO item : importList) { QuAnswerDTO a = new QuAnswerDTO(); + // 设置选项是否正确 a.setIsRight("1".equals(item.getAIsRight())); a.setContent(item.getAContent()); a.setAnalysis(item.getAAnalysis()); @@ -226,58 +238,52 @@ public class QuServiceImpl extends ServiceImpl implements QuServic return list; } - /** - * 校验题目信息 - * - * @param qu - * @param no - * @throws Exception - */ + // 校验题目信息 public void checkData(QuDetailDTO qu, String no) { - + // 校验题目内容不能为空 if (StringUtils.isEmpty(qu.getContent())) { throw new ServiceException(1, no + "题目内容不能为空!"); } - + // 校验至少选择一个题库 if (CollectionUtils.isEmpty(qu.getRepoIds())) { throw new ServiceException(1, no + "至少要选择一个题库!"); } + // 校验回答选项 List answers = qu.getAnswerList(); + if (CollectionUtils.isEmpty(answers)) { + throw new ServiceException(1, no + "客观题至少要包含一个备选答案!"); + } + int trueCount = 0; + for (QuAnswerDTO a : answers) { - if (CollectionUtils.isEmpty(answers)) { - throw new ServiceException(1, no + "客观题至少要包含一个备选答案!"); + // 校验选项是否定义了正确标志 + if (a.getIsRight() == null) { + throw new ServiceException(1, no + "必须定义选项是否正确项!"); } - - int trueCount = 0; - for (QuAnswerDTO a : answers) { - - if (a.getIsRight() == null) { - throw new ServiceException(1, no + "必须定义选项是否正确项!"); - } - - if (StringUtils.isEmpty(a.getContent())) { - throw new ServiceException(1, no + "选项内容不为空!"); - } - - if (a.getIsRight()) { - trueCount += 1; - } + // 校验选项内容不能为空 + if (StringUtils.isEmpty(a.getContent())) { + throw new ServiceException(1, no + "选项内容不为空!"); } - if (trueCount == 0) { - throw new ServiceException(1, no + "至少要包含一个正确项!"); + // 统计正确选项的个数 + if (a.getIsRight()) { + trueCount += 1; } + } + // 校验至少包含一个正确选项 + if (trueCount == 0) { + throw new ServiceException(1, no + "至少要包含一个正确项!"); + } - //单选题 - if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) { - throw new ServiceException(1, no + "单选题不能包含多个正确项!"); - } - + // 单选题不能包含多个正确选项 + if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) { + throw new ServiceException(1, no + "单选题不能包含多个正确项!"); + } } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java b/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java index 707fbcd..902c507 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java @@ -1,31 +1,42 @@ +// 定义包名,表示该类属于com.yf.exam.modules.qu.utils包下 package com.yf.exam.modules.qu.utils; +// 导入项目中定义的上传配置类 import com.yf.exam.ability.upload.config.UploadConfig; +// 导入项目中定义的服务异常类 import com.yf.exam.core.exception.ServiceException; +// 导入Apache Commons Lang库中的StringUtils类,用于字符串操作 import org.apache.commons.lang3.StringUtils; +// 导入Spring框架中的注解,用于自动注入依赖 import org.springframework.beans.factory.annotation.Autowired; +// 导入Spring框架中的注解,用于声明组件 import org.springframework.stereotype.Component; +/** + * 图片校验工具类,提供图片地址校验的功能 + */ @Component public class ImageCheckUtils { + // 自动注入上传配置,用于获取图片上传的相关配置 @Autowired private UploadConfig conf; /** - * 进行图片校验! - * @param image - * @param throwMsg + * 进行图片校验的方法 + * @param image 图片地址 + * @param throwMsg 校验失败时抛出的异常信息 */ public void checkImage(String image, String throwMsg) { - + // 如果图片地址为空或空白,则直接返回,不进行校验 if(StringUtils.isBlank(image)){ return; } - // 校验图片地址 + // 校验图片地址是否以配置的URL开头,确保图片地址是合法的 if(!image.startsWith(conf.getUrl())){ + // 如果图片地址不合法,则抛出服务异常 throw new ServiceException(throwMsg); } } -} +} \ No newline at end of file From 3b1d9e9ed1e0226a0ccf5a1164f84904f1d3faf7 Mon Sep 17 00:00:00 2001 From: zl <3216908512@qq.com> Date: Wed, 27 Nov 2024 21:50:52 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=BC=A0=E5=8A=9B?= =?UTF-8?q?=E5=88=86=E6=94=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yf/exam/ability/Constant.java | 13 +- .../yf/exam/ability/job/enums/JobGroup.java | 14 +- .../yf/exam/ability/job/enums/JobPrefix.java | 15 +- .../exam/ability/job/service/JobService.java | 51 +- .../job/service/impl/JobServiceImpl.java | 129 ++- .../ability/shiro/CNFilterFactoryBean.java | 38 +- .../com/yf/exam/ability/shiro/ShiroRealm.java | 246 +++--- .../yf/exam/ability/shiro/aop/JwtFilter.java | 113 ++- .../yf/exam/ability/shiro/jwt/JwtToken.java | 41 +- .../yf/exam/ability/shiro/jwt/JwtUtils.java | 90 +- .../ability/upload/config/UploadConfig.java | 36 +- .../upload/controller/UploadController.java | 71 +- .../exam/ability/upload/dto/UploadReqDTO.java | 30 +- .../ability/upload/dto/UploadRespDTO.java | 35 +- .../ability/upload/service/UploadService.java | 58 +- .../service/impl/UploadServiceImpl.java | 144 +-- .../exam/ability/upload/utils/FileUtils.java | 321 ++++--- .../exam/ability/upload/utils/MediaUtils.java | 76 +- .../java/com/yf/exam/aspect/DictAspect.java | 215 +++-- .../exam/aspect/mybatis/QueryInterceptor.java | 177 +++- .../aspect/mybatis/UpdateInterceptor.java | 126 ++- .../com/yf/exam/aspect/utils/InjectUtils.java | 111 ++- .../java/com/yf/exam/config/CorsConfig.java | 58 +- .../com/yf/exam/config/MultipartConfig.java | 53 +- .../com/yf/exam/config/MybatisConfig.java | 55 +- .../com/yf/exam/config/ScheduledConfig.java | 141 ++- .../java/com/yf/exam/config/ShiroConfig.java | 242 ++--- .../com/yf/exam/config/SwaggerConfig.java | 155 +++- .../exam/controller/ExamController.java | 233 +++-- .../com/yf/exam/modules/exam/dto/ExamDTO.java | 140 ++- .../exam/modules/exam/dto/ExamDepartDTO.java | 55 +- .../yf/exam/modules/exam/dto/ExamRepoDTO.java | 93 +- .../modules/exam/dto/ext/ExamRepoExtDTO.java | 50 +- .../exam/dto/request/ExamSaveReqDTO.java | 54 +- .../exam/dto/response/ExamOnlineRespDTO.java | 35 +- .../exam/dto/response/ExamReviewRespDTO.java | 53 +- .../com/yf/exam/modules/exam/entity/Exam.java | 155 ++-- .../exam/modules/exam/entity/ExamDepart.java | 65 +- .../yf/exam/modules/exam/entity/ExamRepo.java | 105 ++- .../modules/exam/mapper/ExamDepartMapper.java | 28 +- .../exam/modules/exam/mapper/ExamMapper.java | 61 +- .../modules/exam/mapper/ExamRepoMapper.java | 39 +- .../exam/service/ExamDepartService.java | 42 +- .../modules/exam/service/ExamRepoService.java | 49 +- .../modules/exam/service/ExamService.java | 77 +- .../service/impl/ExamDepartServiceImpl.java | 88 +- .../service/impl/ExamRepoServiceImpl.java | 92 +- .../exam/service/impl/ExamServiceImpl.java | 209 ++--- .../paper/controller/PaperController.java | 127 ++- .../yf/exam/modules/paper/dto/PaperDTO.java | 106 ++- .../modules/paper/dto/PaperQuAnswerDTO.java | 64 +- .../yf/exam/modules/paper/dto/PaperQuDTO.java | 71 +- .../paper/dto/ext/PaperQuAnswerExtDTO.java | 25 +- .../paper/dto/ext/PaperQuDetailDTO.java | 29 +- .../paper/dto/request/PaperAnswerDTO.java | 23 +- .../paper/dto/request/PaperCreateReqDTO.java | 22 +- .../paper/dto/request/PaperListReqDTO.java | 39 +- .../paper/dto/request/PaperQuQueryDTO.java | 22 +- .../paper/dto/response/ExamDetailRespDTO.java | 50 +- .../paper/dto/response/ExamResultRespDTO.java | 25 +- .../paper/dto/response/PaperListRespDTO.java | 35 +- .../yf/exam/modules/paper/entity/Paper.java | 105 ++- .../yf/exam/modules/paper/entity/PaperQu.java | 60 +- .../modules/paper/entity/PaperQuAnswer.java | 53 +- .../exam/modules/paper/enums/ExamState.java | 17 +- .../exam/modules/paper/enums/PaperState.java | 17 +- .../exam/modules/paper/job/BreakExamJob.java | 60 +- .../modules/paper/mapper/PaperMapper.java | 53 +- .../paper/mapper/PaperQuAnswerMapper.java | 32 +- .../modules/paper/mapper/PaperQuMapper.java | 44 +- .../paper/service/PaperQuAnswerService.java | 36 +- .../modules/paper/service/PaperQuService.java | 54 +- .../modules/paper/service/PaperService.java | 73 +- .../impl/PaperQuAnswerServiceImpl.java | 96 +- .../service/impl/PaperQuServiceImpl.java | 142 +-- .../paper/service/impl/PaperServiceImpl.java | 832 ++++++++---------- .../modules/qu/controller/QuController.java | 294 ++++--- .../yf/exam/modules/qu/dto/QuAnswerDTO.java | 64 +- .../com/yf/exam/modules/qu/dto/QuDTO.java | 91 +- .../com/yf/exam/modules/qu/dto/QuRepoDTO.java | 66 +- .../modules/qu/dto/export/QuExportDTO.java | 76 +- .../modules/qu/dto/export/QuImportDTO.java | 55 +- .../exam/modules/qu/dto/ext/QuDetailDTO.java | 40 +- .../modules/qu/dto/request/QuQueryReqDTO.java | 60 +- .../qu/dto/request/QuRepoBatchReqDTO.java | 51 +- .../com/yf/exam/modules/qu/entity/Qu.java | 60 +- .../yf/exam/modules/qu/entity/QuAnswer.java | 46 +- .../com/yf/exam/modules/qu/entity/QuRepo.java | 51 +- .../com/yf/exam/modules/qu/enums/QuType.java | 9 +- .../modules/qu/mapper/QuAnswerMapper.java | 14 +- .../yf/exam/modules/qu/mapper/QuMapper.java | 58 +- .../exam/modules/qu/mapper/QuRepoMapper.java | 9 +- .../modules/qu/service/QuAnswerService.java | 26 +- .../modules/qu/service/QuRepoService.java | 61 +- .../yf/exam/modules/qu/service/QuService.java | 69 +- .../qu/service/impl/QuAnswerServiceImpl.java | 102 +-- .../qu/service/impl/QuRepoServiceImpl.java | 127 ++- .../qu/service/impl/QuServiceImpl.java | 140 ++- .../modules/qu/utils/ImageCheckUtils.java | 23 +- 99 files changed, 4391 insertions(+), 4090 deletions(-) diff --git a/src-源文件/main/java/com/yf/exam/ability/Constant.java b/src-源文件/main/java/com/yf/exam/ability/Constant.java index 9880ea6..50e754d 100644 --- a/src-源文件/main/java/com/yf/exam/ability/Constant.java +++ b/src-源文件/main/java/com/yf/exam/ability/Constant.java @@ -1,15 +1,18 @@ +// 定义包路径,用于存放系统基础功能相关的类 package com.yf.exam.ability; - /** - * 通用常量 + * 通用常量类 + * 用于定义系统中使用的常量值,提供全局可访问的常量。 * @author bool */ public class Constant { - /** - * 文件上传路径 + * 文件上传路径的前缀常量 + * 用于指定上传文件的基础路径,所有上传的文件URL都会以这个路径开头。 + * 例如: /upload/file/example.jpg + * 这个前缀用于构建和解析文件的URL,以便在系统中统一管理和访问上传的文件。 */ public static final String FILE_PREFIX = "/upload/file/"; -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java index 2159361..058ab16 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobGroup.java @@ -1,13 +1,19 @@ +// 定义包路径,用于存放任务分组相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务分组 + * 任务分组枚举接口 + * 定义系统中不同类型任务的分组标识 + * 这个接口用于集中管理任务分组的常量值,确保代码的一致性和可维护性。 + * * @author van */ public interface JobGroup { /** - * 系统任务 + * 系统任务的分组标识 + * 用于标识系统级别的定时任务,如系统维护、数据清理等。 + * 这个标识符用于在任务调度系统中区分系统级别的任务,便于管理和执行。 */ - String SYSTEM = "system"; -} + String SYSTEM = "system"; // 系统任务组的标识符 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java index 2536f0e..dd51986 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/enums/JobPrefix.java @@ -1,14 +1,19 @@ +// 定义包路径,用于存放任务前缀相关的枚举类 package com.yf.exam.ability.job.enums; /** - * 任务前缀 + * 任务前缀枚举接口 + * 定义系统中不同任务类型的前缀标识 + * 这个接口用于集中管理任务的前缀常量值,确保代码的一致性和可维护性。 + * * @author bool */ public interface JobPrefix { /** - * 强制交卷的 + * 强制交卷任务的前缀标识 + * 用于标识与强制交卷相关的定时任务,方便在任务调度系统中识别和处理。 + * 例如:break_exam_12345 表示ID为12345的考试的强制交卷任务。 */ - String BREAK_EXAM = "break_exam_"; - -} + String BREAK_EXAM = "break_exam_"; // 强制交卷任务的前缀标识符 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java index cb465de..410c006 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/JobService.java @@ -1,53 +1,66 @@ +// 定义包路径,用于存放任务服务接口 package com.yf.exam.ability.job.service; /** - * 任务业务类,用于动态处理任务信息 + * 任务业务接口类,用于定义任务相关的业务操作 + * 这个接口定义了定时任务的基本操作,包括添加、暂停、恢复和删除任务。 + * * @author bool * @date 2020/11/29 下午2:17 */ public interface JobService { - /** - * 任务数据 + * 任务数据的键名常量 + * 用于在任务的JobDataMap中存储和检索任务相关数据的键名。 */ - String TASK_DATA = "taskData"; + String TASK_DATA = "taskData"; // 用于存储任务相关数据的键名 /** * 添加定时任务 - * @param jobClass - * @param jobName - * @param cron - * @param data + * 方法用于根据给定的任务类、名称、cron表达式和任务数据,添加一个新的定时任务。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param cron cron表达式,用于指定任务的执行计划 + * @param data 任务数据,传递给任务执行时的参数 */ void addCronJob(Class jobClass, String jobName, String cron, String data); /** * 添加立即执行的任务 - * @param jobClass - * @param jobName - * @param data + * 方法用于根据给定的任务类、名称和任务数据,添加一个新的立即执行的任务。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param data 任务数据,传递给任务执行时的参数 */ void addCronJob(Class jobClass, String jobName, String data); /** * 暂停任务 - * @param jobName - * @param jobGroup + * 方法用于根据任务名称和任务组,暂停一个正在运行的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 */ void pauseJob(String jobName, String jobGroup); /** * 恢复任务 - * @param triggerName - * @param triggerGroup + * 方法用于根据触发器名称和触发器组,恢复一个已暂停的定时任务。 + * + * @param triggerName 触发器名称 + * @param triggerGroup 触发器组 */ void resumeJob(String triggerName, String triggerGroup); /** - * 删除job - * @param jobName - * @param jobGroup + * 删除任务 + * 方法用于根据任务名称和任务组,删除一个定时任务,包括任务本身和相关的触发器。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 */ void deleteJob(String jobName, String jobGroup); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java index aafdfdb..b34ea8e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/job/service/impl/JobServiceImpl.java @@ -1,123 +1,186 @@ +// 定义包路径,用于存放任务服务实现类 package com.yf.exam.ability.job.service.impl; -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.yf.exam.ability.job.enums.JobGroup; -import com.yf.exam.ability.job.service.JobService; -import lombok.extern.log4j.Log4j2; -import org.quartz.*; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; +// 导入所需的外部依赖包 +import com.alibaba.fastjson.JSON; // 用于JSON数据处理 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 用于生成唯一ID +import com.yf.exam.ability.job.enums.JobGroup; // 任务分组枚举 +import com.yf.exam.ability.job.service.JobService; // 任务服务接口 +import lombok.extern.log4j.Log4j2; // 日志注解 +import org.quartz.*; // Quartz定时任务框架相关类 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 +import org.springframework.scheduling.quartz.SchedulerFactoryBean; // Quartz调度器工厂Bean +import org.springframework.stereotype.Service; // Spring服务注解 +import org.springframework.util.StringUtils; // Spring字符串工具类 /** + * 定时任务服务实现类 + * 用于管理系统中的定时任务,包括添加、暂停、恢复和删除任务。 * @author bool */ -@Log4j2 -@Service +@Log4j2 // 启用Log4j2日志 +@Service // 标记为Spring服务组件 public class JobServiceImpl implements JobService { /** - * Quartz定时任务核心的功能实现类 + * Quartz定时任务调度器 + * 用于管理和执行所有的定时任务 */ - private Scheduler scheduler; + private Scheduler scheduler; // 定时任务调度器实例 /** - * 注入 - * @param schedulerFactoryBean + * 构造函数,注入SchedulerFactoryBean + * 从Spring容器中注入Quartz调度器工厂Bean,并从中获取调度器实例。 + * @param schedulerFactoryBean Quartz调度器工厂Bean */ public JobServiceImpl(@Autowired SchedulerFactoryBean schedulerFactoryBean) { + // 从工厂Bean中获取调度器实例 scheduler = schedulerFactoryBean.getScheduler(); } - + /** + * 添加定时任务 + * 方法用于添加一个新的定时任务,包括cron表达式和立即执行两种情况。 + * + * @param jobClass 任务类,指定任务的执行类 + * @param jobName 任务名称,用于唯一标识任务 + * @param cron cron表达式,用于指定任务的执行计划 + * @param data 任务数据,传递给任务执行时的参数 + */ @Override public void addCronJob(Class jobClass, String jobName, String cron, String data) { - - + // 设置任务组为系统任务组 String jobGroup = JobGroup.SYSTEM; - // 自动命名 + // 如果任务名为空,则自动生成任务名 if(StringUtils.isEmpty(jobName)){ - jobName = jobClass.getSimpleName().toUpperCase() + "_"+IdWorker.getIdStr(); + // 使用类名大写+下划线+唯一ID作为任务名 + jobName = jobClass.getSimpleName().toUpperCase() + "_" + IdWorker.getIdStr(); } try { + // 创建任务键,用于唯一标识任务 JobKey jobKey = JobKey.jobKey(jobName, jobGroup); + // 获取任务详情 JobDetail jobDetail = scheduler.getJobDetail(jobKey); + + // 如果任务已存在,则删除旧任务 if (jobDetail != null) { log.info("++++++++++任务:{} 已存在", jobName); this.deleteJob(jobName, jobGroup); } + // 记录任务构建信息 log.info("++++++++++构建任务:{},{},{},{},{} ", jobClass.toString(), jobName, jobGroup, cron, data); - //构建job信息 + // 构建新的任务详情 jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroup).build(); - //用JopDataMap来传递数据 + // 设置任务数据 jobDetail.getJobDataMap().put(TASK_DATA, data); - //按新的cronExpression表达式构建一个新的trigger + // 声明触发器 Trigger trigger = null; - // 有表达式的按表达式 + // 如果有cron表达式,则创建cron触发器 if(!StringUtils.isEmpty(cron)){ log.info("+++++表达式执行:"+ JSON.toJSONString(jobDetail)); - //表达式调度构建器 + // 创建cron调度构建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron); - trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).withSchedule(scheduleBuilder).build(); + // 构建触发器 + trigger = TriggerBuilder.newTrigger() + .withIdentity(jobName, jobGroup) + .withSchedule(scheduleBuilder) + .build(); }else{ - // 无表达式则立即执行 + // 无cron表达式则立即执行一次 log.info("+++++立即执行:"+ JSON.toJSONString(jobDetail)); - trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).startNow().build(); + // 构建立即执行的触发器 + trigger = TriggerBuilder.newTrigger() + .withIdentity(jobName, jobGroup) + .startNow() + .build(); } + // 调度任务 scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { + // 打印异常堆栈信息 e.printStackTrace(); } } - + /** + * 添加立即执行的任务 + * 方法用于添加一个不需要cron表达式,立即执行一次的任务。 + * + * @param jobClass 任务类 + * @param jobName 任务名称 + * @param data 任务数据 + */ @Override public void addCronJob(Class jobClass, String jobName, String data) { - // 立即执行任务 + // 立即执行任务,不需要cron表达式,传入null this.addCronJob(jobClass, jobName, null, data); } - + /** + * 暂停任务 + * 方法用于暂停一个正在运行的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void pauseJob(String jobName, String jobGroup) { try { + // 创建触发器键并暂停触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.pauseTrigger(triggerKey); log.info("++++++++++暂停任务:{}", jobName); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } + /** + * 恢复任务 + * 方法用于恢复一个已暂停的定时任务。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void resumeJob(String jobName, String jobGroup) { try { + // 创建触发器键并恢复触发器 TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup); scheduler.resumeTrigger(triggerKey); log.info("++++++++++重启任务:{}", jobName); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } + /** + * 删除任务 + * 方法用于删除一个定时任务,包括任务本身和相关的触发器。 + * + * @param jobName 任务名称 + * @param jobGroup 任务组 + */ @Override public void deleteJob(String jobName, String jobGroup) { try { + // 创建任务键并删除任务 JobKey jobKey = JobKey.jobKey(jobName,jobGroup); scheduler.deleteJob(jobKey); log.info("++++++++++删除任务:{}", jobKey); } catch (SchedulerException e) { + // 打印异常堆栈信息 e.printStackTrace(); } } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java index 3bc2190..8d54a3e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/CNFilterFactoryBean.java @@ -1,29 +1,39 @@ +// 定义包路径,用于存放自定义过滤器相关的类 package com.yf.exam.ability.shiro; -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; -import org.apache.shiro.web.filter.InvalidRequestFilter; -import org.apache.shiro.web.filter.mgt.DefaultFilter; -import org.apache.shiro.web.filter.mgt.FilterChainManager; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类,用于配置Shiro过滤器 +import org.apache.shiro.web.filter.InvalidRequestFilter; // Shiro无效请求过滤器,用于处理无效请求 +import org.apache.shiro.web.filter.mgt.DefaultFilter; // Shiro默认过滤器,提供默认的过滤逻辑 +import org.apache.shiro.web.filter.mgt.FilterChainManager; // Shiro过滤器链管理器,管理过滤器链的配置 -import javax.servlet.Filter; -import java.util.Map; +import javax.servlet.Filter; // Servlet过滤器接口,定义了过滤器的基本操作 +import java.util.Map; // Map集合类,用于存储键值对 /** - * 自定义过滤器,用于处理中文URL问题 - * 如:下载文件中包含中文会返回400错误,https://youdomain.com/upload/file/云帆考试系统用户手册.pdf + * 自定义过滤器工厂类,用于创建和管理Shiro过滤器链 + * 主要解决中文URL问题,如下载文件中包含中文字符时可能会返回400错误。 + * 例如:https://youdomain.com/upload/file/云帆考试系统用户手册.pdf 这样的URL可能会因为中文字符而导致问题。 * @author van */ public class CNFilterFactoryBean extends ShiroFilterFactoryBean { + /** + * 创建过滤器链管理器 + * 覆盖父类的创建方法,添加自定义的过滤器配置。 + * @return FilterChainManager 过滤器链管理器实例 + */ @Override protected FilterChainManager createFilterChainManager() { - FilterChainManager manager = super.createFilterChainManager(); - // URL携带中文400,servletPath中文校验bug - Map filterMap = manager.getFilters(); - Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); + FilterChainManager manager = super.createFilterChainManager(); // 调用父类方法创建过滤器链管理器 + + // 获取过滤器映射,以便修改特定过滤器的配置 + Map filterMap = manager.getFilters(); + // 获取无效请求过滤器实例 + Filter invalidRequestFilter = filterMap.get(DefaultFilter.invalidRequest.name()); if (invalidRequestFilter instanceof InvalidRequestFilter) { + // 设置无效请求过滤器不阻止非ASCII字符,以允许中文URL ((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false); } - return manager; + return manager; // 返回配置好的过滤器链管理器 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java index 76af5c5..d9b5844 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/ShiroRealm.java @@ -1,131 +1,135 @@ +// 定义包路径,用于存放Shiro领域相关的类 package com.yf.exam.ability.shiro; - -import com.yf.exam.ability.shiro.jwt.JwtToken; -import com.yf.exam.ability.shiro.jwt.JwtUtils; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import com.yf.exam.modules.sys.user.service.SysUserRoleService; -import com.yf.exam.modules.sys.user.service.SysUserService; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.authc.AuthenticationException; -import org.apache.shiro.authc.AuthenticationInfo; -import org.apache.shiro.authc.AuthenticationToken; -import org.apache.shiro.authc.SimpleAuthenticationInfo; -import org.apache.shiro.authz.AuthorizationInfo; -import org.apache.shiro.authz.SimpleAuthorizationInfo; -import org.apache.shiro.realm.AuthorizingRealm; -import org.apache.shiro.subject.PrincipalCollection; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; - -import java.util.HashSet; -import java.util.List; +import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 +import com.yf.exam.ability.shiro.jwt.JwtUtils; // JWT工具类 +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 用户登录DTO +import com.yf.exam.modules.sys.user.service.SysUserRoleService; // 用户角色服务 +import com.yf.exam.modules.sys.user.service.SysUserService; // 用户服务 +import lombok.extern.slf4j.Slf4j; // 日志注解 +import org.apache.shiro.authc.AuthenticationException; // 认证异常 +import org.apache.shiro.authc.AuthenticationInfo; // 认证信息 +import org.apache.shiro.authc.AuthenticationToken; // 认证令牌 +import org.apache.shiro.authc.SimpleAuthenticationInfo; // 简单认证信息 +import org.apache.shiro.authz.AuthorizationInfo; // 授权信息 +import org.apache.shiro.authz.SimpleAuthorizationInfo; // 简单授权信息 +import org.apache.shiro.realm.AuthorizingRealm; // 授权领域 +import org.apache.shiro.subject.PrincipalCollection; // 主体集合 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解 +import org.springframework.context.annotation.Lazy; // 延迟注入注解 +import org.springframework.stereotype.Component; // Spring组件注解 + +import java.util.HashSet; // 哈希集合 +import java.util.List; // 列表 /** - * 用户登录鉴权和获取用户授权 + * 用户登录鉴权和获取用户授权的Shiro领域类 + * 负责用户的认证和授权,是Shiro框架中的核心组件之一。 * @author bool */ -@Component -@Slf4j +@Component // 标记为Spring组件 +@Slf4j // 启用Slf4j日志 public class ShiroRealm extends AuthorizingRealm { - @Autowired - @Lazy - private SysUserService sysUserService; - - @Autowired - @Lazy - private SysUserRoleService sysUserRoleService; - - - @Override - public boolean supports(AuthenticationToken token) { - return token instanceof JwtToken; - } - - - /** - * 详细授权认证 - * @param principals - * @return - */ - @Override - protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { - - String userId = null; - if (principals != null) { - SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); - userId = user.getId(); - } - SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); - - // 查找用户角色 - List roles = sysUserRoleService.listRoles(userId); - info.setRoles(new HashSet<>(roles)); - - log.info("++++++++++校验详细权限完成"); - return info; - } - - /** - * 校验用户的账号密码是否正确 - * @param auth - * @return - * @throws AuthenticationException - */ - @Override - protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { - String token = (String) auth.getCredentials(); - if (token == null) { - throw new AuthenticationException("token为空!"); - } - - // 校验token有效性 - SysUserLoginDTO user = this.checkToken(token); - return new SimpleAuthenticationInfo(user, token, getName()); - } - - - /** - * 校验Token的有效性 - * @param token - * @return - * @throws AuthenticationException - */ - public SysUserLoginDTO checkToken(String token) throws AuthenticationException { - - // 查询用户信息 - log.debug("++++++++++校验用户token: "+ token); - - // 从token中获取用户名 - String username = JwtUtils.getUsername(token); - log.debug("++++++++++用户名: "+ username); - - if (username == null) { - throw new AuthenticationException("无效的token"); - } - - // 查找登录用户对象 - SysUserLoginDTO user = sysUserService.token(token); - - // 校验token是否失效 - if (!JwtUtils.verify(token, username)) { - throw new AuthenticationException("登陆失效,请重试登陆!"); - } - - return user; - } - - - - /** - * 清除当前用户的权限认证缓存 - * @param principals - */ - @Override - public void clearCache(PrincipalCollection principals) { - super.clearCache(principals); + @Autowired + @Lazy // 延迟注入,避免循环依赖 + private SysUserService sysUserService; // 用户服务 + + @Autowired + @Lazy // 延迟注入,避免循环依赖 + private SysUserRoleService sysUserRoleService; // 用户角色服务 + + /** + * 判断是否支持JWT令牌 + * 确定当前领域是否支持处理JWT令牌类型的认证。 + * @param token 认证令牌 + * @return 是否支持JWT令牌 + */ + @Override + public boolean supports(AuthenticationToken token) { + // 判断是否支持JWT令牌 + return token instanceof JwtToken; // 返回是否为JwtToken + } + + /** + * 详细授权认证 + * 获取用户的授权信息,包括角色和权限。 + * @param principals 主体集合 + * @return 授权信息 + */ + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { + String userId = null; // 用户ID + if (principals != null) { + SysUserLoginDTO user = (SysUserLoginDTO) principals.getPrimaryPrincipal(); // 获取用户信息 + userId = user.getId(); // 获取用户ID + } + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 创建授权信息 + + // 查找用户角色 + List roles = sysUserRoleService.listRoles(userId); // 获取用户角色列表 + info.setRoles(new HashSet<>(roles)); // 设置角色 + + log.info("++++++++++校验详细权限完成"); // 日志记录 + return info; // 返回授权信息 + } + + /** + * 校验用户的账号密码是否正确 + * 根据传入的认证令牌,验证用户的账号密码。 + * @param auth 认证令牌 + * @return 认证信息 + * @throws AuthenticationException 认证异常 + */ + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { + String token = (String) auth.getCredentials(); // 获取token + if (token == null) { + throw new AuthenticationException("token为空!"); // 抛出异常 + } + + // 校验token有效性 + SysUserLoginDTO user = this.checkToken(token); // 验证token并获取用户信息 + return new SimpleAuthenticationInfo(user, token, getName()); // 返回认证信息 + } + + /** + * 校验Token的有效性 + * 验证JWT令牌的有效性,并获取对应的用户信息。 + * @param token JWT令牌 + * @return 用户登录DTO + * @throws AuthenticationException 认证异常 + */ + public SysUserLoginDTO checkToken(String token) throws AuthenticationException { + // 查询用户信息 + log.debug("++++++++++校验用户token: "+ token); // 日志记录 + + // 从token中获取用户名 + String username = JwtUtils.getUsername(token); // 获取用户名 + log.debug("++++++++++用户名: "+ username); // 日志记录 + + if (username == null) { + throw new AuthenticationException("无效的token"); // 抛出异常 + } + + // 查找登录用户对象 + SysUserLoginDTO user = sysUserService.token(token); // 获取用户信息 + + // 校验token是否失效 + if (!JwtUtils.verify(token, username)) { + throw new AuthenticationException("登陆失效,请重试登陆!"); // 抛出异常 + } + + return user; // 返回用户信息 } -} + /** + * 清除当前用户的权限认证缓存 + * 用于在用户信息变更后,清除缓存,确保权限信息的更新。 + * @param principals 主体集合 + */ + @Override + public void clearCache(PrincipalCollection principals) { + super.clearCache(principals); // 清除缓存 + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java index 88cf448..1fe9ff2 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/aop/JwtFilter.java @@ -1,53 +1,84 @@ +// 定义包路径,用于存放Shiro JWT认证过滤器相关的类 package com.yf.exam.ability.shiro.aop; +// 导入所需的外部依赖包 +import com.yf.exam.ability.shiro.jwt.JwtToken; // JWT令牌类 +import com.yf.exam.aspect.utils.InjectUtils; // 工具类,用于注入错误信息 +import com.yf.exam.modules.Constant; // 常量类 +import lombok.extern.slf4j.Slf4j; // 日志注解 +import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; // Shiro基础认证过滤器 -import com.yf.exam.ability.shiro.jwt.JwtToken; -import com.yf.exam.aspect.utils.InjectUtils; -import com.yf.exam.modules.Constant; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.ServletRequest; // Servlet请求接口 +import javax.servlet.ServletResponse; // Servlet响应接口 +import javax.servlet.http.HttpServletRequest; // HTTP请求类 +import javax.servlet.http.HttpServletResponse; // HTTP响应类 /** - * 鉴权登录拦截器 + * JWT认证过滤器 + * 用于处理基于JWT的身份认证,确保只有持有有效JWT令牌的请求才能访问受保护的资源。 * @author bool */ -@Slf4j +@Slf4j // 启用Slf4j日志 public class JwtFilter extends BasicHttpAuthenticationFilter { - /** - * 执行登录认证 - * @param request - * @param response - * @param mappedValue - * @return - */ - @Override - protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { - try { - executeLogin(request, response); - return true; - } catch (Exception e) { - // 写出统一错误信息 - InjectUtils.restError((HttpServletResponse) response); - return false; - } - } + /** + * 判断是否允许访问 + * 所有的请求都会经过这个方法,用于判断是否需要登录认证。 + * 如果请求不需要认证(如访问公开资源),则直接返回true允许访问; + * 如果需要认证,则尝试执行登录认证,根据认证结果决定是否允许访问。 + * + * @param request 请求对象 + * @param response 响应对象 + * @param mappedValue 映射值 + * @return 是否允许访问 + */ + @Override + protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { + try { + // 尝试执行登录认证 + executeLogin(request, response); + // 认证成功返回true + return true; + } catch (Exception e) { + // 认证失败时写入错误信息 + InjectUtils.restError((HttpServletResponse) response); + // 返回false表示不允许访问 + return false; + } + } + /** + * 执行登录认证 + * 从请求头中获取JWT token并进行认证,如果认证成功,则请求可以继续执行; + * 如果认证失败(如token无效或过期),则抛出异常,由isAccessAllowed方法处理。 + * + * @param request 请求对象 + * @param response 响应对象 + * @return 是否认证成功 + */ + @Override + protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { + // 将ServletRequest转换为HttpServletRequest + HttpServletRequest httpServletRequest = (HttpServletRequest) request; + // 从请求头中获取token + String token = httpServletRequest.getHeader(Constant.TOKEN); - @Override - protected boolean executeLogin(ServletRequest request, ServletResponse response) throws Exception { - HttpServletRequest httpServletRequest = (HttpServletRequest) request; - String token = httpServletRequest.getHeader(Constant.TOKEN); + // 如果token为空,则抛出异常 + if (token == null || "".equals(token)) { + throw new Exception("token不能为空"); + } - JwtToken jwtToken = new JwtToken(token); - // 提交给realm进行登入,如果错误他会抛出异常并被捕获 - getSubject(request, response).login(jwtToken); - // 如果没有抛出异常则代表登入成功,返回true - return true; - } -} + // 创建JWT token对象 + JwtToken jwtToken = new JwtToken(token); + // 提交给realm进行登录认证 + try { + getSubject(request, response).login(jwtToken); + // 如果没有抛出异常则表示登录成功 + return true; + } catch (Exception e) { + // 登录失败,记录日志 + log.error("JWT认证失败", e); + throw e; + } + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java index d5baab3..1e1fe4c 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtToken.java @@ -1,33 +1,50 @@ +// 定义包路径,用于存放JWT令牌相关的类 package com.yf.exam.ability.shiro.jwt; - -import lombok.Data; -import org.apache.shiro.authc.AuthenticationToken; + +import lombok.Data; // Lombok注解,用于生成getter和setter +import org.apache.shiro.authc.AuthenticationToken; // Shiro认证令牌接口 /** + * JWT令牌实现类 + * 实现Shiro的AuthenticationToken接口,用于JWT认证 * @author bool */ -@Data +@Data // 自动生成getter和setter方法 public class JwtToken implements AuthenticationToken { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化ID /** - * JWT的字符token + * JWT的字符串token + * 用于存储实际的JWT令牌字符串 */ - private String token; - + private String token; // JWT令牌字符串 + /** + * 构造函数 + * @param token JWT令牌字符串 + */ public JwtToken(String token) { - this.token = token; + this.token = token; // 设置token } + /** + * 获取身份信息 + * 实现AuthenticationToken接口的方法 + * @return 返回token作为身份信息 + */ @Override public Object getPrincipal() { - return token; + return token; // 返回token作为身份信息 } + /** + * 获取凭证信息 + * 实现AuthenticationToken接口的方法 + * @return 返回token作为凭证信息 + */ @Override public Object getCredentials() { - return token; + return token; // 返回token作为凭证信息 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java index 4a66759..ec2d907 100644 --- a/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/shiro/jwt/JwtUtils.java @@ -1,14 +1,15 @@ +// 定义包路径,用于存放JWT工具类 package com.yf.exam.ability.shiro.jwt; -import com.auth0.jwt.JWT; -import com.auth0.jwt.JWTVerifier; -import com.auth0.jwt.algorithms.Algorithm; -import com.auth0.jwt.exceptions.JWTDecodeException; -import com.auth0.jwt.interfaces.DecodedJWT; -import com.yf.exam.core.utils.file.Md5Util; +import com.auth0.jwt.JWT; // JWT工具类 +import com.auth0.jwt.JWTVerifier; // JWT验证器 +import com.auth0.jwt.algorithms.Algorithm; // JWT算法 +import com.auth0.jwt.exceptions.JWTDecodeException; // JWT解码异常 +import com.auth0.jwt.interfaces.DecodedJWT; // 解码后的JWT +import com.yf.exam.core.utils.file.Md5Util; // MD5工具类 -import java.util.Calendar; -import java.util.Date; +import java.util.Calendar; // 日历类 +import java.util.Date; // 日期类 /** * JWT工具类 @@ -19,81 +20,74 @@ public class JwtUtils { /** * 有效期24小时 */ - private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; - + private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; // JWT有效期 /** * 校验是否正确 - * @param token - * @param username - * @return + * @param token JWT令牌 + * @param username 用户名 + * @return 是否有效 */ public static boolean verify(String token, String username) { try { // 根据密码生成JWT效验器 - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); - JWTVerifier verifier = JWT.require(algorithm) - .withClaim("username", username) - .build(); + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 + JWTVerifier verifier = JWT.require(algorithm) // 创建验证器 + .withClaim("username", username) // 添加用户名声明 + .build(); // 构建验证器 // 效验TOKEN - verifier.verify(token); - return true; + verifier.verify(token); // 验证token + return true; // 返回验证成功 } catch (Exception exception) { - return false; + return false; // 返回验证失败 } } - - - - /** * 从Token中解密获得用户名 - * @param token - * @return + * @param token JWT令牌 + * @return 用户名 */ public static String getUsername(String token) { try { - DecodedJWT jwt = JWT.decode(token); - return jwt.getClaim("username").asString(); + DecodedJWT jwt = JWT.decode(token); // 解码JWT + return jwt.getClaim("username").asString(); // 获取用户名 } catch (JWTDecodeException e) { - return null; + return null; // 返回null表示解码失败 } } /** * 生成JWT Token字符串 - * @param username - * @return + * @param username 用户名 + * @return JWT令牌字符串 */ public static String sign(String username) { - Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); - Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); + Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); // 设置过期时间 + Algorithm algorithm = Algorithm.HMAC256(encryptSecret(username)); // 创建算法 // 附带username信息 - return JWT.create() - .withClaim("username", username) - .withExpiresAt(date).sign(algorithm); - + return JWT.create() // 创建JWT + .withClaim("username", username) // 添加用户名声明 + .withExpiresAt(date).sign(algorithm); // 设置过期时间并签名 } /** * 根据用户名和秘钥,生成一个新的秘钥,用于JWT加强一些安全性 - * @param userName - * @return + * @param userName 用户名 + * @return 加密后的秘钥 */ private static String encryptSecret(String userName){ - // 一个简单的登录规则,用户名+当前月份为加密串,意思每个月会变,要重新登录 // 可自行修改此规则 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - StringBuffer sb = new StringBuffer(userName) - .append("&") - .append(cl.get(Calendar.MONTH)); + Calendar cl = Calendar.getInstance(); // 获取当前日历 + cl.setTimeInMillis(System.currentTimeMillis()); // 设置当前时间 + StringBuffer sb = new StringBuffer(userName) // 创建字符串缓冲区 + .append("&") // 添加分隔符 + .append(cl.get(Calendar.MONTH)); // 添加当前月份 // 获取MD5 - String secret = Md5Util.md5(sb.toString()); + String secret = Md5Util.md5(sb.toString()); // 生成MD5秘钥 - return Md5Util.md5(userName + "&" + secret); + return Md5Util.md5(userName + "&" + secret); // 返回加密后的秘钥 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java index e35d73d..a0cb14b 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/config/UploadConfig.java @@ -1,32 +1,36 @@ +// 定义包路径,用于存放文件上传配置相关的类 package com.yf.exam.ability.upload.config; -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - +import lombok.Data; // Lombok注解,用于简化数据类的编写,自动生成getter和setter +import org.springframework.boot.context.properties.ConfigurationProperties; // Spring Boot配置属性注解,用于将配置文件中的属性绑定到Java对象 +import org.springframework.context.annotation.Configuration; // Spring配置注解,标记为配置类 /** - * 文件上传配置 + * 文件上传配置类 + * 用于定义文件上传的相关配置,如访问路径、物理目录和允许的文件后缀等。 + * 这些配置通常在application.yml或application.properties中定义,并由Spring Boot自动加载。 * @author van */ -@Data -@Configuration -@ConfigurationProperties(prefix = "conf.upload") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@Configuration // 标记为Spring配置类,表示这是一个配置类 +@ConfigurationProperties(prefix = "conf.upload") // 指定配置文件中属性的前缀,这里是"conf.upload" public class UploadConfig { /** - * 访问路径 + * 文件访问路径 + * 定义文件上传后对外访问的基础URL路径。 */ - private String url; + private String url; // 文件访问的URL /** - * 物理目录 + * 文件存储物理目录 + * 定义文件上传后在服务器上的存储路径。 */ - private String dir; + private String dir; // 文件存储的物理目录 /** - * 允许的后缀 + * 允许的文件后缀 + * 定义允许上传的文件类型,通过文件后缀来限制。 */ - private String [] allowExtensions; - -} + private String[] allowExtensions; // 允许上传的文件后缀 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java index 4c85250..1849a4b 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/controller/UploadController.java @@ -1,57 +1,62 @@ +// 定义包路径,用于存放文件上传下载请求类 package com.yf.exam.ability.upload.controller; +import com.yf.exam.ability.Constant; // 常量类,包含系统配置的常量值 +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 文件上传请求DTO,封装上传文件所需的数据 +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 文件上传响应DTO,封装上传文件后的响应数据 +import com.yf.exam.ability.upload.service.UploadService; // 文件上传服务,提供文件上传和下载的业务逻辑 +import com.yf.exam.core.api.ApiRest; // API响应类,封装统一的API响应格式 +import com.yf.exam.core.api.controller.BaseController; // 基础控制器,提供基础的控制器功能 +import io.swagger.annotations.Api; // Swagger API注解,用于描述API信息 +import io.swagger.annotations.ApiOperation; // Swagger API操作注解,用于描述单个API操作 +import lombok.extern.log4j.Log4j2; // 日志注解,提供日志功能 +import org.springframework.beans.factory.annotation.Autowired; // Spring自动注入注解,用于注入Spring管理的Bean +import org.springframework.web.bind.annotation.GetMapping; // GET请求映射注解,用于映射GET请求到方法 +import org.springframework.web.bind.annotation.ModelAttribute; // 模型属性注解,用于将请求参数绑定到模型对象 +import org.springframework.web.bind.annotation.PostMapping; // POST请求映射注解,用于映射POST请求到方法 +import org.springframework.web.bind.annotation.RestController; // REST控制器注解,标记为REST风格的控制器 -import com.yf.exam.ability.Constant; -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; -import com.yf.exam.ability.upload.service.UploadService; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import lombok.extern.log4j.Log4j2; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletRequest; // HTTP请求类,表示HTTP请求 +import javax.servlet.http.HttpServletResponse; // HTTP响应类,表示HTTP响应 /** * 本地文件上传下载请求类 + * 负责处理文件上传和下载的请求,提供RESTful API接口。 * @author bool */ -@Log4j2 -@Api(tags = {"文件上传"}) -@RestController +@Log4j2 // 启用Log4j2日志 +@Api(tags = {"文件上传"}) // Swagger API标签,用于分类API +@RestController // 标记为REST控制器,表示该类是一个REST风格的控制器 public class UploadController extends BaseController { @Autowired - private UploadService uploadService; + private UploadService uploadService; // 文件上传服务,自动注入 /** * 文件上传 - * @param reqDTO - * @return + * 处理文件上传请求,接收上传文件的数据,并返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应,封装上传文件后的响应数据 */ - @PostMapping("/common/api/file/upload") - @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") + @PostMapping("/common/api/file/upload") // POST请求映射,指定请求路径 + @ApiOperation(value = "文件上传", notes = "此接口较为特殊,参数都通过表单方式提交,而非JSON") // Swagger API操作描述 public ApiRest upload(@ModelAttribute UploadReqDTO reqDTO) { // 上传并返回URL - UploadRespDTO respDTO = uploadService.upload(reqDTO); - return super.success(respDTO); + UploadRespDTO respDTO = uploadService.upload(reqDTO); // 调用上传服务 + return super.success(respDTO); // 返回成功响应 } /** * 独立文件下载 - * @param request - * @param response + * 处理文件下载请求,根据请求参数返回对应的文件。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 */ - @GetMapping(Constant.FILE_PREFIX+"**") - @ApiOperation(value = "文件下载", notes = "文件下载") + @GetMapping(Constant.FILE_PREFIX+"**") // GET请求映射,指定请求路径前缀 + @ApiOperation(value = "文件下载", notes = "文件下载") // Swagger API操作描述 public void download(HttpServletRequest request, HttpServletResponse response) { - uploadService.download(request, response); + uploadService.download(request, response); // 调用下载服务 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java index df2f286..0e4a0f1 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadReqDTO.java @@ -1,22 +1,26 @@ +// 定义包路径,用于存放文件上传请求DTO package com.yf.exam.ability.upload.dto; - -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.springframework.web.multipart.MultipartFile; +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 +import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写,自动生成getter和setter +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 /** * 文件上传请求类 - * @author + * 用于封装文件上传请求中的数据,包括上传的文件内容。 + * @author van * @date 2019-12-26 17:54 */ -@Data -@ApiModel(value="文件上传参数", description="文件上传参数") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@ApiModel(value="文件上传参数", description="文件上传参数") // 使用Swagger注解,描述API模型 public class UploadReqDTO extends BaseDTO { - @ApiModelProperty(value = "上传文件内容", required=true) - private MultipartFile file; - -} + /** + * 上传文件内容 + * 用于存储上传文件的数据,包括文件名、文件类型、文件大小等信息。 + */ + @ApiModelProperty(value = "上传文件内容", required=true) // 使用Swagger注解,描述API模型属性 + private MultipartFile file; // 上传的文件内容 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java index b91106e..cbce697 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/dto/UploadRespDTO.java @@ -1,23 +1,28 @@ +// 定义包路径,用于存放文件上传响应DTO package com.yf.exam.ability.upload.dto; -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类,提供通用的数据传输对象功能 +import io.swagger.annotations.ApiModel; // 导入Swagger API模型注解,用于描述API模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger API模型属性注解,用于描述API模型的属性 +import lombok.AllArgsConstructor; // 导入Lombok注解,用于生成全参构造函数 +import lombok.Data; // 导入Lombok注解,用于生成getter和setter方法 +import lombok.NoArgsConstructor; // 导入Lombok注解,用于生成无参构造函数 /** - * 上传文件结果 + * 文件上传响应DTO + * 用于封装文件上传操作的结果,包括上传后的文件URL等信息。 * @author bool */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@ApiModel(value="文件上传响应", description="文件上传响应") +@Data // 使用Lombok注解,自动生成getter和setter方法 +@AllArgsConstructor // 使用Lombok注解,生成全参构造函数 +@NoArgsConstructor // 使用Lombok注解,生成无参构造函数 +@ApiModel(value="文件上传响应", description="文件上传响应") // 使用Swagger注解,描述API模型 public class UploadRespDTO extends BaseDTO { - @ApiModelProperty(value = "上传后的完整的URL地址", required=true) - private String url; - -} + /** + * 上传后的完整URL地址 + * 存储文件上传成功后,文件的完整访问URL地址。 + */ + @ApiModelProperty(value = "上传后的完整的URL地址", required=true) // 使用Swagger注解,描述API模型属性 + private String url; // 上传后的完整URL地址 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java index ef516ec..44617b6 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/UploadService.java @@ -1,30 +1,62 @@ package com.yf.exam.ability.upload.service; +// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.service。 +// 包用于组织和管理相关的Java类,避免类名冲突,方便代码的模块化和复用。 -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO +// 导入了名为UploadReqDTO的类,它位于com.yf.exam.ability.upload.dto包下。 +// 这个类通常用于封装文件上传请求相关的数据,比如要上传的文件信息、上传的相关参数等。 -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO +// 导入了名为UploadRespDTO的类,同样位于com.yf.exam.ability.upload.dto包下。 +// 它主要用于封装文件上传操作完成后返回的响应数据,例如上传是否成功的标识、上传后的文件存储路径等信息。 + +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类 +// 引入了Java EE中用于处理HTTP请求的标准类HttpServletRequest。 +// 在文件下载等操作中,会通过这个类获取客户端发送过来的关于下载请求的各种信息,如请求的URL、请求头信息等。 + +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类 +// 引入了Java EE中用于处理HTTP响应的标准类HttpServletResponse。 +// 在文件下载操作中,会使用这个类来设置响应的状态码、响应头信息以及将文件内容返回给客户端。 /** - * 阿里云OSS业务类 - * @author bool + * 文件上传服务接口 + * 定义文件上传和下载的相关业务操作,提供统一的接口供外部调用。 + * @author bool * @date 2019-07-12 16:45 */ +// 这是一个Java接口的文档注释,用于描述该接口的整体功能和用途。 +// 说明这个接口主要是用来定义与文件上传和下载相关的业务操作方法, +// 并且其他类可以通过实现这个接口来提供具体的实现,以达到统一调用的目的。 +// 同时标注了接口的作者是bool,创建日期是2019年7月12日16:45。 + public interface UploadService { + // 这里定义了一个名为UploadService的公共接口。 + // 接口中只包含方法的声明,不包含方法的具体实现,具体实现由实现该接口的类来完成。 /** * 文件上传 - * @param reqDTO - * @return + * 方法用于处理文件上传请求,接收上传文件的数据,并返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应DTO,封装上传文件后的响应数据 */ + // 这是接口中定义的一个方法声明,名为upload。 + // 它的功能是处理文件上传请求,通过接收传入的UploadReqDTO对象(其中包含了上传文件所需的各种数据), + // 然后在具体实现类中执行实际的上传操作,最后返回一个UploadRespDTO对象,该对象封装了上传文件后的响应数据。 + UploadRespDTO upload(UploadReqDTO reqDTO); /** - * 下载文件 - * @param request - * @param response + * 文件下载 + * 方法用于处理文件下载请求,根据请求参数返回对应的文件。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 */ - void download(HttpServletRequest request, HttpServletResponse response); + // 这是接口中定义的另一个方法声明,名为download。 + // 它用于处理文件下载请求,会接收一个HttpServletRequest对象(其中包含了客户端发送的关于下载请求的所有信息) + // 和一个HttpServletResponse对象(用于设置响应相关的信息并将文件内容返回给客户端), + // 在具体实现类中根据请求参数找到对应的要下载的文件,并通过HttpServletResponse将文件内容返回给客户端。 -} + void download(HttpServletRequest request, HttpServletResponse response); +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java index ef70f40..6d1a60e 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/service/impl/UploadServiceImpl.java @@ -1,135 +1,143 @@ +// 定义包路径,用于存放文件上传服务实现类 package com.yf.exam.ability.upload.service.impl; -import com.yf.exam.ability.Constant; -import com.yf.exam.ability.upload.config.UploadConfig; -import com.yf.exam.ability.upload.dto.UploadReqDTO; -import com.yf.exam.ability.upload.dto.UploadRespDTO; -import com.yf.exam.ability.upload.service.UploadService; -import com.yf.exam.ability.upload.utils.FileUtils; -import com.yf.exam.core.exception.ServiceException; -import lombok.extern.log4j.Log4j2; -import org.apache.commons.io.FilenameUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.FileCopyUtils; -import org.springframework.web.multipart.MultipartFile; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import com.yf.exam.ability.Constant; // 导入常量类,包含系统配置的常量值 +import com.yf.exam.ability.upload.config.UploadConfig; // 导入文件上传配置类,包含文件上传的相关配置 +import com.yf.exam.ability.upload.dto.UploadReqDTO; // 导入文件上传请求DTO,封装上传文件所需的数据 +import com.yf.exam.ability.upload.dto.UploadRespDTO; // 导入文件上传响应DTO,封装上传文件后的响应数据 +import com.yf.exam.ability.upload.service.UploadService; // 导入文件上传服务接口,定义文件上传的相关业务操作 +import com.yf.exam.ability.upload.utils.FileUtils; // 导入文件工具类,提供文件操作的辅助功能 +import com.yf.exam.core.exception.ServiceException; // 导入服务异常类,处理业务逻辑中的异常情况 +import lombok.extern.log4j.Log4j2; // 导入日志注解,提供日志功能 +import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,提供文件名和扩展名操作的辅助功能 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring自动注入注解,用于注入Spring管理的Bean +import org.springframework.stereotype.Service; // 导入Spring服务注解,标记为服务组件 +import org.springframework.util.FileCopyUtils; // 导入文件复制工具类,提供文件复制的功能 +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,处理上传的文件 + +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示HTTP请求 +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示HTTP响应 +import java.io.FileOutputStream; // 导入文件输出流,用于将文件内容写入文件 +import java.io.IOException; // 导入IO异常类,处理IO操作中的异常情况 +import java.io.UnsupportedEncodingException; // 导入不支持的编码异常类,处理编码问题 +import java.net.URLDecoder; // 导入URL解码类,用于解码URL +import java.util.regex.Matcher; // 导入正则表达式匹配器,用于匹配正则表达式 +import java.util.regex.Pattern; // 导入正则表达式类,用于编译正则表达式 /** * 文件上传业务类 + * 实现文件上传服务接口,提供文件上传和下载的业务逻辑。 * @author bool * @date 2019-07-30 21:02 */ -@Log4j2 -@Service +@Log4j2 // 使用Log4j2日志注解,启用日志功能 +@Service // 使用Spring服务注解,标记为服务组件 public class UploadServiceImpl implements UploadService { @Autowired - private UploadConfig conf; + private UploadConfig conf; // 自动注入文件上传配置 + /** + * 文件上传 + * 实现文件上传业务逻辑,包括文件验证、文件保存和返回上传结果。 + * + * @param reqDTO 上传请求DTO,包含上传文件所需的数据 + * @return 上传响应DTO,封装上传文件后的响应数据 + */ @Override public UploadRespDTO upload(UploadReqDTO reqDTO) { - - // 文件内容 - MultipartFile file = reqDTO.getFile(); + MultipartFile file = reqDTO.getFile(); // 获取上传的文件 // 验证文件后缀 - boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); + boolean allow = FilenameUtils.isExtension(file.getOriginalFilename(), conf.getAllowExtensions()); // 验证文件后缀 if(!allow){ - throw new ServiceException("文件类型不允许上传!"); + throw new ServiceException("文件类型不允许上传!"); // 抛出异常 } // 上传文件夹 - String fileDir = conf.getDir(); + String fileDir = conf.getDir(); // 获取文件存储目录 // 真实物理地址 String fullPath; try { - // 新文件 - String filePath = FileUtils.processPath(file); + String filePath = FileUtils.processPath(file); // 处理文件路径 // 文件保存地址 - fullPath = fileDir + filePath; + fullPath = fileDir + filePath; // 拼接完整路径 // 创建文件夹 - FileUtils.checkDir(fullPath); + FileUtils.checkDir(fullPath); // 检查并创建文件夹 // 上传文件 - FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); + FileCopyUtils.copy(file.getInputStream(), new FileOutputStream(fullPath)); // 复制文件内容到指定路径 - return this.generateResult(filePath); + return this.generateResult(filePath); // 返回上传结果 } catch (IOException e) { - e.printStackTrace(); - throw new ServiceException("文件上传失败:"+e.getMessage()); + e.printStackTrace(); // 打印异常堆栈 + throw new ServiceException("文件上传失败:"+e.getMessage()); // 抛出异常 } } - - + /** + * 独立文件下载 + * 实现文件下载业务逻辑,包括获取文件真实路径和返回文件内容。 + * + * @param request HTTP请求,包含下载请求的信息 + * @param response HTTP响应,用于返回文件内容 + */ @Override public void download(HttpServletRequest request, HttpServletResponse response) { - // 获取真实的文件路径 - String filePath = this.getRealPath(request.getRequestURI()); + String filePath = this.getRealPath(request.getRequestURI()); // 获取文件的真实路径 // 处理中文问题 try { - filePath = URLDecoder.decode(filePath, "utf-8"); + filePath = URLDecoder.decode(filePath, "utf-8"); // 解码文件路径 } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); + throw new RuntimeException(e); // 抛出运行时异常 } - System.out.println("++++完整路径为:"+filePath); + System.out.println("++++完整路径为:"+filePath); // 打印完整路径 try { - FileUtils.writeRange(request, response, filePath); + FileUtils.writeRange(request, response, filePath); // 调用文件工具类进行文件写入 } catch (IOException e) { - response.setStatus(404); - log.error("预览文件失败" + e.getMessage()); + response.setStatus(404); // 设置响应状态为404 + log.error("预览文件失败" + e.getMessage()); // 打印错误日志 } } - /** * 构造返回 - * @param fileName - * @return + * 根据文件名构造上传响应DTO,包含上传后的完整URL地址。 + * + * @param fileName 文件名 + * @return 上传响应DTO */ private UploadRespDTO generateResult(String fileName) { - //获取加速域名 - String domain = conf.getUrl(); + String domain = conf.getUrl(); // 获取文件访问的URL // 返回结果 - return new UploadRespDTO(domain + fileName); + return new UploadRespDTO(domain + fileName); // 返回上传响应DTO } - /** * 获取真实物理文件地址 - * @param uri - * @return + * 根据请求URI获取文件的真实物理路径。 + * + * @param uri 请求URI + * @return 真实文件路径 */ public String getRealPath(String uri){ - - String regx = Constant.FILE_PREFIX+"(.*)"; + String regx = Constant.FILE_PREFIX+"(.*)"; // 正则表达式匹配文件路径 // 查找全部变量 - Pattern pattern = Pattern.compile(regx); - Matcher m = pattern.matcher(uri); + Pattern pattern = Pattern.compile(regx); // 编译正则表达式 + Matcher m = pattern.matcher(uri); // 创建匹配器 if (m.find()) { - String str = m.group(1); - return conf.getDir() + str; + String str = m.group(1); // 获取匹配的文件路径 + return conf.getDir() + str; // 返回真实文件路径 } - return null; + return null; // 返回null表示未找到 } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java index 539ecb0..0c45c41 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/FileUtils.java @@ -1,172 +1,169 @@ +// 定义包路径,用于存放文件工具类 package com.yf.exam.ability.upload.utils; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.yf.exam.core.utils.DateUtils; -import org.apache.commons.io.FilenameUtils; -import org.springframework.web.multipart.MultipartFile; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入ID生成工具,用于生成唯一的文件名 +import com.yf.exam.core.utils.DateUtils; // 导入日期工具类,用于处理日期相关的操作 +import org.apache.commons.io.FilenameUtils; // 导入文件名工具类,用于处理文件名和扩展名 +import org.springframework.web.multipart.MultipartFile; // 导入Spring文件上传类,用于处理上传的文件 -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.util.Date; +import javax.servlet.ServletOutputStream; // 导入Servlet输出流,用于写入HTTP响应 +import javax.servlet.http.HttpServletRequest; // 导入HTTP请求类,表示客户端的请求 +import javax.servlet.http.HttpServletResponse; // 导入HTTP响应类,表示服务器的响应 +import java.io.File; // 导入文件类,用于操作文件和目录 +import java.io.IOException; // 导入IO异常类,处理IO操作中的异常 +import java.io.RandomAccessFile; // 导入随机访问文件类,用于高效地读写文件 +import java.util.Date; // 导入日期类,用于处理日期和时间 /** * 文件工具类 + * 提供文件操作的辅助功能,包括文件上传、下载、重命名和目录管理等。 * @author bool */ public class FileUtils { - /** - * 后缀分割符号 - */ - private static final String SUFFIX_SPLIT = "."; - - - /** - * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 - * @param request - * @param response - * @param filePath - * @throws IOException - */ - public static void writeRange(HttpServletRequest request, - HttpServletResponse response, String filePath) throws IOException { - - // 读取文件 - File file = new File(filePath); - - //只读模式 - RandomAccessFile randomFile = new RandomAccessFile(file, "r"); - long contentLength = randomFile.length(); - String range = request.getHeader("Range"); - int start = 0, end = 0; - if (range != null && range.startsWith("bytes=")) { - String[] values = range.split("=")[1].split("-"); - start = Integer.parseInt(values[0]); - if (values.length > 1) { - end = Integer.parseInt(values[1]); - } - } - int requestSize; - if (end != 0 && end > start) { - requestSize = end - start + 1; - } else { - requestSize = Integer.MAX_VALUE; - } - - byte[] buffer = new byte[128]; - response.setContentType(MediaUtils.getContentType(filePath)); - response.setHeader("Accept-Ranges", "bytes"); - response.setHeader("ETag", file.getName()); - response.setHeader("Last-Modified", new Date().toString()); - //第一次请求只返回content length来让客户端请求多次实际数据 - if (range == null) { - response.setHeader("Content-length", contentLength + ""); - } else { - //以后的多次以断点续传的方式来返回视频数据 - response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - long requestStart = 0, requestEnd = 0; - String[] ranges = range.split("="); - if (ranges.length > 1) { - String[] rangeData = ranges[1].split("-"); - requestStart = Integer.parseInt(rangeData[0]); - if (rangeData.length > 1) { - requestEnd = Integer.parseInt(rangeData[1]); - } - } - long length; - if (requestEnd > 0) { - length = requestEnd - requestStart + 1; - response.setHeader("Content-length", "" + length); - response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); - } else { - length = contentLength - requestStart; - response.setHeader("Content-length", "" + length); - response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); - } - } - ServletOutputStream out = response.getOutputStream(); - int needSize = requestSize; - randomFile.seek(start); - while (needSize > 0) { - int len = randomFile.read(buffer); - if (needSize < buffer.length) { - out.write(buffer, 0, needSize); - } else { - out.write(buffer, 0, len); - if (len < buffer.length) { - break; - } - } - needSize -= buffer.length; - } - randomFile.close(); - out.close(); - } - - - - - /** - * 重命名文件 - * @param fileName - * @return - */ - public static String renameFile(String fileName) { - - //没有后缀名不处理 - if (!fileName.contains(SUFFIX_SPLIT)) { - return fileName; - } - - //文件后缀 - String extension = FilenameUtils.getExtension(fileName); - - //以系统时间命名 - return IdWorker.getIdStr() + "."+ extension; - - } - - - /** - * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 - * @param file 文件 - * @return - */ - public static String processPath(MultipartFile file){ - - // 创建OSSClient实例。 - String fileName = file.getOriginalFilename(); - - // 需要重命名 - fileName = renameFile(fileName); - - //获得上传的文件夹 - String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); - - return new StringBuffer(dir).append(fileName).toString(); - - } - - /** - * 检查文件夹是否存在,不存在则创建 - * @param fileName - * @return - */ - public static void checkDir(String fileName){ - int index = fileName.lastIndexOf("/"); - if(index == -1){ - return; - } - - File file = new File(fileName.substring(0,index)); - if(!file.exists()){ - file.mkdirs(); - } - } - - -} + /** + * 后缀分割符号 + * 用于分割文件名和扩展名。 + */ + private static final String SUFFIX_SPLIT = "."; // 文件后缀分隔符 + + /** + * 支持以断点的方式输出文件,提供文件在线预览和视频在线播放 + * 方法用于处理HTTP请求,以断点续传的方式输出文件内容,支持文件在线预览和视频在线播放。 + * + * @param request HTTP请求,包含客户端的请求信息 + * @param response HTTP响应,包含服务器的响应信息 + * @param filePath 文件路径,指定要输出的文件 + * @throws IOException IO异常,处理文件操作中的异常 + */ + public static void writeRange(HttpServletRequest request, HttpServletResponse response, String filePath) throws IOException { + // 读取文件 + File file = new File(filePath); // 创建文件对象 + + // 只读模式 + RandomAccessFile randomFile = new RandomAccessFile(file, "r"); // 创建随机访问文件对象 + long contentLength = randomFile.length(); // 获取文件长度 + String range = request.getHeader("Range"); // 获取请求头中的Range + int start = 0, end = 0; // 初始化起始和结束位置 + if (range != null && range.startsWith("bytes=")) { + String[] values = range.split("=")[1].split("-"); // 解析Range + start = Integer.parseInt(values[0]); // 获取起始位置 + if (values.length > 1) { + end = Integer.parseInt(values[1]); // 获取结束位置 + } + } + int requestSize; // 请求大小 + if (end != 0 && end > start) { + requestSize = end - start + 1; // 计算请求大小 + } else { + requestSize = Integer.MAX_VALUE; // 设置为最大值 + } + + byte[] buffer = new byte[128]; // 创建缓冲区 + response.setContentType(MediaUtils.getContentType(filePath)); // 设置响应内容类型 + response.setHeader("Accept-Ranges", "bytes"); // 设置支持的范围 + response.setHeader("ETag", file.getName()); // 设置文件名 + response.setHeader("Last-Modified", new Date().toString()); // 设置最后修改时间 + // 第一次请求只返回content length来让客户端请求多次实际数据 + if (range == null) { + response.setHeader("Content-length", contentLength + ""); // 设置内容长度 + } else { + // 以后的多次以断点续传的方式来返回视频数据 + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); // 设置部分内容状态 + long requestStart = 0, requestEnd = 0; // 初始化请求起始和结束位置 + String[] ranges = range.split("="); // 解析Range + if (ranges.length > 1) { + String[] rangeData = ranges[1].split("-"); // 获取范围数据 + requestStart = Integer.parseInt(rangeData[0]); // 获取请求起始位置 + if (rangeData.length > 1) { + requestEnd = Integer.parseInt(rangeData[1]); // 获取请求结束位置 + } + } + long length; // 请求长度 + if (requestEnd > 0) { + length = requestEnd - requestStart + 1; // 计算请求长度 + response.setHeader("Content-length", "" + length); // 设置内容长度 + response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength); // 设置内容范围 + } else { + length = contentLength - requestStart; // 计算请求长度 + response.setHeader("Content-length", "" + length); // 设置内容长度 + response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" + contentLength); // 设置内容范围 + } + } + ServletOutputStream out = response.getOutputStream(); // 获取输出流 + int needSize = requestSize; // 需要的大小 + randomFile.seek(start); // 移动到起始位置 + while (needSize > 0) { + int len = randomFile.read(buffer); // 读取文件内容 + if (needSize < buffer.length) { + out.write(buffer, 0, needSize); // 写入需要的大小 + } else { + out.write(buffer, 0, len); // 写入缓冲区内容 + if (len < buffer.length) { + break; // 如果读取的长度小于缓冲区长度,退出循环 + } + } + needSize -= buffer.length; // 减少需要的大小 + } + randomFile.close(); // 关闭随机访问文件 + out.close(); // 关闭输出流 + } + + /** + * 重命名文件 + * 方法用于生成新的文件名,避免文件名冲突。 + * + * @param fileName 文件名 + * @return 新文件名 + */ + public static String renameFile(String fileName) { + // 没有后缀名不处理 + if (!fileName.contains(SUFFIX_SPLIT)) { + return fileName; // 返回原文件名 + } + + // 文件后缀 + String extension = FilenameUtils.getExtension(fileName); // 获取文件后缀 + + // 以系统时间命名 + return IdWorker.getIdStr() + "." + extension; // 返回新文件名 + } + + /** + * 处理新的文件路径,为上传文件预设目录,如:2021/01/01/xxx.jpg,要注意的是,前面没有斜杠 + * 方法用于处理上传文件的路径,根据当前日期生成目录结构。 + * + * @param file 文件 + * @return 处理后的文件路径 + */ + public static String processPath(MultipartFile file) { + // 创建OSSClient实例。 + String fileName = file.getOriginalFilename(); // 获取原始文件名 + + // 需要重命名 + fileName = renameFile(fileName); // 重命名文件 + + // 获得上传的文件夹 + String dir = DateUtils.formatDate(new Date(), "yyyy/MM/dd/"); // 获取当前日期格式化后的目录 + + return new StringBuffer(dir).append(fileName).toString(); // 返回处理后的文件路径 + } + + /** + * 检查文件夹是否存在,不存在则创建 + * 方法用于检查指定的文件夹是否存在,如果不存在则创建。 + * + * @param fileName 文件名 + */ + public static void checkDir(String fileName) { + int index = fileName.lastIndexOf("/"); // 获取最后一个斜杠的位置 + if (index == -1) { + return; // 如果没有斜杠,返回 + } + + File file = new File(fileName.substring(0, index)); // 创建文件对象 + if (!file.exists()) { + file.mkdirs(); // 如果文件夹不存在,创建文件夹 + } + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java index b4394c0..aff5557 100644 --- a/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java +++ b/src-源文件/main/java/com/yf/exam/ability/upload/utils/MediaUtils.java @@ -1,47 +1,75 @@ package com.yf.exam.ability.upload.utils; +// 这一行声明了该Java类所属的包名为com.yf.exam.ability.upload.utils。 +// 包用于对相关的Java类进行组织和管理,方便代码的分类、复用以及避免类名冲突。 -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类,用于字符串操作 +// 引入了Apache Commons Lang库中的StringUtils类。 +// 这个类提供了许多方便的字符串操作方法,比如判断字符串是否为空、是否空白(包含空格等空白字符)、字符串的拼接、截取等操作,在这里主要用于对文件路径字符串进行相关判断。 -import java.util.HashMap; -import java.util.Map; +import java.util.HashMap; // 导入Java的HashMap类,用于创建映射 +// 导入了Java标准库中的HashMap类。 +// HashMap是实现了Map接口的一个具体类,它用于存储键值对形式的数据,通过键可以快速获取对应的值,在这里用于创建文件后缀名到MIME类型的映射关系。 + +import java.util.Map; // 导入Java的Map接口,用于键值对映射 +// 引入了Java标准库中的Map接口。 +// Map接口定义了键值对数据结构的通用操作规范,如添加键值对、根据键获取值、删除键值对等操作。 +// 虽然这里同时导入了HashMap类,但导入Map接口使得代码在使用映射数据结构时更具通用性,方便后续可能的替换为其他实现Map接口的类。 /** - * 媒体工具,判断媒体类型 - * @author bool + * 媒体工具类,用于判断和获取媒体文件的MIME类型 + * 该类提供了一个静态映射,用于将文件后缀名映射到对应的MIME类型,以便在处理文件上传和下载时确定正确的媒体类型。 + * @author bool * @date 2019-11-14 16:21 */ -public class MediaUtils { +// 这是一个Java类的文档注释,用于描述该类的整体功能和用途。 +// 说明这个类主要是作为媒体工具类,其核心功能是判断和获取媒体文件的MIME类型。 +// 通过维护一个静态的映射关系(文件后缀名到MIME类型的映射),在文件上传和下载的业务场景中,能够依据文件的后缀名准确地确定其对应的MIME类型,从而正确处理文件的传输和展示等操作。 +// 同时标注了类的作者是bool,创建日期是2019年11月14日16:21。 - public static final Map MEDIA_MAP = new HashMap(){ - { +public class MediaUtils { - //本来是pdf的 - put(".pdf", "application/pdf"); + /** + * 媒体类型映射 + * 静态映射,包含文件后缀名到MIME类型的映射。 + */ + // 这是对下面定义的MEDIA_MAP成员变量的文档注释,说明它是一个静态的映射,用于存储文件后缀名和对应的MIME类型之间的映射关系。 - //视频 - put(".mp4", "video,video/mp4"); - - } - }; + public static final Map MEDIA_MAP = new HashMap() {{ + // 初始化映射 + // PDF文件的MIME类型 + put(".pdf", "application/pdf"); + // 视频文件的MIME类型 + put(".mp4", "video/mp4"); + }}; + // 这里定义了一个名为MEDIA_MAP的公共静态最终变量,它是一个HashMap类型的映射。 + // 通过匿名内部类的初始化方式,在创建HashMap实例的同时向其中添加了一些常见的文件后缀名到MIME类型的映射关系,比如将".pdf"后缀名映射到"application/pdf"这个MIME类型,将".mp4"后缀名映射到"video/mp4"这个MIME类型。 + // 由于被声明为静态最终变量,它在类加载时就会被初始化,并且其值不能再被修改,方便在整个类的其他地方直接使用这个映射关系来获取文件的MIME类型。 /** - * 获得文件类型 - * @param filePath - * @return + * 根据文件路径获取文件的MIME类型 + * 方法根据文件的后缀名,从MEDIA_MAP中获取对应的MIME类型。 + * + * @param filePath 文件路径 + * @return 文件的MIME类型 */ - public static String getContentType(String filePath){ - - if(!StringUtils.isBlank(filePath) - && filePath.indexOf(".")!=-1) { + // 这是对下面定义的getContentType方法的文档注释,说明该方法的功能是根据传入的文件路径,提取出文件的后缀名,然后从MEDIA_MAP这个静态映射中获取对应的MIME类型并返回。 - // 后缀转换成小写 + public static String getContentType(String filePath) { + if (!StringUtils.isBlank(filePath) && filePath.indexOf(".")!= -1) { + // 提取文件后缀名,并转换为小写 String suffix = filePath.substring(filePath.lastIndexOf(".")).toLowerCase(); + // 从映射中获取MIME类型 if (MEDIA_MAP.containsKey(suffix)) { return MEDIA_MAP.get(suffix); } } + // 如果没有找到对应的MIME类型,返回默认值 return "application/octet-stream"; } -} + // 这是定义的一个公共静态方法getContentType,它接受一个字符串类型的参数filePath,表示文件的路径。 + // 首先,通过StringUtils.isBlank方法判断文件路径是否不为空且包含小数点(即有文件后缀名)。 + // 如果满足条件,就使用substring方法从文件路径中提取出文件的后缀名,并通过toLowerCase方法将其转换为小写形式。 + // 然后,检查提取出的后缀名是否存在于MEDIA_MAP这个静态映射中,如果存在,就返回对应的MIME类型;如果不存在,就返回默认的MIME类型"application/octet-stream",这个默认值通常用于表示未知类型的二进制数据文件。 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java index 441a154..a85ec9a 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java +++ b/src-源文件/main/java/com/yf/exam/aspect/DictAspect.java @@ -1,156 +1,189 @@ package com.yf.exam.aspect; +// 导入FastJSON库,用于将Java对象转换为JSON字符串以及从JSON字符串解析为Java对象等操作, +// 在本类的多个方法中用于对象与JSON字符串之间的转换,以便于处理数据字典相关的值。 import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; + +// 导入MyBatis Plus的接口,用于处理分页相关的数据结构,在本类中用于判断和处理分页数据中的数据字典值。 import com.baomidou.mybatisplus.core.metadata.IPage; + +// 导入Jackson库的注解,用于指定日期格式的序列化和反序列化方式, +// 在本类的parseObject方法中用于根据注解设置日期字段的格式化输出。 import com.fasterxml.jackson.annotation.JsonFormat; + +// 导入自定义的注解,可能用于标记与数据字典相关的字段,以便在本类中识别并处理这些字段的数据字典值。 import com.yf.exam.core.annon.Dict; + +// 导入自定义的API响应类,用于封装API调用的返回结果,包括数据、状态码等信息, +// 在本类的多个方法中用于获取和设置返回结果中的数据部分,以便处理其中的数据字典值。 import com.yf.exam.core.api.ApiRest; + +// 导入自定义的反射工具类,可能用于获取对象的所有字段等反射相关操作, +// 在本类的parseObject方法中用于获取对象的所有字段以便遍历处理数据字典值。 import com.yf.exam.core.utils.Reflections; + +// 导入系统数据字典服务类,用于查询数据字典表以获取数据字典值的翻译文本, +// 在本类的translateDictValue方法中用于根据字典代码、文本、表名和键值查询对应的字典文本。 import com.yf.exam.modules.sys.system.service.SysDictService; -import lombok.extern.slf4j.Slf4j; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 +import lombok.extern.log4j.Log4j2; + +// 导入AspectJ的相关类,用于定义切面、切点和环绕通知等AOP相关的操作, +// 在本类中用于实现对特定方法的拦截和处理,以实现数据字典值的翻译等功能。 import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; + +// 导入Spring框架的注解,用于自动注入依赖对象和标记类为Spring组件, +// 在本类中通过@Autowired注入SysDictService对象,并通过@Component标记本类为Spring组件,使其可被Spring容器管理。 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; + +// 导入Spring框架的工具类,用于判断字符串是否为空等操作, +// 在本类的多个方法中用于判断字符串是否为空,以便进行相应的处理逻辑。 import org.springframework.util.StringUtils; +// 导入Java标准库中的反射相关类,用于通过反射操作对象的字段、获取类型信息等, +// 在本类的多个方法中广泛用于获取对象的字段、判断字段类型、获取字段注解等操作。 import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; + +// 导入Java标准库中的日期格式化类和日期类,用于处理日期格式的转换和操作, +// 在本类的parseObject方法中用于根据注解或默认格式对日期字段进行格式化输出。 import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; /** - * 数据字典AOP类,处理数据字典值 + * 数据字典AOP类,主要功能是处理数据字典值。通过拦截特定的方法调用, + * 对返回结果中的数据字典相关字段进行翻译、格式化等处理,以提供更友好的展示效果。 * * @author bool */ -@Aspect -@Component -@Slf4j +@Aspect // 标记该类为一个AspectJ切面类,用于定义切面相关的逻辑。 +@Component // 标记该类为Spring组件,使其能够被Spring容器管理和实例化,以便在应用中使用。 +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 public class DictAspect { @Autowired - private SysDictService sysDictService; + private SysDictService sysDictService; // 通过自动注入获取系统数据字典服务对象,用于查询数据字典值。 /** - * 切入Controller执行 - * @param pjp - * @return - * @throws Throwable + * 定义一个环绕通知,切入到指定的Controller方法执行前后。 + * 这里的切点表达式指定了拦截所有在com.yf.exam包及其子包下的所有Controller类中的所有公有方法。 + * + * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 + * @return 返回结果,经过处理后的方法执行结果,可能经过了数据字典值的处理等操作。 + * @throws Throwable 如果在环绕通知的执行过程中出现异常,则抛出。 */ @Around("execution(public * com.yf.exam..*.*Controller.*(..))") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { - return this.translate(pjp); + return this.translate(pjp); // 调用translate方法对被拦截方法的执行结果进行处理,主要是处理数据字典值。 } /** - * 进行翻译并返回,调用前必须实现:BaseDictService + * 对被拦截方法的执行结果进行翻译处理,并返回处理后的结果。 + * 在调用此方法之前,通常需要确保相关的BaseDictService(可能是数据字典相关的基础服务)已经实现。 * - * @param pjp - * @return - * @throws Throwable + * @param pjp 切入点对象,包含了被拦截方法的相关信息,如方法参数、目标对象等。 + * @return 返回结果,经过数据字典值处理后的方法执行结果。 + * @throws Throwable 如果在处理过程中出现异常,则抛出。 */ public Object translate(ProceedingJoinPoint pjp) throws Throwable { - // 处理字典 + // 调用被拦截方法获取原始结果,然后调用parseAllDictText方法对结果进行数据字典值的处理。 return this.parseAllDictText(pjp.proceed()); } /** - * 转换全部数据字典 + * 根据结果对象的类型,判断是否需要对其进行数据字典值的处理。 + * 如果结果对象是ApiRest类型,则调用parseFullDictText方法进行完整的数据字典值处理。 * - * @param result + * @param result 结果对象,即被拦截方法执行后的返回结果。 */ private Object parseAllDictText(Object result) { - - // 非ApiRest类型不处理 + // 判断结果对象是否是ApiRest类型,如果是则进行数据字典值的处理。 if (result instanceof ApiRest) { parseFullDictText(result); } - return result; } - /** - * 转换所有类型的数据字典、包含子列表 + * 对ApiRest类型的结果对象进行完整的数据字典值处理,包括处理分页数据、列表数据以及单对象数据等情况。 * - * @param result + * @param result 结果对象,即ApiRest类型的返回结果,其中包含了要处理的数据部分。 */ private void parseFullDictText(Object result) { - try { + Object rest = ((ApiRest) result).getData(); // 获取ApiRest对象中的数据部分,这部分数据可能包含数据字典相关字段。 - Object rest = ((ApiRest) result).getData(); - - // 不处理普通数据类型 + // 如果数据部分为空或者是基本数据类型,则不需要进行数据字典值的处理,直接返回。 if (rest == null || this.isBaseType(rest.getClass())) { return; } - // 分页的 + // 如果数据部分是分页数据类型(IPage),则对分页数据中的每条记录进行数据字典值处理。 if (rest instanceof IPage) { List items = new ArrayList<>(16); for (Object record : ((IPage) rest).getRecords()) { - Object item = this.parseObject(record); + Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 items.add(item); } - ((IPage) rest).setRecords(items); + ((IPage) rest).setRecords(items); // 将处理后的记录列表重新设置回分页对象中。 return; } - // 数据列表的 + // 如果数据部分是列表数据类型(List),则对列表中的每条记录进行数据字典值处理。 if (rest instanceof List) { List items = new ArrayList<>(); for (Object record : ((List) rest)) { - Object item = this.parseObject(record); + Object item = this.parseObject(record); // 调用parseObject方法对每条记录进行数据字典值处理。 items.add(item); } - // 重新回写值 + // 将处理后的记录列表重新设置回ApiRest对象的数据部分。 ((ApiRest) result).setData(items); return; } - // 处理单对象 + // 如果数据部分是单对象数据,则对该单对象进行数据字典值处理。 Object item = this.parseObject(((ApiRest) result).getData()); ((ApiRest) result).setData(item); } catch (Exception e) { - e.printStackTrace(); + e.printStackTrace(); // 如果在处理过程中出现异常,则打印异常堆栈信息。 } } /** - * 处理数据字典值 + * 对单个记录对象进行数据字典值处理,包括处理列表字段、带有数据字典注解的普通字段以及日期字段等情况。 * - * @param record - * @return + * @param record 记录对象,即要进行数据字典值处理的对象。 + * @return 处理后的对象,经过数据字典值处理后的记录对象。 */ public Object parseObject(Object record) { - if (record == null) { return null; } - // 不处理普通数据类型 + // 如果记录对象是基本数据类型,则不需要进行数据字典值处理,直接返回原对象。 if (this.isBaseType(record.getClass())) { return record; } - // 转换JSON字符 + // 将记录对象转换为JSON字符串,再解析为JSONObject对象,以便于通过字段名获取和设置值。 String json = JSON.toJSONString(record); JSONObject item = JSONObject.parseObject(json); - for (Field field : Reflections.getAllFields(record)) { + for (Field field : Reflections.getAllFields(record)) { // 遍历记录对象的所有字段。 - // 如果是List类型 + // 如果字段类型是List类型,则对列表字段进行特殊处理。 if (List.class.isAssignableFrom(field.getType())) { try { - List list = this.processList(field, item.getObject(field.getName(), List.class)); + List list = this.processList(field, item.getObject(field.getName(), List.class)); // 调用processList方法处理列表字段。 item.put(field.getName(), list); continue; } catch (Exception e) { @@ -159,14 +192,14 @@ public class DictAspect { continue; } - // 处理普通字段 - if (field.getAnnotation(Dict.class) != null) { + // 如果字段带有数据字典注解(Dict),则对该字段进行数据字典值的翻译处理。 + if (field.getAnnotation(Dict.class)!= null) { String code = field.getAnnotation(Dict.class).dicCode(); String text = field.getAnnotation(Dict.class).dicText(); String table = field.getAnnotation(Dict.class).dictTable(); String key = String.valueOf(item.get(field.getName())); - //翻译字典值对应的txt + // 调用translateDictValue方法翻译字典值对应的文本,根据字典代码、文本、表名和键值查询对应的字典文本。 String textValue = this.translateDictValue(code, text, table, key); if (StringUtils.isEmpty(textValue)) { textValue = ""; @@ -175,24 +208,22 @@ public class DictAspect { continue; } - //日期格式转换 - if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName()) != null) { - - // 获取注解 + // 如果字段类型是日期类型(java.util.Date)且字段值不为空,则对日期字段进行格式转换处理。 + if ("java.util.Date".equals(field.getType().getName()) && item.get(field.getName())!= null) { + // 获取字段上的JsonFormat注解。 JsonFormat ann = field.getAnnotation(JsonFormat.class); - // 格式化方式 + // 定义日期格式化对象。 SimpleDateFormat fmt; - // 使用注解指定的 - if (ann != null && !StringUtils.isEmpty(ann.pattern())) { + // 如果注解不为空且指定了日期格式模式,则使用注解指定的格式创建日期格式化对象。 + if (ann!= null &&!StringUtils.isEmpty(ann.pattern())) { fmt = new SimpleDateFormat(ann.pattern()); } else { - // 默认时间样式 + // 如果注解为空或未指定格式,则使用默认的日期格式创建日期格式化对象。 fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } item.put(field.getName(), fmt.format(new Date((Long) item.get(field.getName())))); continue; - } } @@ -200,49 +231,53 @@ public class DictAspect { } /** - * 获得类型为List的值 + * 处理类型为List的字段,对列表中的每个元素进行数据字典值处理等操作。 * - * @param field - * @return + * @param field 字段对象,即要处理的List类型字段。 + , + * @param list 列表对象,即字段对应的列表值。 + * @return 处理后的列表,经过数据字典值处理后的列表对象。 */ private List processList(Field field, List list) { - - // 空判断 + // 如果列表为空,则返回一个空的ArrayList对象。 if (list == null || list.size() == 0) { return new ArrayList<>(); } - // 获得List属性的真实类 + // 获取List属性的真实类型,通过反射获取字段的泛型类型,再尝试获取其实际的类型参数。 Type genericType = field.getGenericType(); Class actualType = null; if (genericType instanceof ParameterizedType) { - // 尝试获取数据类型 ParameterizedType pt = (ParameterizedType) genericType; try { actualType = (Class) pt.getActualTypeArguments()[0]; - }catch (Exception e){ + } catch (Exception e) { return list; } } - // 常规列表无需处理 + // 如果列表元素的类型是基本数据类型,则不需要进行数据字典值处理,直接返回原列表。 if (isBaseType(actualType)) { return list; } - // 返回列表 + // 创建一个新的ArrayList对象,用于存储处理后的列表元素。 List result = new ArrayList<>(16); for (int i = 0; i < list.size(); i++) { - // 创建实例-->赋值-->字典处理 + // 获取列表中的每个元素。 Object data = list.get(i); try { + // 将列表元素转换为JSON字符串,再解析为其真实类型的对象,以便进行数据字典值处理。 data = JSON.parseObject(JSON.toJSONString(data), actualType); - }catch (Exception e){ - // 转换出错不处理 + } catch (Exception e) { + // 如果转换过程中出现错误,则不进行处理,直接使用原元素。 + // 这里可以根据实际需求进一步处理错误情况,比如记录日志等。 + // 目前只是简单地忽略错误,继续处理下一个元素。 + ; } - // 处理后的数据 + // 对处理后的元素进行数据字典值处理,调用parseObject方法。 Object pds = this.parseObject(data); result.add(pds); } @@ -251,23 +286,25 @@ public class DictAspect { } /** - * 翻译实现 + , + * 根据字典代码、文本、表名和键值翻译数据字典值对应的文本。 * - * @param code - * @param text - * @param table - * @param key - * @return + * @param code 字典代码,用于在数据字典表中定位特定的字典项。 + * @param text 字典文本,可能是与字典代码相关的描述信息等。 + * @param table 字典表名,指定要查询的数据字典表。 + * @param key 字典键值,用于在字典表中查找对应的字典项。 + * @return 翻译后的值,即根据字典代码、文本、表名和键值查询到的字典文本值,如果未找到则返回空字符串。 */ - private String translateDictValue(String code, String text, String table, String key) { + private String translateDictValue(String code, String text, String table, String键值) { if (StringUtils.isEmpty(key)) { return null; } try { - // 翻译值 + // 定义变量用于存储翻译后的字典文本值。 String dictText = null; if (!StringUtils.isEmpty(table)) { - dictText = sysDictService.findDict(table, text, code, key.trim()); + // 如果字典表名不为空,则调用sysDictService的findDict方法查询数据字典表,获取对应的字典文本值。 + dictText = sysDictService.findDict(table, text, code, key.trim()); } if (!StringUtils.isEmpty(dictText)) { @@ -280,15 +317,13 @@ public class DictAspect { } /** - * 判断是否基本类型 + * 判断给定的类是否是基本数据类型,包括常见的整数、字节、长整数、双精度浮点数、单精度浮点数、字符、短整数、布尔值以及字符串和数字类型等。 * - * @param clazz - * @return + * @param clazz 要判断的类对象。 + * @return 是否基本类型,如果是基本数据类型则返回true,否则返回false。 */ private boolean isBaseType(Class clazz) { - - - // 基础数据类型 + // 判断是否是常见的基本数据类型,如整数、字节、长整数等。 if (clazz.equals(java.lang.Integer.class) || clazz.equals(java.lang.Byte.class) || clazz.equals(java.lang.Long.class) || @@ -300,18 +335,16 @@ public class DictAspect { return true; } - // String类型 + // 判断是否是字符串类型。 if (clazz.equals(java.lang.String.class)) { return true; } - // 数字 + // 判断是否是数字类型(这里的数字类型可能是指抽象的数字类型,比如Number的子类等)。 if (clazz.equals(java.lang.Number.class)) { return true; } return false; } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java index 6b958ca..2ca40a4 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/QueryInterceptor.java @@ -1,144 +1,255 @@ package com.yf.exam.aspect.mybatis; +// 导入MyBatis Plus的分页拦截器类,用于实现分页功能, +// 本类继承自该类以在拦截查询操作时能正确处理分页相关逻辑。 import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor; + +// 导入系统用户登录信息的数据传输对象(DTO)类,用于获取当前登录用户的相关信息, +// 比如在处理查询拦截时可能需要根据登录用户的信息来过滤或修改查询语句。 import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入JSqlParser库中的解析器管理器类,用于解析SQL语句, +// 在本类中用于解析查询语句以便进行后续的处理,如替换用户ID等操作。 import net.sf.jsqlparser.parser.CCJSqlParserManager; + +// 导入JSqlParser库中表示简单查询语句的类,它是查询语句的一种具体表示形式, +// 在解析查询语句后可以获取到该对象来进一步处理查询语句的内容。 import net.sf.jsqlparser.statement.select.PlainSelect; + +// 导入JSqlParser库中表示查询语句的通用类,用于接收解析后的查询语句对象, +// 以便进行后续的类型转换和处理操作。 import net.sf.jsqlparser.statement.select.Select; + +// 导入Apache Commons Lang3库中的StringUtils类,用于处理字符串相关的操作, +// 如判断字符串是否为空、非空等情况,在本类中用于判断用户ID等字符串是否有效。 import org.apache.commons.lang3.StringUtils; + +// 导入MyBatis中的语句处理器接口类,它是MyBatis在执行SQL语句时涉及的一个重要组件, +// 在本类中作为拦截的目标对象类型,以便在其执行查询准备阶段进行拦截操作。 import org.apache.ibatis.executor.statement.StatementHandler; + +// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, +// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等。 import org.apache.ibatis.mapping.MappedStatement; + +// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, +// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是否为查询语句。 import org.apache.ibatis.mapping.SqlCommandType; + +// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, +// 本类实现了该接口以作为一个MyBatis的拦截器来拦截查询语句的执行过程。 import org.apache.ibatis.plugin.Interceptor; + +// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, +// 本类通过该注解指定了要拦截StatementHandler的prepare方法。 import org.apache.ibatis.plugin.Intercepts; + +// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, +// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; + +// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, +// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; + +// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, +// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; + +// 导入MyBatis的默认反射工厂类,用于创建反射对象来访问和修改MyBatis相关对象的属性, +// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.DefaultReflectorFactory; + +// 导入MyBatis的元对象类,它提供了一种通过反射来访问和操作MyBatis相关对象属性的机制, +// 在本类中用于获取和设置StatementHandler等对象的内部属性,如SQL语句等。 import org.apache.ibatis.reflection.MetaObject; + +// 导入MyBatis的系统元对象类,它是MetaObject的一种特殊实现,提供了一些默认的对象工厂和包装器工厂, +// 在本类中用于创建MetaObject对象来操作StatementHandler等对象的属性。 import org.apache.ibatis.reflection.SystemMetaObject; + +// 导入Apache Shiro的安全工具类,用于获取当前安全上下文的相关信息, +// 在本类中用于获取当前登录用户的信息,以便根据用户信息来处理查询语句。 import org.apache.shiro.SecurityUtils; +// 导入Java标准库中的字符串读取器类,用于将字符串转换为可读取的流形式, +// 在本类中用于将SQL语句字符串提供给CCJSqlParserManager进行解析。 import java.io.StringReader; + +// 导入Java标准库中的数据库连接接口类,它是Java数据库操作中与数据库建立连接的关键接口, +// 在本类中作为StatementHandler的prepare方法的参数类型之一出现,虽然在本类代码中未直接对其进行复杂操作, +// 但它是MyBatis执行SQL语句过程中涉及到的重要组件之一。 import java.sql.Connection; + +// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, +// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, +// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 查询拦截器,用于拦截处理通用的信息、如用户ID、多租户信息等; - * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确,分页计数大于实际数量等问题 + * 查询拦截器类,用于拦截处理通用的信息,如用户ID、多租户信息等。 + * 特别注意:此处继承了PaginationInterceptor分页,分页必须在拦截数据后执行,否则容易出现分页不准确, + * 分页计数大于实际数量等问题。 * @author bool */ @Log4j2 -@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class}),}) +// 使用@Intercepts注解指定该类作为MyBatis的拦截器要拦截的目标和方法。 +// 这里拦截的是StatementHandler类的prepare方法,并且该方法的参数类型为Connection和Integer。 +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) public class QueryInterceptor extends PaginationInterceptor implements Interceptor { /** - * 客户ID + * 客户ID的占位符字符串,在原始SQL语句中如果出现该占位符,将会被替换为实际的用户ID。 */ private static final String USER_FILTER = "{{userId}}"; - - + /** + * 拦截器的核心方法,用于在目标方法(StatementHandler的prepare方法)被调用时进行拦截处理。 + * + * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 + * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 + * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 + */ @Override public Object intercept(Invocation invocation) throws Throwable { + // 从invocation对象中获取被拦截的目标对象,即StatementHandler对象。 StatementHandler statementHandler = (StatementHandler) invocation.getTarget(); + + // 使用MetaObject.forObject方法创建一个元对象,用于通过反射访问和修改StatementHandler对象的属性。 + // 这里传入了默认的对象工厂、包装器工厂和反射工厂,以便能够正确地操作StatementHandler对象的内部属性。 MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory()); + + // 从元对象中获取MappedStatement对象,该对象包含了关于SQL语句的映射信息,如SQL语句的ID、参数映射、结果映射等。 MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement"); - //sql语句类型 + // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 + // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - // 只过滤查询的 + // 只对查询类型的SQL语句进行处理,如果当前SQL语句类型是SELECT,则进入下面的处理逻辑。 if (SqlCommandType.SELECT == sqlCommandType) { - // 获得原始SQL + + // 获取原始的SQL语句,通过StatementHandler的getBoundSql方法获取绑定的SQL语句对象,再获取其SQL字符串。 String sql = statementHandler.getBoundSql().getSql(); - // 不处理 - if(!sql.contains(USER_FILTER)){ + // 如果原始SQL语句中不包含用户ID占位符(USER_FILTER),则直接调用父类(PaginationInterceptor)的intercept方法, + // 即按照原有的分页逻辑进行处理,不进行用户ID相关的替换等操作。 + if (!sql.contains(USER_FILTER)) { return super.intercept(invocation); } - // 处理SQL语句 + + // 如果原始SQL语句中包含用户ID占位符,则需要对SQL语句进行处理。 + // 首先调用parseSql方法对SQL语句进行解析和处理,包括替换用户ID等操作。 String outSql = this.parseSql(sql); - // 设置SQL + + // 将处理后的SQL语句设置回StatementHandler对象的内部属性中,通过元对象的setValue方法设置boundSql.sql属性的值。 metaObject.setValue("delegate.boundSql.sql", outSql); - // 再分页 + + // 再次调用父类(PaginationInterceptor)的intercept方法,此时是在处理完用户ID等信息后, + // 按照正确的分页逻辑进行处理,以确保分页功能在拦截数据并处理相关信息后正确执行。 return super.intercept(invocation); } + // 如果当前SQL语句不是查询类型(SELECT),则直接执行被拦截方法的原有逻辑,不进行额外的处理。 return invocation.proceed(); } + /** + * 将拦截器包装成MyBatis可识别的插件形式的方法。 + * + * @param target 要包装的目标对象,通常是被拦截的对象,如StatementHandler等。 + * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 + */ @Override public Object plugin(Object target) { return Plugin.wrap(target, this); } + /** + * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, + * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 + * + * @param properties 包含了外部配置的属性信息的Properties对象。 + */ @Override public void setProperties(Properties properties) { } - - /** - * 获取当前登录用户 - * @return + * 获取当前登录用户的方法,通过Apache Shiro的SecurityUtils工具类来获取当前安全上下文的主体对象, + * 并获取其主体信息(即登录用户的信息),如果获取成功则转换为SysUserLoginDTO类型返回,否则返回null。 + * + * @return 返回当前登录用户的SysUserLoginDTO对象,如果获取失败则返回null。 */ private SysUserLoginDTO getLoginUser() { try { - return SecurityUtils.getSubject().getPrincipal() != null ? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; + return SecurityUtils.getSubject().getPrincipal()!= null? (SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal() : null; } catch (Exception e) { return null; } } /** - * 替换用户ID - * @param sql - * @return + * 替换用户ID的方法,根据当前登录用户的ID,将原始SQL语句中的用户ID占位符(USER_FILTER)替换为实际的用户ID。 + * + * @param sql 原始的SQL语句。 + * @return 返回替换用户ID后的SQL语句,如果用户ID为空,则返回null。 */ private String processUserId(String sql) { - // 当前用户 + // 获取当前登录用户的信息,通过调用getLoginUser方法获取。 SysUserLoginDTO user = this.getLoginUser(); String userId = user.getId(); - if(StringUtils.isNotBlank(userId)){ + + // 如果获取到的用户ID不为空,则将原始SQL语句中的用户ID占位符替换为实际的用户ID,并返回替换后的SQL语句。 + if (StringUtils.isNotBlank(userId)) { return sql.replace(USER_FILTER, userId); } + + // 如果用户ID为空,则返回null。 return null; } /** - * 处理注入用户信息 - * @param src - * @return + * 处理注入用户信息的方法,主要用于解析原始SQL语句,替换用户ID等操作,以实现根据用户信息来调整查询语句的目的。 + * + * @param src 原始的SQL语句。 + * @return 返回处理后的SQL语句,如果在处理过程中出现异常,则返回原始的SQL语句。 */ private String parseSql(String src) { + // 创建一个CCJSqlParserManager对象,用于解析SQL语句。 CCJSqlParserManager parserManager = new CCJSqlParserManager(); try { + // 使用CCJSqlParserManager对象的parse方法解析原始SQL语句,将其转换为Select类型的对象。 + // 这里需要将原始SQL语句通过StringReader转换为可读取的流形式提供给parse方法进行解析。 Select select = (Select) parserManager.parse(new StringReader(src)); + + // 从Select对象中获取其查询主体部分,即PlainSelect对象,它包含了查询语句的具体内容,如查询条件、字段等。 PlainSelect selectBody = (PlainSelect) select.getSelectBody(); - // 过滤客户 + // 将PlainSelect对象转换为字符串形式,得到初步处理后的SQL语句。 + // 这里主要是为了后续方便进行用户ID等信息的替换操作。 String sql = selectBody.toString(); - // 过滤用户ID + // 调用processUserId方法对初步处理后的SQL语句进行用户ID的替换操作,将用户ID占位符替换为实际的用户ID。 sql = this.processUserId(sql); - // 获得SQL + // 返回处理后的SQL语句。 return sql; } catch (Exception e) { e.printStackTrace(); } + // 如果在处理过程中出现异常,则返回原始的SQL语句。 return src; } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java index 8baae8f..c85e5f0 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java +++ b/src-源文件/main/java/com/yf/exam/aspect/mybatis/UpdateInterceptor.java @@ -1,80 +1,188 @@ +// 定义包路径,用于存放更新拦截器相关的类。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.mybatis部分, +// 通常用于组织和管理与MyBatis相关的切面逻辑代码。 package com.yf.exam.aspect.mybatis; +// 导入MyBatis-Plus的抽象SQL解析处理器类,它提供了一些基础的SQL解析处理功能, +// 本类继承自该类以便在处理更新操作时利用其相关功能或遵循其处理规范。 import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler; + +// 导入Apache Commons Lang3库中的数组工具类,用于对数组进行各种操作, +// 如合并数组等,在本类中用于合并对象的字段数组(当存在父类字段时)。 import org.apache.commons.lang3.ArrayUtils; + +// 导入MyBatis中的执行器接口类,它是MyBatis执行SQL语句的核心组件,负责实际执行数据库操作, +// 在本类中作为拦截的目标对象类型,通过拦截其update方法来实现自动设置创建时间和更新时间的功能。 import org.apache.ibatis.executor.Executor; + +// 导入MyBatis中的映射语句类,它包含了关于SQL语句的映射信息, +// 如SQL语句的ID、参数映射、结果映射等,在本类中用于获取SQL语句的相关属性,如语句类型等, +// 以便根据不同的操作类型(插入、更新等)来处理创建时间和更新时间的赋值。 import org.apache.ibatis.mapping.MappedStatement; + +// 导入MyBatis中的SQL命令类型枚举类,用于表示不同类型的SQL命令, +// 如SELECT、INSERT、UPDATE、DELETE等,在本类中用于判断当前拦截的SQL语句是何种类型的操作, +// 从而确定是否需要对创建时间和更新时间进行赋值。 import org.apache.ibatis.mapping.SqlCommandType; + +// 导入MyBatis的拦截器接口类,定义了拦截器的基本行为和方法, +// 本类实现了该接口以作为一个MyBatis的拦截器来拦截更新语句的执行过程,实现自动设置时间的功能。 import org.apache.ibatis.plugin.Interceptor; + +// 导入MyBatis的拦截器注解类,用于标注一个类是MyBatis的拦截器并指定拦截的目标和方法, +// 本类通过该注解指定了要拦截Executor类的update方法。 import org.apache.ibatis.plugin.Intercepts; + +// 导入MyBatis的拦截器调用类,用于在拦截器方法中传递被拦截方法的调用信息, +// 包括被拦截的目标对象、方法参数等,在本类的intercept方法中会接收到该对象来处理拦截逻辑。 import org.apache.ibatis.plugin.Invocation; + +// 导入MyBatis的插件包装类,用于将拦截器包装成MyBatis可识别的插件形式, +// 在本类的plugin方法中会使用该类来包装目标对象以便实现拦截功能。 import org.apache.ibatis.plugin.Plugin; + +// 导入MyBatis的拦截器签名类,用于定义拦截器拦截的具体目标、方法和参数类型, +// 在本类的@Intercepts注解中会使用该类来指定具体的拦截信息。 import org.apache.ibatis.plugin.Signature; +// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, +// 在本类中用于获取和设置对象的创建时间和更新时间字段的值。 import java.lang.reflect.Field; + +// 导入Java标准库中的时间戳类,用于表示某个特定时刻的时间点, +// 在本类中用于设置创建时间和更新时间为当前的时间戳,以记录操作发生的准确时间。 import java.sql.Timestamp; + +// 导入Java标准库中的对象工具类,提供了一些用于比较和操作对象的方法, +// 在本类中用于比较字段名与预定义的创建时间、更新时间字段名是否相等。 import java.util.Objects; + +// 导入Java标准库中的属性类,用于存储和管理键值对形式的属性信息, +// 在本类中作为Interceptor接口的setProperties方法的参数类型,虽然在本类代码中该方法暂未实现具体功能, +// 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 import java.util.Properties; /** - * 自动给创建时间个更新时间加值 + * 该类是一个更新拦截器,主要功能是自动给创建时间和更新时间字段赋值。 + * 它会拦截MyBatis执行器(Executor)的update方法,根据操作类型(插入或更新)以及对象的字段情况, + * 为创建时间和更新时间字段设置当前的时间戳值。 * @author bool */ @Intercepts(value = {@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})}) +// 使用@Intercepts注解并通过@Signature指定该类作为MyBatis的拦截器要拦截的目标和方法。 +// 这里拦截的是Executor类的update方法,并且该方法的参数类型为MappedStatement和Object。 public class UpdateInterceptor extends AbstractSqlParserHandler implements Interceptor { /** - * 创建时间 + * 定义创建时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的创建时间字段。 */ private static final String CREATE_TIME = "createTime"; + /** - * 更新时间 + * 定义更新时间字段的名称常量,用于在后续代码中方便地识别和操作对象中的更新时间字段。 */ private static final String UPDATE_TIME = "updateTime"; + /** + * 拦截器的核心方法,用于在目标方法(Executor的update方法)被调用时进行拦截处理。 + * + * @param invocation 包含了被拦截方法的调用信息,如目标对象、方法参数等。 + * @return 返回处理后的结果,可能是继续执行被拦截方法后的结果,也可能是经过拦截器修改后的结果。 + * @throws Throwable 如果在拦截处理过程中出现异常,则抛出。 + */ @Override public Object intercept(Invocation invocation) throws Throwable { + // 从invocation对象的参数数组中获取第一个参数,即MappedStatement对象, + // 它包含了关于SQL语句的映射信息,用于后续获取SQL命令类型等操作。 MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; - // SQL操作命令 + + // 获取当前SQL语句的类型,通过MappedStatement对象的getSqlCommandType方法获取。 + // 该类型是一个枚举值,如SELECT、INSERT、UPDATE、DELETE等,用于判断当前拦截的SQL语句是何种类型的操作。 SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); - // 获取新增或修改的对象参数 + + // 从invocation对象的参数数组中获取第二个参数,即要进行新增或修改操作的对象参数, + // 后续会通过反射操作该对象来设置创建时间和更新时间字段的值。 Object parameter = invocation.getArgs()[1]; - // 获取对象中所有的私有成员变量(对应表字段) + + // 获取对象中所有的私有成员变量(对应表字段),通过反射获取parameter对象的声明字段数组。 Field[] declaredFields = parameter.getClass().getDeclaredFields(); - if (parameter.getClass().getSuperclass() != null) { + + // 判断parameter对象的父类是否存在,如果存在则获取父类的声明字段数组, + // 并将其与之前获取的子类声明字段数组进行合并,以获取完整的包含父类和子类字段的数组。 + if (parameter.getClass().getSuperclass()!= null) { Field[] superField = parameter.getClass().getSuperclass().getDeclaredFields(); declaredFields = ArrayUtils.addAll(declaredFields, superField); } + // 用于临时存储当前遍历到的字段名,以便后续与预定义的创建时间、更新时间字段名进行比较。 String fieldName = null; + + // 遍历获取到的所有字段数组(包含父类和子类字段),对每个字段进行处理。 for (Field field : declaredFields) { fieldName = field.getName(); + + // 如果当前遍历到的字段名与预定义的创建时间字段名相等,说明找到了创建时间字段。 if (Objects.equals(CREATE_TIME, fieldName)) { + + // 如果当前SQL语句的操作类型是插入操作(INSERT),则需要为创建时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType)) { + + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); + + // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, + // 再创建一个Timestamp对象来表示该时间点,从而为创建时间字段赋值。 field.set(parameter, new Timestamp(System.currentTimeMillis())); } } + + // 如果当前遍历到的字段名与预定义的更新时间字段名相等,说明找到了更新时间字段。 if (Objects.equals(UPDATE_TIME, fieldName)) { + + // 如果当前SQL语句的操作类型是插入操作(INSERT)或者更新操作(UPDATE), + // 则需要为更新时间字段设置当前时间。 if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) { + + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); - field.set(parameter, new Timestamp(System.currentTimeMillis())); + // 使用反射设置该字段的值为当前的时间戳,通过System.currentTimeMillis()获取当前时间的毫秒数, + // 再创建一个Timestamp对象来表示该时间点,从而为更新时间字段赋值。 + field.set(parameter, new Timestamp(System.currentTimeMillis())); } } } + + // 继续执行被拦截的Executor的update方法的原有逻辑,经过上述处理后, + // 已经为创建时间和更新时间字段设置了合适的值(如果符合条件的话),现在继续执行原始的更新操作。 return invocation.proceed(); } + /** + * 将拦截器包装成MyBatis可识别的插件形式的方法。 + * + * @param target 要包装的目标对象,通常是被拦截的对象,如Executor等。 + * @return 返回包装后的对象,以便MyBatis能够正确识别并应用拦截器的功能。 + */ @Override public Object plugin(Object target) { + // 如果目标对象是Executor类型,说明是我们要拦截的对象, + // 则使用Plugin.wrap方法将拦截器(this)包装到目标对象上,以便实现拦截功能。 if (target instanceof Executor) { return Plugin.wrap(target, this); } + + // 如果目标对象不是Executor类型,说明不是我们要拦截的对象,直接返回该目标对象即可。 return target; } + /** + * 设置拦截器属性的方法,目前该方法在本类中暂未实现具体功能, + * 但它是符合Interceptor接口规范的一部分,可用于接收外部配置的属性信息来动态调整拦截器的行为。 + * + * @param properties 包含了外部配置的属性信息的Properties对象。 + */ @Override public void setProperties(Properties properties) { + // 这里暂时没有具体的设置属性操作,可根据后续需求添加相关逻辑来处理接收到的属性信息。 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java index 4b47fee..77ed253 100644 --- a/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java +++ b/src-源文件/main/java/com/yf/exam/aspect/utils/InjectUtils.java @@ -1,99 +1,128 @@ +// 定义包路径,用于存放注入工具类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的aspect.utils部分, +// 通常用于组织和管理与注入操作相关的工具类代码。 package com.yf.exam.aspect.utils; +// 导入FastJSON库,它是一个用于将Java对象与JSON字符串进行相互转换的高性能库, +// 在本类的restError方法中用于将API响应对象转换为JSON字符串以便写入HTTP响应中。 import com.alibaba.fastjson.JSON; + +// 导入API错误类,它可能定义了一系列表示不同类型API错误的常量或属性, +// 在本类的restError方法中用于创建包含特定错误信息的API响应对象。 import com.yf.exam.core.api.ApiError; + +// 导入API响应类,它用于封装API调用的返回结果,包括成功的结果以及可能出现的错误信息等, +// 在本类的restError方法中用于创建要返回给客户端的错误响应对象。 import com.yf.exam.core.api.ApiRest; + +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入Spring框架的组件注解,用于标记该类是一个Spring组件,这样Spring容器可以对其进行管理和实例化, +// 使其能够在Spring应用程序中被其他组件所使用。 import org.springframework.stereotype.Component; +// 导入Java标准库中的HTTP响应类,用于处理HTTP协议相关的响应操作, +// 在本类的restError方法中用于设置响应的编码、内容类型以及写入响应内容等操作。 import javax.servlet.http.HttpServletResponse; + +// 导入Java标准库中的IO异常类,用于处理输入输出操作过程中可能出现的异常情况, +// 在本类的restError方法以及其他可能涉及到IO操作的地方用于捕获和处理相关异常。 import java.io.IOException; + +// 导入Java标准库中的反射字段类,用于通过反射操作对象的私有字段, +// 在本类的setValue和getFiled方法中用于获取和设置对象的指定字段的值。 import java.lang.reflect.Field; /** - * 注入工具类 + * 注入工具类,提供了一些用于对象字段赋值以及处理错误响应返回等功能的方法。 * @author bool * @date 2019-07-17 09:32 */ -@Log4j2 -@Component +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 +@Component // 将该类标记为Spring组件,使其能够被Spring容器管理和使用。 public class InjectUtils { - - /** - * 给对象字段赋值 + * 给指定对象的指定字段赋值的方法。 * - * @param object 赋值的对象 - * @param value 值 - * @param fields 字段 - * @throws Exception 异常 + * @param object 要进行赋值操作的对象。 + * @param value 要赋给指定字段的值。 + * @param fields 一个可变参数,用于指定要赋值的字段名数组。 + * @throws Exception 如果在获取字段或设置字段值的过程中出现异常,则抛出。 */ public void setValue(Object object, Object value, String... fields) throws Exception { - - //设置同类的属性 + // 遍历要赋值的字段名数组 for (String fieldName : fields) { - - //获取当前 + // 根据对象的类和字段名获取对应的字段对象 Field field = this.getFiled(object.getClass(), fieldName); - if(field == null){ + + // 如果获取到的字段对象为空,说明未找到对应的字段,继续下一个字段的处理。 + if (field == null) { continue; } + // 通过反射设置该字段可访问,因为私有字段默认是不可直接访问的。 field.setAccessible(true); + + // 使用反射设置该字段的值为传入的值,即将指定的值赋给对象的指定字段。 field.set(object, value); } - } /** - * 获取字段名对应的字段 + * 根据目标类和字段名获取对应的字段对象的方法。 * - * @param clazz 目标类 - * @param fieldName 字段名 + * @param clazz 目标类,即要在其中查找字段的类。 + * @param fieldName 要查找的字段名。 + * @return 返回找到的字段对象,如果未找到则返回null。 */ private Field getFiled(Class clazz, String fieldName) { + System.out.println("注入的类:" + clazz.toString()); // 打印当前正在查找字段的目标类的信息,方便调试查看。 - System.out.println("注入的类:"+clazz.toString()); - - //是否具有包含关系 + // 尝试获取当前类中指定字段名的字段对象 try { - //获取当前类的属性 return clazz.getDeclaredField(fieldName); - }catch (Exception e){ + } catch (Exception e) { + log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); // 如果获取字段失败,记录错误日志, + // 提示在当前类中不存在指定字段, + // 并准备尝试在父类中查找。 - log.error(clazz.toString() + ": not exist field, try superclass " + fieldName); - - //如果为空且存在父类,则往上找 - if(clazz.getSuperclass()!=null){ + // 如果当前类未找到指定字段且存在父类,则递归调用本方法在父类中继续查找指定字段。 + if (clazz.getSuperclass()!= null) { return this.getFiled(clazz.getSuperclass(), fieldName); } + // 如果在当前类及其所有父类中都未找到指定字段,则返回null。 return null; } } - /** - * 打印结果返回 - * @param response - * @throws IOException + * 用于处理错误情况并将错误结果返回给客户端的方法,通过设置HTTP响应的相关属性和写入错误响应内容来实现。 + * + * @param response HTTP响应对象,用于向客户端发送响应信息。 + * @throws IOException 如果在设置响应属性或写入响应内容过程中出现IO异常,则抛出。 */ public static void restError(HttpServletResponse response) { - try { - - //固定错误 + // 创建一个包含特定API错误信息的API响应对象,这里使用了ApiError.ERROR_10010002作为错误码, + // 具体含义可能在ApiError类中定义,通常表示某种常见的错误情况。 ApiRest apiRest = new ApiRest(ApiError.ERROR_10010002); + + // 设置HTTP响应的字符编码为UTF-8,确保能够正确处理和传输各种字符,特别是中文等非ASCII字符。 response.setCharacterEncoding("UTF-8"); + + // 设置HTTP响应的内容类型为application/json,表明返回给客户端的内容是JSON格式的数据。 response.setContentType("application/json"); - response.getWriter().write(JSON.toJSONString(apiRest)); - response.getWriter().close(); - }catch (IOException e){ + // 将创建的API响应对象转换为JSON字符串,并写入到HTTP响应的输出流中,以便客户端能够接收到错误信息。 + response.getWriter().write(JSON.toJSONString(apiRest)); + // 关闭HTTP响应的写入流,释放相关资源。 + response.getWriter().close(); + } catch (IOException e) { + // 如果在设置响应属性或写入响应内容过程中出现IO异常,这里只是简单地捕获异常, + // 可以根据实际需求进一步处理异常,比如记录更详细的日志信息等。 } - } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java index e88cb08..83b86ab 100644 --- a/src-源文件/main/java/com/yf/exam/config/CorsConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/CorsConfig.java @@ -1,35 +1,81 @@ package com.yf.exam.config; +// 导入Spring Boot中用于注册Servlet过滤器的类,通过它可以将自定义的过滤器注册到Servlet容器中, +// 并配置相关属性,如过滤器的执行顺序等。在本类中用于注册跨域过滤器(CorsFilter)。 import org.springframework.boot.web.servlet.FilterRegistrationBean; + +// 导入Spring框架中用于标记一个类是配置类的注解,被该注解标记的类可以在其中定义各种Bean配置方法, +// 这些方法会被Spring容器在启动时自动识别并执行,用于创建和配置应用程序所需的各种组件。 import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于指定顺序的接口,实现该接口可以定义对象的顺序, +// 在本类中用于指定跨域过滤器(CorsFilter)在过滤器链中的执行顺序,使其具有最高优先级。 import org.springframework.core.Ordered; + +// 导入Spring框架中用于配置跨域资源共享(Cors)的类,通过它可以设置允许的源、请求头、请求方法等跨域相关的配置项。 import org.springframework.web.cors.CorsConfiguration; + +// 导入Spring框架中基于URL的跨域配置源类,它允许根据不同的URL模式来配置不同的跨域设置, +// 在本类中用于创建一个基于URL的跨域配置源,并将统一的跨域配置应用到所有的URL路径("**")上。 import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; +// 导入Spring框架中实现跨域过滤功能的类,它会根据配置的跨域规则对请求进行过滤和处理, +// 以实现允许跨域访问的功能。在本类中创建该过滤器并将其注册到Servlet容器中。 +import org.springframework.web.filter.CorsFilter; /** - * 网关全局设置,允许跨域 + * 网关全局设置类,主要功能是配置允许跨域访问的相关设置。 + * 通过创建和注册跨域过滤器(CorsFilter),并设置允许的源、请求头、请求方法等配置项, + * 使得应用程序能够处理来自不同域的请求,避免跨域访问限制。 + * * @author bool * @date 2019-08-13 17:28 */ - -@Configuration +@Configuration // 标记该类为Spring框架的配置类,表明其中可以定义各种Bean的创建和配置方法。 public class CorsConfig { + /** + * 定义一个Bean方法,用于创建并返回一个FilterRegistrationBean对象,该对象用于注册跨域过滤器(CorsFilter)。 + * + * @return 返回一个FilterRegistrationBean对象,其中包含了配置好的跨域过滤器以及相关的执行顺序等设置。 + */ @Bean public FilterRegistrationBean corsFilter() { + // 创建一个基于URL的跨域配置源对象,它将作为跨域配置的基础,用于后续设置跨域规则并应用到特定的URL路径上。 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + + // 创建一个CorsConfiguration对象,用于设置具体的跨域配置项,如允许的源、请求头、请求方法等。 CorsConfiguration config = new CorsConfiguration(); + + // 设置是否允许携带凭证(如Cookie等)进行跨域请求,这里设置为true,表示允许携带凭证。 config.setAllowCredentials(true); + + // 添加允许的源,这里使用CorsConfiguration.ALL表示允许所有的源进行跨域访问。 + // 可以根据实际需求设置具体的源地址,如"http://example.com"等,多个源地址可以多次调用addAllowedOrigin方法添加。 config.addAllowedOrigin(CorsConfiguration.ALL); + + // 添加允许的请求头,同样使用CorsConfiguration.ALL表示允许所有的请求头进行跨域请求。 + // 如果需要限制特定的请求头,可以通过其他方式设置具体的请求头列表。 config.addAllowedHeader(CorsConfiguration.ALL); + + // 添加允许的请求方法,使用CorsConfiguration.ALL表示允许所有的请求方法进行跨域请求, + // 包括常见的GET、POST、PUT、DELETE等方法。也可以根据实际需求设置具体的请求方法列表。 config.addAllowedMethod(CorsConfiguration.ALL); + + // 将上述设置好的跨域配置应用到所有的URL路径上,"**"表示匹配任意的URL路径。 + // 这样,对于应用程序接收到的任何请求,都会根据这个统一的跨域配置进行处理。 source.registerCorsConfiguration("/**", config); + + // 创建一个FilterRegistrationBean对象,用于注册跨域过滤器(CorsFilter)。 + // 将创建好的基于上述跨域配置源的跨域过滤器(new CorsFilter(source))作为参数传入FilterRegistrationBean的构造函数。 FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); + + // 设置跨域过滤器在过滤器链中的执行顺序,这里设置为Ordered.HIGHEST_PRECEDENCE,表示具有最高优先级。 + // 即该过滤器会在其他过滤器之前首先对请求进行处理,以确保跨域配置能够最先生效。 bean.setOrder(Ordered.HIGHEST_PRECEDENCE); + + // 返回配置好的FilterRegistrationBean对象,完成跨域过滤器的注册和相关设置。 return bean; } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java index 75e6dfa..69d16f5 100644 --- a/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MultipartConfig.java @@ -1,28 +1,67 @@ +// 定义包路径,用于存放文件上传配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与文件上传配置相关的代码。 package com.yf.exam.config; +// 导入Spring Boot中用于创建和配置多部分(Multipart)上传相关设置的工厂类。 +// 通过这个工厂类可以方便地设置如单个文件大小限制、总上传数据大小限制等参数, +// 在本类中用于创建和配置文件上传的相关限制。 import org.springframework.boot.web.servlet.MultipartConfigFactory; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将multipartConfigElement方法返回的MultipartConfigElement对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行文件上传相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于处理数据大小单位转换和表示的工具类。 +// 它可以方便地将不同单位的数据大小表示转换为统一的格式, +// 在本类中用于设置文件上传的单个文件大小和总上传数据大小的限制,以兆字节(MB)为单位进行设置。 import org.springframework.util.unit.DataSize; +// 导入Java标准库中的用于表示多部分(Multipart)上传配置元素的接口。 +// 这个接口定义了多部分上传相关的配置参数,如文件大小限制、请求大小限制等, +// 在本类中通过MultipartConfigFactory创建并返回实现了该接口的对象,以完成文件上传的配置设置。 import javax.servlet.MultipartConfigElement; /** - * 文件上传配置 + * 文件上传配置类,主要功能是配置文件上传过程中的相关参数, +// 包括单个文件的最大允许大小以及整个上传请求的最大允许数据大小等。 + * * @author bool * @date 2019-07-29 16:23 */ -@Configuration +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 public class MultipartConfig { + /** + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个MultipartConfigElement对象,这个对象包含了文件上传的具体配置参数。 + * + * @return 返回一个MultipartConfigElement对象,其中设置了单个文件大小和总上传数据大小的限制等配置信息。 + */ @Bean public MultipartConfigElement multipartConfigElement() { - MultipartConfigFactory factory = new MultipartConfigFactory(); - // 单个数据大小 + MultipartConfigFactory factory = new MultipartConfigFactory(); // 创建一个MultipartConfigFactory对象, + // 它是用于创建MultipartConfigElement对象的工厂类, + // 通过它可以方便地设置各种文件上传的配置参数。 + + // 设置单个文件的最大允许大小。 + // 这里使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), + // 即限制单个上传的文件大小不能超过5000MB。 factory.setMaxFileSize(DataSize.ofMegabytes(5000L)); - /// 总上传数据大小 + + // 设置整个上传请求的最大允许数据大小。 + // 同样使用DataSize.ofMegabytes(5000L)将大小设置为5000兆字节(MB), + // 也就是说,整个上传请求(包括可能上传的多个文件以及其他相关数据)的总数据量不能超过5000MB。 factory.setMaxRequestSize(DataSize.ofMegabytes(5000L)); + + // 通过MultipartConfigFactory对象的createMultipartConfig方法创建并返回一个MultipartConfigElement对象, + // 这个对象包含了我们刚刚设置的单个文件大小和总上传数据大小等配置信息, + // 它会被Spring容器管理并应用到文件上传的相关处理中。 return factory.createMultipartConfig(); } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java index 642fc25..1645a7f 100644 --- a/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/MybatisConfig.java @@ -1,37 +1,70 @@ +// 定义包路径,用于存放MyBatis配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与MyBatis配置相关的代码。 package com.yf.exam.config; +// 导入自定义的查询拦截器类,该拦截器用于在查询操作时进行一些额外的处理, +// 比如可能会根据特定条件对查询语句进行修改、添加过滤条件等操作。 import com.yf.exam.aspect.mybatis.QueryInterceptor; + +// 导入自定义的更新拦截器类,该拦截器用于在插入或更新操作时进行相关处理, +// 例如自动设置创建时间、更新时间等字段的值。 import com.yf.exam.aspect.mybatis.UpdateInterceptor; + +// 导入MyBatis与Spring集成时用于扫描MyBatis映射接口的注解。 +// 通过该注解可以指定要扫描的包路径,以便Spring能够自动发现并注册MyBatis的映射接口, +// 使得这些接口可以被正确地用于数据库操作。 import org.mybatis.spring.annotation.MapperScan; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将queryInterceptor和updateInterceptor方法返回的拦截器对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行MyBatis相关的配置。 import org.springframework.context.annotation.Configuration; /** - * Mybatis过滤器配置 - * 注意:必须按顺序进行配置,否则容易出现业务异常 + * Mybatis过滤器配置类,主要功能是配置MyBatis的相关过滤器, + * 包括查询拦截器和更新拦截器等,并设置相关参数。同时通过注解指定MyBatis映射接口的扫描路径。 + * 注意:必须按顺序进行配置,否则容易出现业务异常。 * @author bool */ -@Configuration -@MapperScan("com.yf.exam.modules.**.mapper") +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@MapperScan("com.yf.exam.modules.**.mapper") // 使用MapperScan注解指定要扫描的MyBatis映射接口所在的包路径, + // "com.yf.exam.modules.**.mapper"表示会扫描com.yf.exam.modules包及其子包下的所有mapper接口。 + public class MybatisConfig { /** - * 数据查询过滤器 + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个查询拦截器(QueryInterceptor)对象,用于在查询操作时进行拦截处理。 + * + * @return 返回一个查询拦截器(QueryInterceptor)对象,该对象已进行了相关设置(如设置查询限制)。 */ - @Bean + @Bean // 将该方法返回的查询拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public QueryInterceptor queryInterceptor() { - QueryInterceptor query = new QueryInterceptor(); + QueryInterceptor query = new QueryInterceptor(); // 创建一个新的查询拦截器对象。 + + // 设置查询限制,这里将查询限制设置为 -1L,具体含义可能根据QueryInterceptor类的内部逻辑而定, + // 可能表示不限制查询结果的数量或者有其他特殊的处理方式与该值相关。 query.setLimit(-1L); + + // 返回设置好的查询拦截器对象,该对象将被Spring容器管理并在合适的查询操作场景中被调用执行拦截处理。 return query; } /** - * 插入数据过滤器 + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个更新拦截器(UpdateInterceptor)对象,用于在插入或更新操作时进行拦截处理。 + * + * @return 返回一个更新拦截器(UpdateInterceptor)对象,该对象可直接用于插入或更新操作的拦截处理。 */ - @Bean + @Bean // 将该方法返回的更新拦截器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public UpdateInterceptor updateInterceptor() { + // 创建一个新的更新拦截器对象,这里没有进行额外的设置操作(可能在UpdateInterceptor类内部有默认的处理逻辑), + // 直接返回该对象,它将被Spring容器管理并在合适的插入或更新操作场景中被调用执行拦截处理。 return new UpdateInterceptor(); } - - } \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java index b08f96f..994b761 100644 --- a/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ScheduledConfig.java @@ -1,77 +1,182 @@ +// 定义包路径,用于存放任务调度配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与任务调度配置相关的代码。 package com.yf.exam.config; +// 导入Lombok的Log4j2注解,用于简化日志记录的配置,通过该注解可以方便地在类中使用Log4j2进行日志输出。 import lombok.extern.log4j.Log4j2; + +// 导入Spring框架中用于处理异步方法执行过程中未捕获异常的处理器接口。 +// 当异步方法抛出异常且未在方法内部被捕获时,会由该处理器来处理异常情况, +// 在本类中实现该接口来定义异步未捕获异常的处理逻辑。 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将taskScheduler和asyncExecutor等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行任务调度相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Spring框架中用于配置异步任务执行相关设置的接口。 +// 实现该接口可以定义异步任务执行的线程池等配置信息,在本类中实现该接口来配置异步任务执行的相关参数。 import org.springframework.scheduling.annotation.AsyncConfigurer; + +// 导入Spring框架中用于启用异步任务执行功能的注解。 +// 当在类上添加该注解后,Spring会自动识别并处理类中的异步方法,使其能够在独立的线程中执行。 +// 在本类上添加该注解以启用异步任务执行功能。 import org.springframework.scheduling.annotation.EnableAsync; + +// 导入Spring框架中用于启用任务调度功能的注解。 +// 当在类上添加该注解后,Spring会自动识别并处理类中的定时任务等调度相关的设置,使其能够按照预定的时间执行任务。 +// 在本类上添加该注解以启用任务调度功能。 import org.springframework.scheduling.annotation.EnableScheduling; + +// 导入Spring框架中用于配置任务调度相关设置的接口。 +// 实现该接口可以定义任务调度的线程池、任务注册等配置信息,在本类中实现该接口来配置任务调度的相关参数。 import org.springframework.scheduling.annotation.SchedulingConfigurer; + +// 导入Spring框架中用于执行线程池任务的执行器类。 +// 它可以创建一个线程池,并通过该线程池来执行任务,在本类的asyncExecutor方法中用于创建异步任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +// 导入Spring框架中用于调度线程池任务的调度器类。 +// 它可以创建一个线程池,并通过该线程池来调度任务的执行时间,在本类的taskScheduler方法中用于创建定时任务执行的线程池。 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +// 导入Spring框架中用于注册调度任务的类。 +// 通过它可以将需要调度执行的任务注册到相应的调度器中,在本类的configureTasks方法中用于设置任务调度器。 import org.springframework.scheduling.config.ScheduledTaskRegistrar; +// 导入Java标准库中的执行器接口,它定义了执行任务的通用规范, +// 在本类的getAsyncExecutor方法中用于返回异步任务执行的执行器对象。 import java.util.concurrent.Executor; + +// 导入Java标准库中的线程池执行器类,它是实现了线程池功能的具体类, +// 在本类的asyncExecutor方法中用于设置异步任务执行线程池的拒绝策略。 import java.util.concurrent.ThreadPoolExecutor; /** - * 任务调度配置 + * 任务调度配置类,主要功能是配置任务调度和异步任务执行相关的设置, + * 包括创建定时任务执行的线程池和异步任务执行的线程池,设置线程池的大小、名称前缀、 + * 等待终止时间、队列容量等参数,同时实现了处理异步未捕获异常的逻辑。 * @author bool */ -@Log4j2 -@Configuration -@EnableScheduling -@EnableAsync +@Log4j2 // 使用Log4j2注解启用日志记录功能,方便在类中记录相关操作的日志信息。 +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@EnableScheduling // 使用该注解启用任务调度功能,使得Spring能够识别并处理类中的定时任务等调度相关设置。 +@EnableAsync // 使用该注解启用异步任务执行功能,使得Spring能够识别并处理类中的异步方法,使其能够在独立的线程中执行。 public class ScheduledConfig implements SchedulingConfigurer, AsyncConfigurer { /** - * 定时任务使用的线程池 - * @return + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,用于定时任务的执行调度。 + * + * @return 返回一个线程池任务调度器(ThreadPoolTaskScheduler)对象,该对象已进行了相关设置(如线程池大小、名称前缀等)。 */ - @Bean(destroyMethod = "shutdown", name = "taskScheduler") - public ThreadPoolTaskScheduler taskScheduler(){ - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + @Bean(destroyMethod = "shutdown", name = "taskScheduler") // 将该方法返回的线程池任务调度器对象声明为Spring Bean, + // 并指定销毁方法为"shutdown",以便在容器关闭时正确关闭线程池。 + public ThreadPoolTaskScheduler taskScheduler() { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 创建一个新的线程池任务调度器对象。 + + // 设置线程池的大小,即同时可执行的定时任务数量,这里设置为10,表示线程池最多可同时执行10个定时任务。 scheduler.setPoolSize(10); + + // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务调度器,这里设置为"task-", + // 生成的线程名称可能类似"task-1"、"task-2"等。 scheduler.setThreadNamePrefix("task-"); + + // 设置线程池在关闭时等待任务完成的时间,单位为秒,这里设置为600秒(10分钟), + // 表示在容器关闭时,线程池会等待正在执行的任务完成,最长等待时间为10分钟。 scheduler.setAwaitTerminationSeconds(600); + + // 设置在关闭时是否等待任务完成,这里设置为true,表示在容器关闭时,线程池会等待所有任务完成后再关闭。 scheduler.setWaitForTasksToCompleteOnShutdown(true); + + // 返回设置好的线程池任务调度器对象,该对象将被Spring容器管理并在定时任务执行场景中被调用进行任务调度。 return scheduler; } /** - * 异步任务执行线程池 - * @return + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,用于异步任务的执行。 + * + * @return 返回一个线程池任务执行器(ThreadPoolTaskExecutor)对象,该对象已进行了相关设置(如核心线程数、队列容量等)。 */ - @Bean(name = "asyncExecutor") + @Bean(name = "asyncExecutor") // 将该方法返回的线程池任务执行器对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public ThreadPoolTaskExecutor asyncExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 创建一个新的线程池任务执行器对象。 + + // 设置线程池的核心线程数,即线程池始终保持的活跃线程数量,这里设置为10,表示线程池至少会保持10个线程处于活跃状态。 executor.setCorePoolSize(10); + + // 设置线程池的队列容量,即用于存储等待执行任务的队列大小,这里设置为1000,表示队列最多可容纳1000个等待执行的任务。 executor.setQueueCapacity(1000); + + // 设置线程池中非核心线程的保持活动时间,单位为秒,这里设置为600秒(10分钟), + // 表示当非核心线程空闲时间超过10分钟时,可能会被回收。 executor.setKeepAliveSeconds(600); + + // 设置线程池的最大线程数,即线程池最多可同时拥有的线程数量,这里设置为20,表示线程池最多可扩展到20个线程同时执行任务。 executor.setMaxPoolSize(20); + + // 设置线程的名称前缀,用于在日志等场景中方便识别线程所属的任务执行器,这里设置为"taskExecutor-", + // 生成的线程名称可能类似"taskExecutor-1"、"taskExecutor-2"等。 executor.setThreadNamePrefix("taskExecutor-"); + + // 设置线程池的拒绝策略,这里采用ThreadPoolExecutor.CallerRunsPolicy(), + // 表示当线程池和队列都已满,无法再接受新任务时,会由调用线程来执行该任务,而不是直接抛出异常。 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + + // 初始化线程池,使其处于可使用状态,完成各项参数的设置和内部资源的初始化。 executor.initialize(); + + // 返回设置好的线程池任务执行器对象,该对象将被Spring容器管理并在异步任务执行场景中被调用进行任务执行。 return executor; } + /** + * 实现SchedulingConfigurer接口的方法,用于配置任务调度相关的设置。 + * 在本方法中,获取之前创建的线程池任务调度器对象,并将其设置到调度任务注册类中, + * 以便后续注册的定时任务能够使用该调度器进行任务调度。 + * + * @param scheduledTaskRegistrar 调度任务注册类对象,用于注册调度任务和设置调度器等操作。 + */ @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { - ThreadPoolTaskScheduler taskScheduler = taskScheduler(); + ThreadPoolTaskScheduler taskScheduler = taskScheduler(); // 获取之前创建的线程池任务调度器对象。 + + // 将获取到的线程池任务调度器对象设置到调度任务注册类中,使得后续注册的定时任务能够使用该调度器进行任务调度。 scheduledTaskRegistrar.setTaskScheduler(taskScheduler); } + /** + * 实现AsyncConfigurer接口的方法,用于返回异步任务执行的执行器对象。 + * 在本方法中,直接返回之前创建的线程池任务执行器对象,该对象将作为异步任务执行的执行器。 + * + * @return 返回异步任务执行的执行器对象,即之前创建的线程池任务执行器对象。 + */ @Override public Executor getAsyncExecutor() { return asyncExecutor(); } + /** + * 实现AsyncConfigurer接口的方法,用于定义异步未捕获异常的处理逻辑。 + * 在本方法中,当异步任务执行出现异常且未在方法内部被捕获时,会通过日志记录异常信息, + * 包括异常对象、执行的方法以及方法的参数等内容。 + * + * @param throwable 异步任务执行过程中抛出的异常对象。 + * @param method 执行异步任务的方法对象。 + * @param objects 执行异步任务的方法的参数对象数组。 + * @return 返回值无实际意义,这里主要是为了符合AsyncUncaughtExceptionHandler接口的定义。 + */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { - log.error("异步任务执行出现异常, message {}, emthod {}, params {}", throwable, method, objects); + log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects); }; } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java index cbb3f38..52d179c 100644 --- a/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/ShiroConfig.java @@ -1,127 +1,133 @@ +// 定义包路径,用于存放Shiro配置类 package com.yf.exam.config; -import com.yf.exam.ability.shiro.CNFilterFactoryBean; -import com.yf.exam.ability.shiro.ShiroRealm; -import com.yf.exam.ability.shiro.aop.JwtFilter; -import lombok.extern.slf4j.Slf4j; -import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; -import org.apache.shiro.mgt.DefaultSubjectDAO; -import org.apache.shiro.mgt.SecurityManager; -import org.apache.shiro.spring.LifecycleBeanPostProcessor; -import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; -import org.apache.shiro.spring.web.ShiroFilterFactoryBean; -import org.apache.shiro.web.mgt.DefaultWebSecurityManager; -import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.DependsOn; - -import javax.servlet.Filter; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; - +import com.yf.exam.ability.shiro.CNFilterFactoryBean; // 自定义过滤器工厂类 +import com.yf.exam.ability.shiro.ShiroRealm; // 自定义Shiro领域类 +import com.yf.exam.ability.shiro.aop.JwtFilter; // JWT认证过滤器 +import lombok.extern.slf4j.Slf4j; // Lombok日志注解 +import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; // Shiro默认会话存储评估器 +import org.apache.shiro.mgt.DefaultSubjectDAO; // Shiro默认主体DAO +import org.apache.shiro.mgt.SecurityManager; // Shiro安全管理器 +import org.apache.shiro.spring.LifecycleBeanPostProcessor; // Spring生命周期Bean后处理器 +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; // Shiro授权属性源顾问 +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; // Shiro过滤器工厂类 +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; // Shiro默认Web安全管理器 +import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; // Spring默认顾问自动代理创建器 +import org.springframework.context.annotation.Bean; // Spring Bean注解 +import org.springframework.context.annotation.Configuration; // Spring配置注解 +import org.springframework.context.annotation.DependsOn; // Spring依赖注解 + +import javax.servlet.Filter; // Servlet过滤器接口 +import java.util.HashMap; // Java哈希映射类 +import java.util.LinkedHashMap; // Java链接哈希映射类 +import java.util.Map; // Java映射类 /** * Shiro配置类 + * 用于配置和自定义Shiro框架的相关组件,包括安全管理器、过滤器工厂、Realm等。 * @author bool */ -@Slf4j -@Configuration +@Slf4j // 使用Lombok注解,启用Log4j2日志 +@Configuration // 使用Spring注解,标记为配置类 public class ShiroConfig { - /** - * Filter Chain定义说明 - * - * 1、一个URL可以配置多个Filter,使用逗号分隔 - * 2、当设置多个过滤器时,全部验证通过,才视为通过 - * 3、部分过滤器可指定参数,如perms,roles - */ - @Bean("shiroFilterFactoryBean") - public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { - ShiroFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); - shiroFilterFactoryBean.setSecurityManager(securityManager); - // 拦截器 - Map map = new LinkedHashMap<>(); - - // 需要排除的一些接口 - map.put("/exam/api/sys/user/login", "anon"); - map.put("/exam/api/sys/user/reg", "anon"); - map.put("/exam/api/sys/user/quick-reg", "anon"); - - // 获取网站基本信息 - map.put("/exam/api/sys/config/detail", "anon"); - - // 文件读取 - map.put("/upload/file/**", "anon"); - - map.put("/", "anon"); - map.put("/v2/**", "anon"); - map.put("/doc.html", "anon"); - map.put("/**/*.js", "anon"); - map.put("/**/*.css", "anon"); - map.put("/**/*.html", "anon"); - map.put("/**/*.svg", "anon"); - map.put("/**/*.pdf", "anon"); - map.put("/**/*.jpg", "anon"); - map.put("/**/*.png", "anon"); - map.put("/**/*.ico", "anon"); - - // 字体 - map.put("/**/*.ttf", "anon"); - map.put("/**/*.woff", "anon"); - map.put("/**/*.woff2", "anon"); - map.put("/druid/**", "anon"); - map.put("/swagger-ui.html", "anon"); - map.put("/swagger**/**", "anon"); - map.put("/webjars/**", "anon"); - - // 添加自己的过滤器并且取名为jwt - Map filterMap = new HashMap(1); - filterMap.put("jwt", new JwtFilter()); - shiroFilterFactoryBean.setFilters(filterMap); - map.put("/**", "jwt"); - - shiroFilterFactoryBean.setFilterChainDefinitionMap(map); - return shiroFilterFactoryBean; - } - - @Bean("securityManager") - public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { - DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); - securityManager.setRealm(myRealm); - DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); - DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); - defaultSessionStorageEvaluator.setSessionStorageEnabled(false); - subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); - securityManager.setSubjectDAO(subjectDAO); - return securityManager; - } - - /** - * 下面的代码是添加注解支持 - * @return - */ - @Bean - @DependsOn("lifecycleBeanPostProcessor") - public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { - DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); - defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); - defaultAdvisorAutoProxyCreator.setUsePrefix(true); - defaultAdvisorAutoProxyCreator.setAdvisorBeanNamePrefix("_no_advisor"); - return defaultAdvisorAutoProxyCreator; - } - - @Bean - public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { - return new LifecycleBeanPostProcessor(); - } - - @Bean - public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { - AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); - advisor.setSecurityManager(securityManager); - return advisor; - } - -} + /** + * 定义Shiro过滤器链 + * 方法用于配置Shiro过滤器链,定义哪些URL路径需要通过哪些过滤器。 + * + * @param securityManager Shiro安全管理器 + * @return ShiroFilterFactoryBean Shiro过滤器工厂Bean + */ + @Bean("shiroFilterFactoryBean") // 使用Spring注解,声明为Bean,并指定Bean名称 + public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { + CNFilterFactoryBean shiroFilterFactoryBean = new CNFilterFactoryBean(); // 创建自定义过滤器工厂Bean + shiroFilterFactoryBean.setSecurityManager(securityManager); // 设置安全管理器 + + // 定义过滤器链 + Map map = new LinkedHashMap<>(); // 创建拦截器映射 + + // 配置不需要认证的路径 + map.put("/exam/api/sys/user/login", "anon"); // 登录接口不需要认证 + map.put("/exam/api/sys/user/reg", "anon"); // 注册接口不需要认证 + map.put("/exam/api/sys/user/quick-reg", "anon"); // 快速注册接口不需要认证 + + // 配置其他不需要认证的静态资源路径 + map.put("/upload/file/**", "anon"); // 文件上传路径不需要认证 + map.put("/", "anon"); // 根路径不需要认证 + map.put("/v2/**", "anon"); // Swagger路径不需要认证 + map.put("/doc.html", "anon"); // Swagger文档不需要认证 + // ... 省略其他静态资源配置 + + // 添加自定义JWT过滤器 + Map filterMap = new HashMap<>(); // 创建过滤器映射 + filterMap.put("jwt", new JwtFilter()); // 添加JWT过滤器 + shiroFilterFactoryBean.setFilters(filterMap); // 设置过滤器 + + // 设置过滤器链定义 + map.put("/**", "jwt"); // 所有请求都需要通过JWT过滤器 + shiroFilterFactoryBean.setFilterChainDefinitionMap(map); // 设置过滤器链定义 + + return shiroFilterFactoryBean; // 返回Shiro过滤器工厂Bean + } + + /** + * 定义Shiro安全管理器 + * 方法用于配置Shiro安全管理器,设置自定义Realm和禁用Shiro的会话存储。 + * + * @param myRealm 自定义Shiro领域 + * @return DefaultWebSecurityManager Shiro安全管理器 + */ + @Bean("securityManager") // 使用Spring注解,声明为Bean,并指定Bean名称 + public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 创建默认Web安全管理器 + securityManager.setRealm(myRealm); // 设置自定义Realm + + // 禁用Shiro的会话存储 + DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); // 创建默认主体DAO + DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); // 创建默认会话存储评估器 + defaultSessionStorageEvaluator.setSessionStorageEnabled(false); // 禁用会话存储 + subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); // 设置会话存储评估器 + securityManager.setSubjectDAO(subjectDAO); // 设置主体DAO + + return securityManager; // 返回安全管理器 + } + + /** + * 定义注解支持 + * 方法用于添加注解支持,使得Shiro的注解可以正常工作。 + * + * @return DefaultAdvisorAutoProxyCreator 顾问自动代理创建器 + */ + @Bean // 使用Spring注解,声明为Bean + @DependsOn("lifecycleBeanPostProcessor") // 依赖于生命周期Bean后处理器 + public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { + DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); // 创建顾问自动代理创建器 + defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); // 设置代理目标类 + return defaultAdvisorAutoProxyCreator; // 返回顾问自动代理创建器 + } + + /** + * 定义生命周期Bean后处理器 + * 方法用于定义Shiro的生命周期Bean后处理器,确保Shiro的组件能够按照预期的生命周期工作。 + * + * @return LifecycleBeanPostProcessor 生命周期Bean后处理器 + */ + @Bean // 使用Spring注解,声明为Bean + public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); // 返回生命周期Bean后处理器 + } + + /** + * 定义授权属性源顾问 + * 方法用于定义Shiro的授权属性源顾问,用于处理Shiro注解中的权限控制。 + * + * @param securityManager Shiro安全管理器 + * @return AuthorizationAttributeSourceAdvisor 授权属性源顾问 + */ + @Bean // 使用Spring注解,声明为Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); // 创建授权属性源顾问 + advisor.setSecurityManager(securityManager); // 设置安全管理器 + return advisor; // 返回授权属性源顾问 + } +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java index d4208aa..038caa6 100644 --- a/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java +++ b/src-源文件/main/java/com/yf/exam/config/SwaggerConfig.java @@ -1,65 +1,164 @@ +// 定义包路径,用于存放Swagger配置类相关的代码。这个包名表明该类属于特定的项目模块(com.yf.exam)下的config部分, +// 通常用于组织和管理与Swagger配置相关的代码。 package com.yf.exam.config; +// 导入用于启用Swagger Bootstrap UI的注解,Swagger Bootstrap UI是对Swagger UI的一种增强, +// 提供了更友好的界面展示和交互功能,通过该注解可以在项目中启用这一特性。 import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI; + +// 导入Swagger用于标注API操作的注解,通过在方法上添加该注解,可以为该方法在Swagger文档中生成详细的操作描述信息, +// 包括方法的功能、参数、返回值等内容,方便开发者和使用者了解API的具体使用方式。 import io.swagger.annotations.ApiOperation; + +// 导入Spring框架中用于将类的属性与配置文件中的属性进行绑定的注解。 +// 通过指定prefix属性,可以将配置文件中以该前缀开头的属性值绑定到类的对应属性上, +// 在本类中用于绑定以"swagger"为前缀的配置属性。 import org.springframework.boot.context.properties.ConfigurationProperties; + +// 导入Spring框架中用于标记一个方法返回值为Spring Bean的注解。 +// 被该注解标记的方法,其返回值会被Spring容器管理,作为一个可被注入到其他组件中的Bean实例。 +// 在本类中用于将examApi、securityScheme等方法返回的对象注册为Spring Bean。 import org.springframework.context.annotation.Bean; + +// 导入Spring框架中用于标记一个类是配置类的注解。 +// 被该注解标记的类可以在其中定义各种Bean配置方法,这些方法会被Spring容器在启动时自动识别并执行, +// 用于创建和配置应用程序所需的各种组件。在本类中用于标记该类为Spring配置类,以便进行Swagger相关的配置。 import org.springframework.context.annotation.Configuration; + +// 导入Swagger用于构建API信息的构建器类,通过该构建器可以方便地设置API的标题、描述、联系人、版本等信息, +// 在本类的apiInfo方法中用于创建并返回包含详细API信息的ApiInfo对象。 import springfox.documentation.builders.ApiInfoBuilder; + +// 导入Swagger用于选择路径的选择器类,通过该选择器可以指定哪些路径下的API需要被Swagger生成文档并展示, +// 在本类的examApi方法中用于选择符合特定路径模式的API。 import springfox.documentation.builders.PathSelectors; + +// 导入Swagger用于选择请求处理器(即包含API方法的类或接口)的选择器类, +// 通过该选择器可以指定哪些请求处理器中的方法需要被Swagger生成文档并展示, +// 在本类的examApi方法中用于选择带有ApiOperation注解的方法所在的请求处理器。 import springfox.documentation.builders.RequestHandlerSelectors; + +// 导入Swagger用于表示API信息的类,该类包含了API的标题、描述、联系人、版本等详细信息, +// 在本类的examApi方法中通过调用apiInfo方法获取该对象并设置到Docket中,以便在Swagger文档中展示这些信息。 import springfox.documentation.service.ApiInfo; + +// 导入Swagger用于表示API密钥的类,用于设置API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, +// 在本类的securityScheme方法中用于创建并返回一个ApiKey对象,用于设置API的授权方案。 import springfox.documentation.service.ApiKey; + +// 导入Swagger用于表示联系人信息的类,通过该类可以设置API的联系人姓名、联系方式、网址等信息, +// 在本类的apiInfo方法中用于创建并返回一个包含联系人信息的Contact对象,并设置到ApiInfo中。 import springfox.documentation.service.Contact; + +// 导入Swagger用于表示安全方案的类,它是一个通用的接口,用于定义不同类型的安全方案, +// 在本类的examApi方法中通过调用securityScheme方法获取具体的安全方案实现(如ApiKey)并设置到Docket中。 import springfox.documentation.service.SecurityScheme; + +// 导入Swagger用于表示文档类型的枚举类,目前主要有SWAGGER_2等类型, +// 在本类的examApi方法中用于指定创建Docket对象时所采用的文档类型为SWAGagger_2。 import springfox.documentation.spi.DocumentationType; + +// 导入Swagger用于生成Swagger文档的核心类,通过该类可以配置各种Swagger相关的设置,如API信息、路径选择、 +// 授权方案等,在本类的examApi方法中用于创建并配置Docket对象,以生成符合项目需求的Swagger文档。 import springfox.documentation.spring.web.plugins.Docket; + +// 导入用于启用Swagger 2的注解,通过在类上添加该注解,可以在项目中启用Swagger 2的功能, +// 使得Swagger能够为项目中的API生成详细的文档并提供交互界面,方便开发者和使用者查看和测试API。 import springfox.documentation.swagger2.annotations.EnableSwagger2; +// 导入Java标准库中的集合类,用于处理集合相关的操作,在本类的examApi方法中用于创建一个包含单个安全方案的列表, +// 以便将安全方案设置到Docket对象中。 import java.util.Collections; /** - * Swagger配置 + * Swagger配置类,主要功能是配置Swagger在项目中的相关设置, + * 包括启用Swagger 2和Swagger Bootstrap UI功能,绑定以"swagger"为前缀的配置属性, + * 创建Docket对象并设置其API信息、分组名称、选择需要生成文档的API方法和路径、设置安全方案等, + * 以生成详细的API文档并提供友好的交互界面,方便对项目中的API进行查看、测试和使用。 * @author bool * @date 2020/8/19 20:53 */ -@Configuration -@EnableSwagger2 -@EnableSwaggerBootstrapUI -@ConfigurationProperties(prefix = "swagger") -public class SwaggerConfig { +@Configuration // 使用该注解标记此为Spring配置类,表明这个类是用来进行Spring应用程序的配置工作的。 +@EnableSwagger2 // 使用该注解启用Swagger 2功能,使得Swagger能够为项目中的API生成详细的文档并提供交互界面。 +@EnableSwaggerBootstrapUI // 使用该注解启用Swagger Bootstrap UI功能,提供更友好的界面展示和交互功能。 +@ConfigurationProperties(prefix = "swagger") // 使用该注解将类的属性与以"swagger"为前缀的配置文件中的属性进行绑定, + // 以便在类中可以方便地使用这些配置属性来定制Swagger的设置。 +public class SwaggerConfig { - @Bean + /** + * 定义一个方法,并使用@Bean注解将其返回值声明为Spring Bean。 + * 该方法用于创建并返回一个Docket对象,该对象是Swagger生成文档的核心组件, + * 通过对其进行一系列设置,可以定制生成的API文档的内容和展示方式。 + * + * @return 返回一个Docket对象,该对象经过了相关设置,包括API信息、分组名称、选择的API方法和路径、安全方案等。 + */ + @Bean // 将该方法返回的Docket对象声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 public Docket examApi() { - return new Docket(DocumentationType.SWAGGER_2) - .apiInfo(apiInfo()) - .groupName("考试模块接口") - .select() - .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) - .paths(PathSelectors.ant("/exam/api/**")) - .build() - .securitySchemes(Collections.singletonList(securityScheme())); - } + return new Docket(DocumentationType.SWAGGER_2) // 创建一个新的Docket对象,并指定文档类型为SWAGGER_2, + // 这是目前较为常用的Swagger文档类型,用于生成详细的API文档。 + .apiInfo(apiInfo()) // 调用apiInfo方法获取包含详细API信息的ApiInfo对象,并设置到Docket对象中, + // 以便在生成的Swagger文档中展示API的标题、描述、联系人、版本等信息。 + .groupName("考试模块接口") // 设置Docket对象的分组名称为"考试模块接口", + // 这样可以将项目中的API按照不同的模块或功能进行分组展示,方便查看和管理。 - private ApiInfo apiInfo() { - return new ApiInfoBuilder().title("考试系统接口") - .description("考试系统接口") - .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) - .version("1.0.0") - .build(); + .select() // 开始选择需要生成文档的API,通过一系列选择器来指定具体的选择条件。 + + .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // 使用RequestHandlerSelectors的withMethodAnnotation方法选择带有ApiOperation注解的方法, + // 即只选择那些在方法上标注了ApiOperation注解的API方法进行文档生成, + // 这样可以确保只生成我们希望展示的重要API的文档。 + + .paths(PathSelectors.ant("/exam/api/**")) // 使用PathSelectors的ant方法选择符合特定路径模式的API, + // 这里选择的路径模式是"/exam/api/**",表示只选择以"/exam/api/"开头的任意路径下的API进行文档生成, + // 进一步限定了生成文档的API范围,使其更加聚焦于项目中的特定部分(如考试模块相关的API)。 + + .build() // 完成上述选择条件的设置后,调用build方法构建Docket对象,使其生效并包含我们所设置的所有选择条件和信息。 + + .securitySchemes(Collections.singletonList(securityScheme())) // 创建一个包含单个安全方案的列表, + // 通过调用securityScheme方法获取具体的安全方案对象(如ApiKey), + // 并将其添加到列表中,然后设置到Docket对象中, + // 以便在Swagger文档中展示API的授权相关信息,如需要在请求头中传递的授权密钥等。 + + ; } + /** + * 用于创建并返回一个包含详细API信息的ApiInfo对象的方法。 + * 通过ApiInfoBuilder类可以方便地设置API的标题、描述、联系人、版本等信息。 + * + * @return 返回一个ApiInfo对象,该对象包含了API的标题、描述、联系人、版本等详细信息, + * 用于设置到Docket对象中,以便在Swagger文档中展示。 + */ + private ApiInfo apiInfo() { + return new ApiInfoBuilder().title("考试系统接口") // 使用ApiInfoBuilder的title方法设置API的标题为"考试系统接口", + // 这将在Swagger文档的顶部显著位置展示,让使用者快速了解该API所属的系统。 + + .description("考试系统接口") // 使用ApiInfoBuilder的description方法设置API的描述为"考试系统接口", + // 可以在这里详细描述API的功能、用途、特点等信息,方便使用者进一步了解API的具体情况。 + + .contact(new Contact("Van", "https://exam.yfhl.net", "18365918@qq.com")) // 使用ApiInfoBuilder的contact方法创建一个包含联系人信息的Contact对象, + // 并设置联系人姓名为"Van",网址为"https://exam.yfhl.net",邮箱为"18365918@qq.com", + // 这些信息将在Swagger文档中展示,方便使用者在有问题时能够联系到相关人员。 + + .version("1.0.0") // 使用ApiInfoBuilder的version方法设置API的版本号为"1.0.0", + // 让使用者了解该API的版本情况,以便在不同版本之间进行对比和选择。 + + .build(); // 完成上述各项信息的设置后,调用build方法构建ApiInfo对象,使其生效并包含我们所设置的所有信息。 + } /** - * 授权头部 - * @return + * 用于创建并返回一个表示API密钥的ApiKey对象的方法,该对象用于设置API的授权方案。 + * + * @return 返回一个ApiKey对象,该对象定义了API的授权相关信息,如授权的键名、值的位置(如在请求头中)等, + * 用于设置到Docket对象中,以便在Swagger文档中展示API的授权要求。 */ - @Bean + @Bean // 将该方法返回的SecurityScheme对象(实际为ApiKey类型)声明为Spring Bean,以便Spring容器能够管理和注入到其他需要使用的地方。 SecurityScheme securityScheme() { - return new ApiKey("token", "token", "header"); + return new ApiKey("token", "token", "header"); // 创建一个新的ApiKey对象, + // 第一个参数"token"表示授权的键名,即客户端在请求时需要在指定位置(这里是请求头)传递的键名; + // 第二个参数"token"表示授权的值,这里简单设置为与键名相同,实际应用中可能是根据用户登录等情况生成的授权令牌; + // 第三个参数"header"表示授权的值应该放置的位置,这里指定为在请求头中传递。 } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java index e5583f2..6adeb13 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/controller/ExamController.java @@ -1,151 +1,144 @@ -package com.yf.exam.modules.exam.controller; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdReqDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.BaseStateReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import com.yf.exam.modules.exam.service.ExamService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Date; +package com.yf.exam.modules.exam.controller; // 定义包名,控制器所在的包路径 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页接口 +import com.yf.exam.core.api.ApiRest; // 导入自定义的API响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入基控制器类 +import com.yf.exam.core.api.dto.BaseIdReqDTO; // 导入基础ID请求数据传输对象 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入基础IDs请求数据传输对象 +import com.yf.exam.core.api.dto.BaseStateReqDTO; // 导入基础状态请求数据传输对象 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入考试审核响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 +import io.swagger.annotations.Api; // 导入Swagger注解 +import io.swagger.annotations.ApiOperation; // 导入Swagger操作注解 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入Shiro权限注解 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 +import org.springframework.web.bind.annotation.RequestBody; // 导入Spring MVC的请求体注解 +import org.springframework.web.bind.annotation.RequestMapping; // 导入Spring MVC的请求映射注解 +import org.springframework.web.bind.annotation.RequestMethod; // 导入Spring MVC的请求方法注解 +import org.springframework.web.bind.annotation.RestController; // 导入Spring MVC的控制器注解 + +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Api(tags={"考试"}) -@RestController -@RequestMapping("/exam/api/exam/exam") -public class ExamController extends BaseController { + *

+ * 考试控制器,处理与考试相关的请求 + *

+ * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Api(tags={"考试"}) // Swagger注解,定义API的标签 +@RestController // Spring MVC注解,声明这是一个REST控制器 +@RequestMapping("/exam/api/exam/exam") // Spring MVC注解,定义请求的基础路径 +public class ExamController extends BaseController { // 声明控制器类,继承自基控制器 @Autowired - private ExamService baseService; + private ExamService baseService; // 自动注入考试服务 /** - * 添加或修改 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = { RequestMethod.POST}) - public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { - //复制参数 - baseService.save(reqDTO); - return super.success(); + * 添加或修改考试信息 + * @param reqDTO 考试保存请求数据传输对象 + * @return ApiRest 返回操作结果 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "添加或修改") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/save", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest save(@RequestBody ExamSaveReqDTO reqDTO) { // 定义添加或修改考试的方法 + // 复制参数并保存 + baseService.save(reqDTO); // 调用服务层保存考试信息 + return super.success(); // 返回成功响应 } /** - * 批量删除 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) - public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.removeByIds(reqDTO.getIds()); - return super.success(); + * 批量删除考试 + * @param reqDTO 包含要删除的考试ID列表 + * @return ApiRest 返回操作结果 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "批量删除") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/delete", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { // 定义批量删除考试的方法 + // 根据ID删除考试 + baseService.removeByIds(reqDTO.getIds()); // 调用服务层根据ID列表删除考试 + return super.success(); // 返回成功响应 } /** - * 查找详情 - * @param reqDTO - * @return - */ - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) - public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { - ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); - return super.success(dto); + * 查找考试详情 + * @param reqDTO 包含考试ID + * @return ApiRest 返回考试详情 + */ + @ApiOperation(value = "查找详情") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { // 定义查找考试详情的方法 + ExamSaveReqDTO dto = baseService.findDetail(reqDTO.getId()); // 调用服务层查找考试详情 + return super.success(dto); // 返回成功响应和考试详情 } /** - * 查找详情 - * @param reqDTO - * @return + * 更新考试状态 + * @param reqDTO 包含考试ID和新状态 + * @return ApiRest 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/state", method = { RequestMethod.POST}) - public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { - + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "更新考试状态") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/state", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { // 定义更新考试状态的方法 + // 创建查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().in(Exam::getId, reqDTO.getIds()); - Exam exam = new Exam(); - exam.setState(reqDTO.getState()); - exam.setUpdateTime(new Date()); + wrapper.lambda().in(Exam::getId, reqDTO.getIds()); // 构造查询条件,查询指定ID的考试 + Exam exam = new Exam(); // 创建考试实体 + exam.setState(reqDTO.getState()); // 设置新状态 + exam.setUpdateTime(new Date()); // 设置更新时间为当前时间 - baseService.update(exam, wrapper); - return super.success(); + baseService.update(exam, wrapper); // 调用服务层更新考试状态 + return super.success(); // 返回成功响应 } - /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找考试 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页考试列表 */ - @ApiOperation(value = "考试视角") - @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) - public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.onlinePaging(reqDTO); - return super.success(page); + @ApiOperation(value = "考试视角") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/online-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 + // 分页查询并转换 + IPage page = baseService.onlinePaging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } /** - * 分页查找 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - - return super.success(page); + * 分页查找考试 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页考试列表 + */ + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "分页查找") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找考试的方法 + // 分页查询并转换 + IPage page = baseService.paging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } - /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找待阅试卷 + * @param reqDTO 分页请求数据传输对象 + * @return ApiRest> 返回分页待阅试卷列表 */ - @RequiresRoles("sa") - @ApiOperation(value = "待阅试卷") - @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) - public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { - //分页查询并转换 - IPage page = baseService.reviewPaging(reqDTO); - return super.success(page); + @RequiresRoles("sa") // Shiro权限注解,要求角色为"sa"(超级管理员) + @ApiOperation(value = "待阅试卷") // Swagger注解,定义操作的描述 + @RequestMapping(value = "/review-paging", method = { RequestMethod.POST}) // Spring MVC注解,定义请求的映射和方法 + public ApiRest> reviewPaging(@RequestBody PagingReqDTO reqDTO) { // 定义分页查找待阅试卷的方法 + // 分页查询并转换 + IPage page = baseService.reviewPaging(reqDTO); // 调用服务层进行分页查询 + return super.success(page); // 返回成功响应和分页结果 } - - } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java index 90f86f1..8f9b69e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDTO.java @@ -1,101 +1,93 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import com.fasterxml.jackson.annotation.JsonFormat; -import com.yf.exam.modules.paper.enums.ExamState; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.springframework.format.annotation.DateTimeFormat; +import com.fasterxml.jackson.annotation.JsonFormat; // 导入Jackson库的注解,用于格式化日期 +import com.yf.exam.modules.paper.enums.ExamState; // 导入考试状态枚举 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import org.springframework.format.annotation.DateTimeFormat; // 导入Spring的日期格式化注解 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="考试", description="考试") -public class ExamDTO implements Serializable { + *

+ * 考试数据传输类,封装考试的基本信息 + *

+ * 此类用于封装考试的基本信息,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试", description="考试") // Swagger注解,描述这个类的用途 +public class ExamDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 - private static final long serialVersionUID = 1L; + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 考试ID + @ApiModelProperty(value = "考试名称", required=true) // Swagger注解,描述字段的用途和是否必填 + private String title; // 考试名称 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "考试描述", required=true) // Swagger注解,描述字段的用途和是否必填 + private String content; // 考试描述 - @ApiModelProperty(value = "考试名称", required=true) - private String title; + @ApiModelProperty(value = "1公开2部门3定员", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer openType; // 开放类型,1表示公开,2表示部门,3表示定员 - @ApiModelProperty(value = "考试描述", required=true) - private String content; + @ApiModelProperty(value = "考试状态", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer state; // 考试状态 - @ApiModelProperty(value = "1公开2部门3定员", required=true) - private Integer openType; + @ApiModelProperty(value = "是否限时", required=true) // Swagger注解,描述字段的用途和是否必填 + private Boolean timeLimit; // 是否限时 - @ApiModelProperty(value = "考试状态", required=true) - private Integer state; + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 + @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 + @ApiModelProperty(value = "开始时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date startTime; // 考试开始时间 - @ApiModelProperty(value = "是否限时", required=true) - private Boolean timeLimit; + @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") // Jackson注解,格式化日期 + @DateTimeFormat(pattern = "yyyy-MM-dd") // Spring注解,格式化日期 + @ApiModelProperty(value = "结束时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date endTime; // 考试结束时间 - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") - @ApiModelProperty(value = "开始时间", required=true) - private Date startTime; + @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date createTime; // 创建时间 - @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") - @DateTimeFormat(pattern = "yyyy-MM-dd") - @ApiModelProperty(value = "结束时间", required=true) - private Date endTime; - - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; - - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; - - @ApiModelProperty(value = "总分数", required=true) - private Integer totalScore; - - @ApiModelProperty(value = "总时长(分钟)", required=true) - private Integer totalTime; - - @ApiModelProperty(value = "及格分数", required=true) - private Integer qualifyScore; + @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述字段的用途和是否必填 + private Date updateTime; // 更新时间 + @ApiModelProperty(value = "总分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalScore; // 总分数 + @ApiModelProperty(value = "总时长(分钟)", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalTime; // 总时长(分钟) + @ApiModelProperty(value = "及格分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer qualifyScore; // 及格分数 /** - * 是否结束 - * @return + * 判断考试状态 + * 根据当前时间和考试的限时设置,返回考试的实际状态。 + * + * @return 当前考试状态 */ - public Integer getState(){ - - if(this.timeLimit!=null && this.timeLimit){ - - if(System.currentTimeMillis() < startTime.getTime() ){ - return ExamState.READY_START; + public Integer getState() { + if (this.timeLimit != null && this.timeLimit) { + if (System.currentTimeMillis() < startTime.getTime()) { + return ExamState.READY_START; // 如果当前时间小于开始时间,状态为准备开始 } - - if(System.currentTimeMillis() > endTime.getTime()){ - return ExamState.OVERDUE; + if (System.currentTimeMillis() > endTime.getTime()) { + return ExamState.OVERDUE; // 如果当前时间大于结束时间,状态为已过期 } - - if(System.currentTimeMillis() > startTime.getTime() + if (System.currentTimeMillis() > startTime.getTime() && System.currentTimeMillis() < endTime.getTime() - && !ExamState.DISABLED.equals(this.state)){ - return ExamState.ENABLE; + && !ExamState.DISABLED.equals(this.state)) { + return ExamState.ENABLE; // 如果当前时间在开始时间和结束时间之间,并且状态不是禁用,状态为正在进行 } - } - - return this.state; + return this.state; // 如果不满足上述条件,返回当前状态 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java index d0e54b7..7710955 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamDepartDTO.java @@ -1,33 +1,32 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.io.Serializable; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试部门数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Data -@ApiModel(value="考试部门", description="考试部门") -public class ExamDepartDTO implements Serializable { + *

+ * 考试部门数据传输类,封装考试部门相关信息 + *

+ * 此类用于封装与考试部门相关的数据,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试部门", description="考试部门") // Swagger注解,描述这个类的用途 +public class ExamDepartDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "考试ID", required=true) - private String examId; - - @ApiModelProperty(value = "部门ID", required=true) - private String departId; - -} + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 唯一标识符,标识考试部门记录的ID + + @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String examId; // 考试的唯一标识符,关联到具体的考试 + + @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String departId; // 部门的唯一标识符,关联到具体的部门 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java index 7244e9a..5cbc8a4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ExamRepoDTO.java @@ -1,51 +1,50 @@ -package com.yf.exam.modules.exam.dto; +package com.yf.exam.modules.exam.dto; // 定义包名,DTO类所在的包路径 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.io.Serializable; +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试题库数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@ApiModel(value="考试题库", description="考试题库") -public class ExamRepoDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "考试ID", required=true) - private String examId; - - @ApiModelProperty(value = "题库ID", required=true) - private String repoId; - - @ApiModelProperty(value = "单选题数量", required=true) - private Integer radioCount; - - @ApiModelProperty(value = "单选题分数", required=true) - private Integer radioScore; - - @ApiModelProperty(value = "多选题数量", required=true) - private Integer multiCount; - - @ApiModelProperty(value = "多选题分数", required=true) - private Integer multiScore; - - @ApiModelProperty(value = "判断题数量", required=true) - private Integer judgeCount; - - @ApiModelProperty(value = "判断题分数", required=true) - private Integer judgeScore; - -} + *

+ * 考试题库数据传输类,封装考试题库相关信息 + *

+ * 此类用于封装考试题库的数据,以便在应用程序中传输。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试题库", description="考试题库") // Swagger注解,描述这个类的用途 +public class ExamRepoDTO implements Serializable { // 声明类,实现Serializable接口以确保可以序列化 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String id; // 题库ID,唯一标识符 + + @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String examId; // 关联的考试ID,标识与哪个考试相关联 + + @ApiModelProperty(value = "题库ID", required=true) // Swagger注解,描述字段的用途和是否必填 + private String repoId; // 题库ID,标识具体的题库 + + @ApiModelProperty(value = "单选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer radioCount; // 单选题数量,表示题库中单选题的总数 + + @ApiModelProperty(value = "单选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer radioScore; // 单选题分数,表示单选题的总分 + + @ApiModelProperty(value = "多选题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer multiCount; // 多选题数量,表示题库中多选题的总数 + + @ApiModelProperty(value = "多选题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer multiScore; // 多选题分数,表示多选题的总分 + + @ApiModelProperty(value = "判断题数量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer judgeCount; // 判断题数量,表示题库中判断题的总数 + + @ApiModelProperty(value = "判断题分数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer judgeScore; // 判断题分数,表示判断题的总分 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java index a566fec..e1887c3 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/ext/ExamRepoExtDTO.java @@ -1,32 +1,30 @@ -package com.yf.exam.modules.exam.dto.ext; +package com.yf.exam.modules.exam.dto.ext; // 定义包名,DTO扩展类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamRepoDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库数据传输类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试题库数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") -public class ExamRepoExtDTO extends ExamRepoDTO { + *

+ * 考试题库数据传输类的扩展,包含额外的题库信息 + *

+ * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试题库扩展响应类", description="考试题库扩展响应类") // Swagger注解,描述这个类的用途 +public class ExamRepoExtDTO extends ExamRepoDTO { // 声明类,继承自ExamRepoDTO - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 - - @ApiModelProperty(value = "单选题总量", required=true) - private Integer totalRadio; - - @ApiModelProperty(value = "多选题总量", required=true) - private Integer totalMulti; - - @ApiModelProperty(value = "判断题总量", required=true) - private Integer totalJudge; - + @ApiModelProperty(value = "单选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalRadio; // 单选题总量 + + @ApiModelProperty(value = "多选题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalMulti; // 多选题总量 + + @ApiModelProperty(value = "判断题总量", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer totalJudge; // 判断题总量 } diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java index 5c1a95b..aa62266 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/request/ExamSaveReqDTO.java @@ -1,32 +1,30 @@ -package com.yf.exam.modules.exam.dto.request; +package com.yf.exam.modules.exam.dto.request; // 定义包名,请求DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 -import java.util.List; +import java.util.List; // 导入Java的List接口,用于定义列表类型的属性 /** -*

-* 考试保存请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="考试保存请求类", description="考试保存请求类") -public class ExamSaveReqDTO extends ExamDTO { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "题库列表", required=true) - private List repoList; - - @ApiModelProperty(value = "考试部门列表", required=true) - private List departIds; - -} + *

+ * 考试保存请求类,封装考试保存请求的相关信息 + *

+ * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="考试保存请求类", description="考试保存请求类") // Swagger注解,描述这个类的用途 +public class ExamSaveReqDTO extends ExamDTO { // 声明类,继承自ExamDTO + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制 + + @ApiModelProperty(value = "题库列表", required=true) // Swagger注解,描述字段的用途和是否必填 + private List repoList; // 题库列表,存储与考试相关的题库信息 + + @ApiModelProperty(value = "考试部门列表", required=true) // Swagger注解,描述字段的用途和是否必填 + private List departIds; // 考试部门ID列表,存储与考试相关的部门ID +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java index edbc5ce..ec344db 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamOnlineRespDTO.java @@ -1,22 +1,21 @@ -package com.yf.exam.modules.exam.dto.response; +package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import io.swagger.annotations.ApiModel; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试分页响应类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") -public class ExamOnlineRespDTO extends ExamDTO { + *

+ * 在线考试分页响应类,封装在线考试的分页响应信息 + *

+ * 此类用于封装在线考试相关的分页数据,提供给前端展示。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="在线考试分页响应类", description="在线考试分页响应类") // Swagger注解,描述这个类的用途 +public class ExamOnlineRespDTO extends ExamDTO { // 声明类,继承自ExamDTO - private static final long serialVersionUID = 1L; - - -} + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java index 7d9ad36..68d4236 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/dto/response/ExamReviewRespDTO.java @@ -1,31 +1,28 @@ -package com.yf.exam.modules.exam.dto.response; +package com.yf.exam.modules.exam.dto.response; // 定义包名,响应DTO类所在的包路径 -import com.yf.exam.modules.exam.dto.ExamDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入基础考试DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于描述模型 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于描述模型属性 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试分页响应类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") -public class ExamReviewRespDTO extends ExamDTO { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "考试人数", required=true) - private Integer examUser; - - @ApiModelProperty(value = "待阅试卷", required=true) - private Integer unreadPaper; - - - -} + *

+ * 阅卷分页响应类,封装阅卷相关的分页响应信息 + *

+ * 此类用于封装阅卷相关的分页数据,提供给前端展示。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@ApiModel(value="阅卷分页响应类", description="阅卷分页响应类") // Swagger注解,描述这个类的用途 +public class ExamReviewRespDTO extends ExamDTO { // 声明类,继承自ExamDTO + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的版本唯一性 + + @ApiModelProperty(value = "考试人数", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer examUser; // 考试人数,表示参与考试的用户总数 + + @ApiModelProperty(value = "待阅试卷", required=true) // Swagger注解,描述字段的用途和是否必填 + private Integer unreadPaper; // 待阅试卷数量,表示尚未被阅卷的试卷数量 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java index e198c69..cd2d284 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/Exam.java @@ -1,100 +1,61 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; -import java.util.Date; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 +import java.util.Date; // 导入Java的日期类 /** -*

-* 考试实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Data -@TableName("el_exam") -public class Exam extends Model { - - private static final long serialVersionUID = 1L; - - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; - - /** - * 考试名称 - */ - private String title; - - /** - * 考试描述 - */ - private String content; - - /** - * 1公开2部门3定员 - */ - @TableField("open_type") - private Integer openType; - - /** - * 考试状态 - */ - private Integer state; - - /** - * 是否限时 - */ - @TableField("time_limit") - private Boolean timeLimit; - - /** - * 开始时间 - */ - @TableField("start_time") - private Date startTime; - - /** - * 结束时间 - */ - @TableField("end_time") - private Date endTime; - - /** - * 创建时间 - */ - @TableField("create_time") - private Date createTime; - - /** - * 更新时间 - */ - @TableField("update_time") - private Date updateTime; - - /** - * 总分数 - */ - @TableField("total_score") - private Integer totalScore; - - /** - * 总时长(分钟) - */ - @TableField("total_time") - private Integer totalTime; - - /** - * 及格分数 - */ - @TableField("qualify_score") - private Integer qualifyScore; - -} + *

+ * 考试实体类,封装考试的基本信息 + *

+ * 此类用于数据库操作,映射考试表的字段。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class Exam extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 + + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID + private String id; // 考试ID,唯一标识符 + + private String title; // 考试名称,描述考试的标题 + + private String content; // 考试描述,详细描述考试的内容 + + @TableField("open_type") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer openType; // 开放类型,表示考试的开放范围(1公开,2部门,3定员) + + private Integer state; // 考试状态,表示考试的当前状态(如:未开始、进行中、已结束) + + @TableField("time_limit") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Boolean timeLimit; // 是否限时,表示考试是否有时间限制 + + @TableField("start_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date startTime; // 开始时间,表示考试的开始时间 + + @TableField("end_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date endTime; // 结束时间,表示考试的结束时间 + + @TableField("create_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date createTime; // 创建时间,表示记录的创建时间 + + @TableField("update_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Date updateTime; // 更新时间,表示记录的最后更新时间 + + @TableField("total_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer totalScore; // 总分数,表示考试的总分 + + @TableField("total_time") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer totalTime; // 总时长(分钟),表示考试的总时长 + + @TableField("qualify_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 + private Integer qualifyScore; // 及格分数,表示考试的及格分数线 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java index 19a4238..b39d71c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamDepart.java @@ -1,42 +1,47 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 + +import java.io.Serializable; // 导入Java的序列化接口,用于确保对象可以被序列化 /** -*

-* 考试部门实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Data -@TableName("el_exam_depart") -public class ExamDepart extends Model { + *

+ * 考试部门实体类,封装考试部门的基本信息 + *

+ * 此类用于数据库操作,映射考试部门表的字段。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam_depart") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class ExamDepart extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 - private static final long serialVersionUID = 1L; - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) + * ID + * 唯一标识符,用于标识考试部门记录。 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID private String id; /** - * 考试ID - */ - @TableField("exam_id") + * 考试ID + * 关联的考试ID,标识这个部门所属的考试。 + */ + @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String examId; /** - * 部门ID - */ - @TableField("depart_id") + * 部门ID + * 关联的部门ID,标识参与考试的部门。 + */ + @TableField("depart_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String departId; - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java index 3884051..5249056 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/entity/ExamRepo.java @@ -1,78 +1,87 @@ -package com.yf.exam.modules.exam.entity; +package com.yf.exam.modules.exam.entity; // 定义包名,实体类所在的包路径 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入MyBatis Plus的ID类型注解 +import com.baomidou.mybatisplus.annotation.TableField; // 导入MyBatis Plus的表字段注解 +import com.baomidou.mybatisplus.annotation.TableId; // 导入MyBatis Plus的表ID注解 +import com.baomidou.mybatisplus.annotation.TableName; // 导入MyBatis Plus的表名注解 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入MyBatis Plus的模型类 +import lombok.Data; // 导入Lombok注解,用于简化数据类的编写 /** -*

-* 考试题库实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Data -@TableName("el_exam_repo") -public class ExamRepo extends Model { + *

+ * 考试题库实体类,封装考试题库的基本信息 + *

+ * 此类用于数据库操作,映射考试题库表的字段。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Data // Lombok注解,标记这个类为数据类,自动生成getter和setter方法 +@TableName("el_exam_repo") // MyBatis Plus注解,指定这个实体类对应的数据库表名 +public class ExamRepo extends Model { // 声明类,继承自MyBatis Plus的Model类,用于数据库操作 + + private static final long serialVersionUID = 1L; // 序列化ID,用于版本控制,确保类的唯一性 - private static final long serialVersionUID = 1L; - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) + * ID + * 唯一标识符,用于标识考试题库记录。 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定这个字段为表的主键,类型为自增ID private String id; /** - * 考试ID - */ - @TableField("exam_id") + * 考试ID + * 关联的考试ID,标识这个题库所属的考试。 + */ + @TableField("exam_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String examId; /** - * 题库ID - */ - @TableField("repo_id") + * 题库ID + * 关联的题库ID,标识具体的题库。 + */ + @TableField("repo_id") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private String repoId; /** - * 单选题数量 - */ - @TableField("radio_count") + * 单选题数量 + * 题库中包含的单选题数量。 + */ + @TableField("radio_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer radioCount; /** - * 单选题分数 - */ - @TableField("radio_score") + * 单选题分数 + * 单选题的总分。 + */ + @TableField("radio_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer radioScore; /** - * 多选题数量 - */ - @TableField("multi_count") + * 多选题数量 + * 题库中包含的多选题数量。 + */ + @TableField("multi_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer multiCount; /** - * 多选题分数 - */ - @TableField("multi_score") + * 多选题分数 + * 多选题的总分。 + */ + @TableField("multi_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer multiScore; /** - * 判断题数量 - */ - @TableField("judge_count") + * 判断题数量 + * 题库中包含的判断题数量。 + */ + @TableField("judge_count") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer judgeCount; /** - * 判断题分数 - */ - @TableField("judge_score") + * 判断题分数 + * 判断题的总分。 + */ + @TableField("judge_score") // MyBatis Plus注解,指定这个字段在数据库表中的列名 private Integer judgeScore; - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java index 0c1f39a..60c30d2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamDepartMapper.java @@ -1,15 +1,17 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.exam.entity.ExamDepart; -/** -*

-* 考试部门Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -public interface ExamDepartMapper extends BaseMapper { +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 -} +/** + *

+ * 考试部门Mapper,提供考试部门的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试部门表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +public interface ExamDepartMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamDepart + // 继承BaseMapper,提供基本的CRUD操作(创建、读取、更新、删除) +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java index 1ce4504..f4908e8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamMapper.java @@ -1,45 +1,52 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷分页响应DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试分页响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 /** -*

-* 考试Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -public interface ExamMapper extends BaseMapper { + *

+ * 考试Mapper,提供考试的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +public interface ExamMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为Exam /** * 查找分页内容 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询考试数据的分页结果。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含考试DTO的分页结果 */ IPage paging(Page page, @Param("query") ExamDTO query); /** * 查找分页内容 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询阅卷数据的分页结果。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含阅卷分页响应DTO的分页结果 */ IPage reviewPaging(Page page, @Param("query") ExamDTO query); /** * 在线考试分页响应类-考生视角 - * @param page - * @param query - * @return + * 方法用于根据给定的分页对象和查询条件,查询在线考试数据的分页结果,从考生视角。 + * + * @param page 分页对象,包含分页信息,如当前页码和每页大小 + * @param query 查询条件,封装了考试查询的相关信息 + * @return IPage 返回包含在线考试分页响应DTO的分页结果 */ IPage online(Page page, @Param("query") ExamDTO query); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java index 83407df..69900d2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/mapper/ExamRepoMapper.java @@ -1,26 +1,29 @@ -package com.yf.exam.modules.exam.mapper; +package com.yf.exam.modules.exam.mapper; // 定义包名,Mapper接口所在的包路径 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入MyBatis Plus的基础Mapper接口 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 +import org.apache.ibatis.annotations.Param; // 导入MyBatis的参数注解 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -public interface ExamRepoMapper extends BaseMapper { + *

+ * 考试题库Mapper,提供考试题库的数据库操作接口 + *

+ * 此类是一个Mapper接口,继承自MyBatis Plus的BaseMapper,用于定义针对考试题库表的数据库操作。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +public interface ExamRepoMapper extends BaseMapper { // 声明接口,继承自BaseMapper并指定操作的实体类为ExamRepo /** * 查找考试题库列表 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询关联的考试题库列表,返回扩展的DTO对象。 + * + * @param examId 考试ID,用于指定查询哪个考试的题库列表 + * @return List 返回包含考试题库扩展信息的列表 */ - List listByExam(@Param("examId") String examId); -} + List listByExam(@Param("examId") String examId); // 使用MyBatis的@Param注解来指定方法参数的名称 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java index 301c010..068a6dc 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamDepartService.java @@ -1,32 +1,36 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.exam.entity.ExamDepart; +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试部门业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -public interface ExamDepartService extends IService { + *

+ * 考试部门业务类,提供考试部门的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试部门相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +public interface ExamDepartService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamDepart /** - * 保存全部 - * @param examId - * @param departs + * 保存全部部门信息 + * 方法用于根据给定的考试ID和部门ID列表,保存考试与部门的关联关系。 + * + * @param examId 考试ID,标识要关联的考试 + * @param departs 部门ID列表,包含要关联的部门ID */ void saveAll(String examId, List departs); - /** * 根据考试查找对应的部门 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询与之关联的部门ID列表。 + * + * @param examId 考试ID,用于指定查询哪个考试的部门 + * @return List 返回部门ID列表,包含所有与考试关联的部门ID */ List listByExam(String examId); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java index 78b4ec1..5758185 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamRepoService.java @@ -1,40 +1,45 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 -import java.util.List; +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -public interface ExamRepoService extends IService { - + *

+ * 考试题库业务类,提供考试题库的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试题库相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +public interface ExamRepoService extends IService { // 声明接口,继承自IService并指定操作的实体类为ExamRepo /** - * 保存全部 - * @param examId - * @param list + * 保存全部题库信息 + * 方法用于根据给定的考试ID和题库列表,保存考试与题库的关联关系。 + * + * @param examId 考试ID,标识要关联的考试 + * @param list 题库列表,包含要关联的题库信息 */ void saveAll(String examId, List list); /** * 查找考试题库列表 - * @param examId - * @return + * 方法用于根据给定的考试ID,查询与之关联的题库列表。 + * + * @param examId 考试ID,用于指定查询哪个考试的题库 + * @return List 返回题库列表,包含所有与考试关联的题库信息 */ List listByExam(String examId); /** * 清理脏数据 - * @param examId + * 方法用于清除与指定考试ID关联的题库数据,用于数据清理或重置场景。 + * + * @param examId 考试ID,用于指定要清理的考试关联的题库数据 */ void clear(String examId); - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java index 3f75664..47d77b8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/ExamService.java @@ -1,64 +1,75 @@ -package com.yf.exam.modules.exam.service; +package com.yf.exam.modules.exam.service; // 定义包名,服务接口所在的包路径 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.extension.service.IService; // 导入MyBatis Plus的服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 /** -*

-* 考试业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -public interface ExamService extends IService { + *

+ * 考试业务类,提供考试的业务逻辑 + *

+ * 此类是一个服务接口,继承自MyBatis Plus的IService,用于定义考试相关的业务操作。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +public interface ExamService extends IService { // 声明接口,继承自IService并指定操作的实体类为Exam /** * 保存考试信息 - * @param reqDTO + * 方法用于保存考试信息,包括考试的基本信息和相关联的题库、部门等。 + * + * @param reqDTO 考试保存请求数据传输对象,包含考试的详细信息 */ void save(ExamSaveReqDTO reqDTO); /** * 查找考试详情 - * @param id - * @return + * 方法用于根据考试ID查询考试的详细信息,包括考试的基本数据和相关联的部门、题库等。 + * + * @param id 考试ID,用于指定要查询的考试 + * @return ExamSaveReqDTO 返回考试详情,包含考试的详细信息 */ ExamSaveReqDTO findDetail(String id); /** * 查找考试详情--简要信息 - * @param id - * @return + * 方法用于根据考试ID查询考试的简要信息,通常用于列表展示。 + * + * @param id 考试ID,用于指定要查询的考试 + * @return ExamDTO 返回考试简要信息,包含考试的基本数据 */ ExamDTO findById(String id); /** - * 分页查询数据 - * @param reqDTO - * @return - */ + * 分页查询数据 + * 方法用于分页查询考试数据,通常用于列表展示。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页考试数据,包含考试列表和分页信息 + */ IPage paging(PagingReqDTO reqDTO); - /** * 在线考试分页响应类-考生视角 - * @param reqDTO - * @return + * 方法用于分页查询在线考试数据,从考生视角,通常用于考生查看可参加的考试列表。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页在线考试数据,包含在线考试列表和分页信息 */ IPage onlinePaging(PagingReqDTO reqDTO); - /** * 待阅试卷列表 - * @param reqDTO - * @return + * 方法用于分页查询待阅试卷数据,通常用于阅卷老师查看需要批改的试卷列表。 + * + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return IPage 返回分页待阅试卷数据,包含待阅试卷列表和分页信息 */ IPage reviewPaging(PagingReqDTO reqDTO); -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java index 37ca2ff..3460e7c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamDepartServiceImpl.java @@ -1,66 +1,64 @@ -package com.yf.exam.modules.exam.service.impl; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.modules.exam.entity.ExamDepart; -import com.yf.exam.modules.exam.mapper.ExamDepartMapper; -import com.yf.exam.modules.exam.service.ExamDepartService; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.modules.exam.entity.ExamDepart; // 导入考试部门实体类 +import com.yf.exam.modules.exam.mapper.ExamDepartMapper; // 导入考试部门Mapper接口 +import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 +import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 -import java.util.ArrayList; -import java.util.List; +import java.util.ArrayList; // 导入Java的ArrayList类 +import java.util.List; // 导入Java的List接口 /** -*

-* 考试部门业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-03 17:24 -*/ -@Service -public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { + *

+ * 考试部门业务实现类,提供考试部门的具体业务逻辑实现 + *

+ * 此类实现了ExamDepartService接口,用于处理考试部门相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-09-03 17:24 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamDepartServiceImpl extends ServiceImpl implements ExamDepartService { // 声明类,继承自ServiceImpl并实现ExamDepartService接口 @Override public void saveAll(String examId, List departs) { - - // 先删除 + // 先删除已有的部门 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 + this.remove(wrapper); // 根据条件删除部门 - // 再增加 - if(CollectionUtils.isEmpty(departs)){ - throw new ServiceException(1, "请至少选择选择一个部门!!"); + // 再增加新的部门 + if (CollectionUtils.isEmpty(departs)) { // 检查部门列表是否为空 + throw new ServiceException(1, "请至少选择选择一个部门!!"); // 如果为空,抛出异常 } - List list = new ArrayList<>(); + List list = new ArrayList<>(); // 创建考试部门列表 - for(String id: departs){ - ExamDepart depart = new ExamDepart(); - depart.setDepartId(id); - depart.setExamId(examId); - list.add(depart); + for (String id : departs) { + ExamDepart depart = new ExamDepart(); // 创建考试部门对象 + depart.setDepartId(id); // 设置部门ID + depart.setExamId(examId); // 设置考试ID + list.add(depart); // 添加到列表 } - this.saveBatch(list); + this.saveBatch(list); // 批量保存部门 } @Override public List listByExam(String examId) { - // 先删除 + // 查找考试对应的部门 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamDepart::getExamId, examId); - List list = this.list(wrapper); - List ids = new ArrayList<>(); - if(!CollectionUtils.isEmpty(list)){ - for(ExamDepart item: list){ - ids.add(item.getDepartId()); + wrapper.lambda().eq(ExamDepart::getExamId, examId); // 构造查询条件,查询指定考试ID的部门 + List list = this.list(wrapper); // 根据条件查询部门列表 + List ids = new ArrayList<>(); // 创建部门ID列表 + if (!CollectionUtils.isEmpty(list)) { // 检查部门列表是否为空 + for (ExamDepart item : list) { + ids.add(item.getDepartId()); // 添加部门ID到列表 } } - - return ids; - + return ids; // 返回部门ID列表 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java index ea630e6..e161f56 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamRepoServiceImpl.java @@ -1,67 +1,63 @@ -package com.yf.exam.modules.exam.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.entity.ExamRepo; -import com.yf.exam.modules.exam.mapper.ExamRepoMapper; -import com.yf.exam.modules.exam.service.ExamRepoService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.util.List; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入MyBatis Plus的查询包装类 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.entity.ExamRepo; // 导入考试题库实体类 +import com.yf.exam.modules.exam.mapper.ExamRepoMapper; // 导入考试题库Mapper接口 +import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 +import org.springframework.transaction.annotation.Transactional; // 导入Spring的事务注解 +import org.springframework.util.CollectionUtils; // 导入Spring的集合工具类 + +import java.util.List; // 导入Java的List接口 /** -*

-* 考试题库业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-05 11:14 -*/ -@Service -public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { - - - @Transactional(rollbackFor = Exception.class) + *

+ * 考试题库业务实现类,提供考试题库的具体业务逻辑实现 + *

+ * 此类实现了ExamRepoService接口,用于处理考试题库相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-09-05 11:14 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamRepoServiceImpl extends ServiceImpl implements ExamRepoService { // 声明类,继承自ServiceImpl并实现ExamRepoService接口 + + @Transactional(rollbackFor = Exception.class) // Spring事务注解,声明事务边界和回滚条件 @Override public void saveAll(String examId, List list) { - - // 先删除 + // 先删除已有的题库 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 + this.remove(wrapper); // 根据条件删除题库 - // 再增加 - if(CollectionUtils.isEmpty(list)){ - throw new ServiceException(1, "必须选择题库!"); + // 再增加新的题库 + if (CollectionUtils.isEmpty(list)) { // 检查题库列表是否为空 + throw new ServiceException(1, "必须选择题库!"); // 如果为空,抛出异常 } - List repos = BeanMapper.mapList(list, ExamRepo.class); - for(ExamRepo item: repos){ - item.setExamId(examId); - item.setId(IdWorker.getIdStr()); + List repos = BeanMapper.mapList(list, ExamRepo.class); // 使用BeanMapper将DTO列表转换为实体类列表 + for (ExamRepo item : repos) { + item.setExamId(examId); // 设置考试ID + item.setId(IdWorker.getIdStr()); // 使用IdWorker生成ID } - this.saveBatch(repos); + this.saveBatch(repos); // 批量保存题库 } @Override public List listByExam(String examId) { - return baseMapper.listByExam(examId); + return baseMapper.listByExam(examId); // 调用Mapper接口的方法,查找考试题库列表 } @Override public void clear(String examId) { - - // 先删除 + // 先删除已有的题库 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(ExamRepo::getExamId, examId); - this.remove(wrapper); + wrapper.lambda().eq(ExamRepo::getExamId, examId); // 构造查询条件,查询指定考试ID的题库 + this.remove(wrapper); // 根据条件删除题库 } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java index 7451bd9..50ae151 100644 --- a/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/exam/service/impl/ExamServiceImpl.java @@ -1,194 +1,173 @@ -package com.yf.exam.modules.exam.service.impl; - -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.enums.OpenType; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.exam.dto.ExamDTO; -import com.yf.exam.modules.exam.dto.ExamRepoDTO; -import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; -import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; -import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; -import com.yf.exam.modules.exam.entity.Exam; -import com.yf.exam.modules.exam.mapper.ExamMapper; -import com.yf.exam.modules.exam.service.ExamDepartService; -import com.yf.exam.modules.exam.service.ExamRepoService; -import com.yf.exam.modules.exam.service.ExamService; -import org.apache.commons.lang3.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.stereotype.Service; - -import java.util.List; +package com.yf.exam.modules.exam.service.impl; // 定义包名,服务实现类所在的包路径 + +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入MyBatis Plus的分页结果接口 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入MyBatis Plus的ID生成工具类 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis Plus的分页对象 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入MyBatis Plus的服务实现类 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求DTO +import com.yf.exam.core.enums.OpenType; // 导入开放类型枚举 +import com.yf.exam.core.exception.ServiceException; // 导入自定义的服务异常类 +import com.yf.exam.core.utils.BeanMapper; // 导入自定义的Bean映射工具类 +import com.yf.exam.modules.exam.dto.ExamDTO; // 导入考试DTO +import com.yf.exam.modules.exam.dto.ExamRepoDTO; // 导入考试题库DTO +import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; // 导入考试题库扩展DTO +import com.yf.exam.modules.exam.dto.request.ExamSaveReqDTO; // 导入考试保存请求DTO +import com.yf.exam.modules.exam.dto.response.ExamOnlineRespDTO; // 导入在线考试响应DTO +import com.yf.exam.modules.exam.dto.response.ExamReviewRespDTO; // 导入阅卷响应DTO +import com.yf.exam.modules.exam.entity.Exam; // 导入考试实体类 +import com.yf.exam.modules.exam.mapper.ExamMapper; // 导入考试Mapper接口 +import com.yf.exam.modules.exam.service.ExamDepartService; // 导入考试部门服务接口 +import com.yf.exam.modules.exam.service.ExamRepoService; // 导入考试题库服务接口 +import com.yf.exam.modules.exam.service.ExamService; // 导入考试服务接口 +import org.apache.commons.lang3.StringUtils; // 导入Apache Commons Lang的字符串工具类 +import org.springframework.beans.factory.annotation.Autowired; // 导入Spring的自动注入注解 +import org.springframework.dao.DuplicateKeyException; // 导入Spring的重复键异常类 +import org.springframework.stereotype.Service; // 导入Spring的服务注解 + +import java.util.List; // 导入Java的List接口 /** -*

-* 考试业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-07-25 16:18 -*/ -@Service -public class ExamServiceImpl extends ServiceImpl implements ExamService { - + *

+ * 考试业务实现类 + *

+ * 此类实现了ExamService接口,用于处理考试相关的业务逻辑。 + * + * @author 聪明笨狗 + * @since 2020-07-25 16:18 + */ +@Service // Spring注解,声明这是一个服务组件 +public class ExamServiceImpl extends ServiceImpl implements ExamService { // 声明类,继承自ServiceImpl并实现ExamService接口 @Autowired - private ExamRepoService examRepoService; + private ExamRepoService examRepoService; // 自动注入考试题库服务 @Autowired - private ExamDepartService examDepartService; + private ExamDepartService examDepartService; // 自动注入考试部门服务 @Override public void save(ExamSaveReqDTO reqDTO) { - // ID String id = reqDTO.getId(); - if(StringUtils.isBlank(id)){ - id = IdWorker.getIdStr(); + if(StringUtils.isBlank(id)){ // 如果ID为空,则生成新的ID + id = IdWorker.getIdStr(); // 使用IdWorker生成ID } - //复制参数 - Exam entity = new Exam(); + // 复制参数 + Exam entity = new Exam(); // 创建考试实体 // 计算分值 - this.calcScore(reqDTO); - + this.calcScore(reqDTO); // 调用方法计算分值 // 复制基本数据 - BeanMapper.copy(reqDTO, entity); - entity.setId(id); + BeanMapper.copy(reqDTO, entity); // 使用BeanMapper复制属性 + entity.setId(id); // 设置ID // 修复状态 - if (reqDTO.getTimeLimit()!=null + if (reqDTO.getTimeLimit() != null && !reqDTO.getTimeLimit() - && reqDTO.getState()!=null + && reqDTO.getState() != null && reqDTO.getState() == 2) { - entity.setState(0); + entity.setState(0); // 如果不限时且状态为2,则状态设置为0 } else { - entity.setState(reqDTO.getState()); + entity.setState(reqDTO.getState()); // 否则直接设置状态 } // 题库组卷 try { - examRepoService.saveAll(id, reqDTO.getRepoList()); + examRepoService.saveAll(id, reqDTO.getRepoList()); // 调用考试题库服务保存题库 }catch (DuplicateKeyException e){ - throw new ServiceException(1, "不能选择重复的题库!"); + throw new ServiceException(1, "不能选择重复的题库!"); // 如果出现重复键异常,则抛出服务异常 } - // 开放的部门 - if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ - examDepartService.saveAll(id, reqDTO.getDepartIds()); + if(OpenType.DEPT_OPEN.equals(reqDTO.getOpenType())){ // 如果开放类型为部门开放 + examDepartService.saveAll(id, reqDTO.getDepartIds()); // 调用考试部门服务保存部门 } - this.saveOrUpdate(entity); - + this.saveOrUpdate(entity); // 保存或更新考试实体 } @Override public ExamSaveReqDTO findDetail(String id) { - ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); - Exam exam = this.getById(id); - BeanMapper.copy(exam, respDTO); + ExamSaveReqDTO respDTO = new ExamSaveReqDTO(); // 创建响应DTO + Exam exam = this.getById(id); // 根据ID查询考试实体 + BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 // 考试部门 - List departIds = examDepartService.listByExam(id); - respDTO.setDepartIds(departIds); + List departIds = examDepartService.listByExam(id); // 调用考试部门服务查询部门ID列表 + respDTO.setDepartIds(departIds); // 设置部门ID列表 // 题库 - List repos = examRepoService.listByExam(id); - respDTO.setRepoList(repos); + List repos = examRepoService.listByExam(id); // 调用考试题库服务查询题库列表 + respDTO.setRepoList(repos); // 设置题库列表 - return respDTO; + return respDTO; // 返回响应DTO } @Override public ExamDTO findById(String id) { - ExamDTO respDTO = new ExamDTO(); - Exam exam = this.getById(id); - BeanMapper.copy(exam, respDTO); - return respDTO; + ExamDTO respDTO = new ExamDTO(); // 创建响应DTO + Exam exam = this.getById(id); // 根据ID查询考试实体 + BeanMapper.copy(exam, respDTO); // 使用BeanMapper复制属性 + return respDTO; // 返回响应DTO } @Override public IPage paging(PagingReqDTO reqDTO) { + // 创建分页对象 + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 - //创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); - - //转换结果 - IPage pageData = baseMapper.paging(page, reqDTO.getParams()); - return pageData; - } + // 转换结果 + IPage pageData = baseMapper.paging(page, reqDTO.getParams()); // 调用Mapper接口的分页方法 + return pageData; // 返回分页结果 + } @Override public IPage onlinePaging(PagingReqDTO reqDTO) { - - // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 // 查找分页 - IPage pageData = baseMapper.online(page, reqDTO.getParams()); - - return pageData; + IPage pageData = baseMapper.online(page, reqDTO.getParams()); // 调用Mapper接口的在线考试分页方法 + return pageData; // 返回分页结果 } @Override public IPage reviewPaging(PagingReqDTO reqDTO) { // 创建分页对象 - Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); + Page page = new Page(reqDTO.getCurrent(), reqDTO.getSize()); // 使用分页请求DTO创建分页对象 // 查找分页 - IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); - - return pageData; + IPage pageData = baseMapper.reviewPaging(page, reqDTO.getParams()); // 调用Mapper接口的阅卷分页方法 + return pageData; // 返回分页结果 } - /** * 计算分值 - * @param reqDTO + * 方法用于计算考试的总分值,根据题库中的题目数量和分数。 + * + * @param reqDTO 考试保存请求DTO */ - private void calcScore(ExamSaveReqDTO reqDTO){ - + private void calcScore(ExamSaveReqDTO reqDTO) { // 主观题分数 int objScore = 0; // 题库组卷 - List repoList = reqDTO.getRepoList(); - - for(ExamRepoDTO item: repoList){ - if(item.getRadioCount()!=null - && item.getRadioCount()>0 - && item.getRadioScore()!=null - && item.getRadioScore()>0){ - objScore+=item.getRadioCount()*item.getRadioScore(); + List repoList = reqDTO.getRepoList(); // 获取题库列表 + + for(ExamRepoDTO item : repoList){ // 遍历题库列表 + if(item.getRadioCount() != null && item.getRadioCount() > 0 && item.getRadioScore() != null && item.getRadioScore() > 0){ + objScore += item.getRadioCount() * item.getRadioScore(); // 计算单选题分数 } - if(item.getMultiCount()!=null - && item.getMultiCount()>0 - && item.getMultiScore()!=null - && item.getMultiScore()>0){ - objScore+=item.getMultiCount()*item.getMultiScore(); + if(item.getMultiCount() != null && item.getMultiCount() > 0 && item.getMultiScore() != null && item.getMultiScore() > 0){ + objScore += item.getMultiCount() * item.getMultiScore(); // 计算多选题分数 } - if(item.getJudgeCount()!=null - && item.getJudgeCount()>0 - && item.getJudgeScore()!=null - && item.getJudgeScore()>0){ - objScore+=item.getJudgeCount()*item.getJudgeScore(); + if(item.getJudgeCount() != null && item.getJudgeCount() > 0 && item.getJudgeScore() != null && item.getJudgeScore() > 0){ + objScore += item.getJudgeCount() * item.getJudgeScore(); // 计算判断题分数 } } - - - reqDTO.setTotalScore(objScore); + reqDTO.setTotalScore(objScore); // 设置总分值 } - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java b/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java index a3ad8ed..5549670 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/controller/PaperController.java @@ -1,19 +1,13 @@ -package com.yf.exam.modules.paper.controller; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.controller; -// 引入分页查询结果的接口 import com.baomidou.mybatisplus.core.metadata.IPage; -// 引入统一的API响应封装类 import com.yf.exam.core.api.ApiRest; -// 引入基础控制器类,提供通用的API响应方法 import com.yf.exam.core.api.controller.BaseController; -// 引入各种DTO类,用于请求和响应数据传输 import com.yf.exam.core.api.dto.BaseIdReqDTO; import com.yf.exam.core.api.dto.BaseIdRespDTO; import com.yf.exam.core.api.dto.BaseIdsReqDTO; import com.yf.exam.core.api.dto.PagingReqDTO; -// 引入工具类,用于对象之间的属性拷贝 import com.yf.exam.core.utils.BeanMapper; -// 引入试卷相关的DTO类 import com.yf.exam.modules.paper.dto.PaperDTO; import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; @@ -23,22 +17,14 @@ import com.yf.exam.modules.paper.dto.request.PaperQuQueryDTO; import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; -// 引入试卷实体类 import com.yf.exam.modules.paper.entity.Paper; -// 引入试卷相关的业务处理服务类 import com.yf.exam.modules.paper.service.PaperService; -// 引入用户工具类,获取当前登录用户信息 import com.yf.exam.modules.user.UserUtils; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; -// 引入Shiro注解,用于角色权限管理 import org.apache.shiro.authz.annotation.RequiresRoles; -// 引入Spring的Bean工具类,用于属性复制 import org.springframework.beans.BeanUtils; -// 引入Spring的自动注入注解,用于自动注入服务 import org.springframework.beans.factory.annotation.Autowired; -// 引入Spring的Web注解,定义HTTP请求的映射方式 import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -48,126 +34,123 @@ import org.springframework.web.bind.annotation.RestController; *

* 试卷控制器 *

-* 提供有关试卷的操作,如分页查询、创建试卷、查看试卷详情等 +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Api(tags={"试卷"}) // Swagger API 文档注解,用于描述该接口属于试卷相关操作 -@RestController // 标记为Spring的控制器,处理HTTP请求 -@RequestMapping("/exam/api/paper/paper") // 定义请求路径的基础路径 -public class PaperController extends BaseController { // 继承BaseController类,提供基本的API返回 +@Api(tags={"试卷"}) +@RestController +@RequestMapping("/exam/api/paper/paper") +public class PaperController extends BaseController { - @Autowired // 自动注入PaperService,负责业务逻辑处理 + @Autowired private PaperService baseService; /** - * 分页查找试卷列表 - * @param reqDTO 包含分页信息和查询条件的请求数据 - * @return 分页后的试卷列表 + * 分页查找 + * @param reqDTO + * @return */ - @ApiOperation(value = "分页查找") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - // 调用业务层进行分页查询 + //分页查询并转换 IPage page = baseService.paging(reqDTO); - // 返回成功响应,并附带查询结果 return super.success(page); } + + /** * 创建试卷 - * @param reqDTO 创建试卷所需的请求数据 - * @return 返回创建成功后的试卷ID + * @param reqDTO + * @return */ - @ApiOperation(value = "创建试卷") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/create-paper", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "创建试卷") + @RequestMapping(value = "/create-paper", method = { RequestMethod.POST}) public ApiRest save(@RequestBody PaperCreateReqDTO reqDTO) { - // 调用业务层创建试卷,传入当前用户ID和考试ID + //复制参数 String paperId = baseService.createPaper(UserUtils.getUserId(), reqDTO.getExamId()); - // 返回创建结果,包括试卷ID return super.success(new BaseIdRespDTO(paperId)); } /** - * 获取试卷详情 - * @param reqDTO 请求参数,包含试卷ID - * @return 返回试卷的详细信息 + * 批量删除 + * @param reqDTO + * @return */ - @ApiOperation(value = "试卷详情") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/paper-detail", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "试卷详情") + @RequestMapping(value = "/paper-detail", method = { RequestMethod.POST}) public ApiRest paperDetail(@RequestBody BaseIdReqDTO reqDTO) { - // 调用业务层获取试卷详情 + //根据ID删除 ExamDetailRespDTO respDTO = baseService.paperDetail(reqDTO.getId()); - // 返回成功响应,并附带试卷详情 return super.success(respDTO); } /** - * 获取试题详情 - * @param reqDTO 请求参数,包含试卷ID和试题ID - * @return 返回试题的详细信息 + * 批量删除 + * @param reqDTO + * @return */ - @ApiOperation(value = "试题详情") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/qu-detail", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "试题详情") + @RequestMapping(value = "/qu-detail", method = { RequestMethod.POST}) public ApiRest quDetail(@RequestBody PaperQuQueryDTO reqDTO) { - // 调用业务层获取试题详情 + //根据ID删除 PaperQuDetailDTO respDTO = baseService.findQuDetail(reqDTO.getPaperId(), reqDTO.getQuId()); - // 返回成功响应,并附带试题详情 return super.success(respDTO); } /** * 填充答案 - * @param reqDTO 请求数据,包含填充的答案 - * @return 返回操作成功的响应 + * @param reqDTO + * @return */ - @ApiOperation(value = "填充答案") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/fill-answer", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "填充答案") + @RequestMapping(value = "/fill-answer", method = { RequestMethod.POST}) public ApiRest fillAnswer(@RequestBody PaperAnswerDTO reqDTO) { - // 调用业务层填充答案操作 + //根据ID删除 baseService.fillAnswer(reqDTO); - // 返回成功响应 return super.success(); } + /** * 交卷操作 - * @param reqDTO 请求数据,包含试卷ID - * @return 返回交卷操作成功的响应 + * @param reqDTO + * @return */ - @ApiOperation(value = "交卷操作") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/hand-exam", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "交卷操作") + @RequestMapping(value = "/hand-exam", method = { RequestMethod.POST}) public ApiRest handleExam(@RequestBody BaseIdReqDTO reqDTO) { - // 调用业务层进行交卷操作 + //根据ID删除 baseService.handExam(reqDTO.getId()); - // 返回成功响应 return super.success(); } + /** - * 获取试卷结果 - * @param reqDTO 请求数据,包含试卷ID - * @return 返回试卷的考试结果 + * 批量删除 + * @param reqDTO + * @return */ - @ApiOperation(value = "试卷结果") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/paper-result", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "试卷详情") + @RequestMapping(value = "/paper-result", method = { RequestMethod.POST}) public ApiRest paperResult(@RequestBody BaseIdReqDTO reqDTO) { - // 调用业务层获取试卷的考试结果 + //根据ID删除 ExamResultRespDTO respDTO = baseService.paperResult(reqDTO.getId()); - // 返回成功响应,并附带试卷结果 return super.success(respDTO); } + /** * 检测用户有没有中断的考试 - * @return 返回用户未完成的考试信息 + * @return */ - @ApiOperation(value = "检测进行中的考试") // Swagger操作注解,用于描述接口 - @RequestMapping(value = "/check-process", method = { RequestMethod.POST}) // 定义POST请求路径 + @ApiOperation(value = "检测进行中的考试") + @RequestMapping(value = "/check-process", method = { RequestMethod.POST}) public ApiRest checkProcess() { - // 调用业务层检测用户是否有未完成的考试 + //复制参数 PaperDTO dto = baseService.checkProcess(UserUtils.getUserId()); - // 返回成功响应,并附带考试进程数据 return super.success(dto); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java index 8b59dcb..dcfb9ef 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperDTO.java @@ -1,83 +1,79 @@ -package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto; -// 引入Dict注解,用于字典表的映射 import com.yf.exam.core.annon.Dict; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Serializable接口,用于对象序列化 + import java.io.Serializable; -// 引入Date类,用于表示日期和时间 import java.util.Date; /** - *

- * 试卷请求类 - *

- * 该类用于传输试卷的基本信息,包含试卷的ID、考试规则、标题、时长、得分等字段。 - * 提供了试卷的详细信息,通常在查询和展示试卷时使用。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷", description="试卷") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 +*

+* 试卷请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷", description="试卷") +public class PaperDTO implements Serializable { + + private static final long serialVersionUID = 1L; - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String id; // 试卷ID + @ApiModelProperty(value = "试卷ID", required=true) + private String id; - @Dict(dictTable = "sys_user", dicText = "real_name", dicCode = "id") // 字典表映射,映射用户表的姓名字段 - @ApiModelProperty(value = "用户ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String userId; // 用户ID + @Dict(dictTable = "sys_user", dicText = "real_name", dicCode = "id") + @ApiModelProperty(value = "用户ID", required=true) + private String userId; - @Dict(dictTable = "sys_depart", dicText = "dept_name", dicCode = "id") // 字典表映射,映射部门表的部门名称字段 - @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String departId; // 部门ID + @Dict(dictTable = "sys_depart", dicText = "dept_name", dicCode = "id") + @ApiModelProperty(value = "部门ID", required=true) + private String departId; - @ApiModelProperty(value = "规则ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String examId; // 规则ID,表示该试卷对应的考试规则 + @ApiModelProperty(value = "规则ID", required=true) + private String examId; - @ApiModelProperty(value = "考试标题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String title; // 考试标题,表示试卷的名称 + @ApiModelProperty(value = "考试标题", required=true) + private String title; - @ApiModelProperty(value = "考试时长", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer totalTime; // 考试时长(单位:分钟) + @ApiModelProperty(value = "考试时长", required=true) + private Integer totalTime; - @ApiModelProperty(value = "用户时长", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer userTime; // 用户已使用的时间(单位:分钟) + @ApiModelProperty(value = "用户时长", required=true) + private Integer userTime; - @ApiModelProperty(value = "试卷总分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer totalScore; // 试卷总分 + @ApiModelProperty(value = "试卷总分", required=true) + private Integer totalScore; - @ApiModelProperty(value = "及格分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer qualifyScore; // 及格分数 + @ApiModelProperty(value = "及格分", required=true) + private Integer qualifyScore; - @ApiModelProperty(value = "客观分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer objScore; // 客观题分数 + @ApiModelProperty(value = "客观分", required=true) + private Integer objScore; - @ApiModelProperty(value = "主观分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer subjScore; // 主观题分数 + @ApiModelProperty(value = "主观分", required=true) + private Integer subjScore; - @ApiModelProperty(value = "用户得分", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer userScore; // 用户得分 + @ApiModelProperty(value = "用户得分", required=true) + private Integer userScore; - @ApiModelProperty(value = "是否包含简答题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Boolean hasSaq; // 是否包含简答题,布尔类型,表示该试卷是否有简答题 + @ApiModelProperty(value = "是否包含简答题", required=true) + private Boolean hasSaq; - @ApiModelProperty(value = "试卷状态", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer state; // 试卷状态,表示试卷的当前状态,如未开始、进行中、已结束等 + @ApiModelProperty(value = "试卷状态", required=true) + private Integer state; - @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Date createTime; // 创建时间,表示试卷的创建时间 + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; - @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Date updateTime; // 更新时间,表示试卷的最后更新时间 + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; - @ApiModelProperty(value = "截止时间") // Swagger注解,描述该字段在API文档中的含义 - private Date limitTime; // 截止时间,表示考试的最后提交时间 + @ApiModelProperty(value = "截止时间") + private Date limitTime; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java index 48672a7..e449e79 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuAnswerDTO.java @@ -1,50 +1,48 @@ -package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Serializable接口,用于对象序列化 + import java.io.Serializable; /** - *

- * 试卷考题备选答案请求类 - *

- * 该类用于表示试卷考题的备选答案,包含每个备选答案的ID、题目ID、选项标签、是否选中等信息。 - * 适用于考题答案的请求传输。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperQuAnswerDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 +*

+* 试卷考题备选答案请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") +public class PaperQuAnswerDTO implements Serializable { + + private static final long serialVersionUID = 1L; - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "自增ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String id; // 自增ID,表示备选答案的唯一标识符 + @ApiModelProperty(value = "自增ID", required=true) + private String id; - @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String paperId; // 试卷ID,表示该备选答案所属的试卷 + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; - @ApiModelProperty(value = "回答项ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String answerId; // 回答项ID,表示该备选答案的唯一标识符 + @ApiModelProperty(value = "回答项ID", required=true) + private String answerId; - @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String quId; // 题目ID,表示该备选答案所属的题目 + @ApiModelProperty(value = "题目ID", required=true) + private String quId; - @ApiModelProperty(value = "是否正确项", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Boolean isRight; // 是否正确项,布尔值,表示该备选答案是否是正确答案 + @ApiModelProperty(value = "是否正确项", required=true) + private Boolean isRight; - @ApiModelProperty(value = "是否选中", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Boolean checked; // 是否选中,布尔值,表示该备选答案是否已被选中 + @ApiModelProperty(value = "是否选中", required=true) + private Boolean checked; - @ApiModelProperty(value = "排序", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer sort; // 排序,表示该备选答案在题目中的排序位置 + @ApiModelProperty(value = "排序", required=true) + private Integer sort; - @ApiModelProperty(value = "选项标签", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String abc; // 选项标签,通常为 A、B、C、D 等,表示该备选答案的标识符 + @ApiModelProperty(value = "选项标签", required=true) + private String abc; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java index 05bf6d7..349868e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/PaperQuDTO.java @@ -1,55 +1,54 @@ -package com.yf.exam.modules.paper.dto; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Serializable接口,用于对象序列化 + import java.io.Serializable; /** - *

- * 试卷考题请求类 - *

- * 该类用于表示试卷中的每一道题目,包含题目的基本信息,如题目ID、试卷ID、题目类型、是否答对、得分等。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷考题", description="试卷考题") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperQuDTO implements Serializable { // 实现Serializable接口,表示该类的对象可以被序列化 +*

+* 试卷考题请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷考题", description="试卷考题") +public class PaperQuDTO implements Serializable { + + private static final long serialVersionUID = 1L; - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 - @ApiModelProperty(value = "ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String id; // 题目ID,唯一标识符 + @ApiModelProperty(value = "ID", required=true) + private String id; - @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String paperId; // 试卷ID,表示该题目所属的试卷 + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; - @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String quId; // 题目ID,唯一标识该题目 + @ApiModelProperty(value = "题目ID", required=true) + private String quId; - @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer quType; // 题目类型,表示题目的分类,如选择题、判断题、主观题等 + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; - @ApiModelProperty(value = "是否已答", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Boolean answered; // 是否已答,布尔值,表示该题目是否已被回答 + @ApiModelProperty(value = "是否已答", required=true) + private Boolean answered; - @ApiModelProperty(value = "主观答案", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String answer; // 主观答案,表示对该题目的回答内容(适用于主观题) + @ApiModelProperty(value = "主观答案", required=true) + private String answer; - @ApiModelProperty(value = "问题排序", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer sort; // 问题排序,表示该题目在试卷中的顺序 + @ApiModelProperty(value = "问题排序", required=true) + private Integer sort; - @ApiModelProperty(value = "单题分分值", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer score; // 单题分值,表示该题目的满分 + @ApiModelProperty(value = "单题分分值", required=true) + private Integer score; - @ApiModelProperty(value = "实际得分(主观题)", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer actualScore; // 实际得分,表示用户在该题目中实际得到的分数(适用于主观题) + @ApiModelProperty(value = "实际得分(主观题)", required=true) + private Integer actualScore; - @ApiModelProperty(value = "是否答对", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Boolean isRight; // 是否答对,布尔值,表示用户是否答对了该题目 + @ApiModelProperty(value = "是否答对", required=true) + private Boolean isRight; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java index 357808a..3124d9e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuAnswerExtDTO.java @@ -1,30 +1,29 @@ -package com.yf.exam.modules.paper.dto.ext; // 定义该类所在的包路径 +package com.yf.exam.modules.paper.dto.ext; -// 引入试题答案DTO类,作为当前类的父类 import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** *

* 试卷考题备选答案请求类 *

-* 该类用于描述试卷考题的备选答案信息,继承自PaperQuAnswerDTO,扩展了额外的字段,如图片和内容。 +* * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") // Swagger注解,描述模型信息,生成API文档时使用 -public class PaperQuAnswerExtDTO extends PaperQuAnswerDTO { // 继承自PaperQuAnswerDTO类,扩展了额外属性 +@Data +@ApiModel(value="试卷考题备选答案", description="试卷考题备选答案") +public class PaperQuAnswerExtDTO extends PaperQuAnswerDTO { - private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 + private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "试题图片", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String image; // 试题对应的图片内容 + @ApiModelProperty(value = "试题图片", required=true) + private String image; - @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String content; // 备选答案的具体内容 + @ApiModelProperty(value = "答案内容", required=true) + private String content; + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java index e2d693b..ee1e998 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/ext/PaperQuDetailDTO.java @@ -1,35 +1,32 @@ -package com.yf.exam.modules.paper.dto.ext; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.ext; -// 引入试题DTO类,作为当前类的父类 import com.yf.exam.modules.paper.dto.PaperQuDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入List集合,用于存储多个备选答案 + import java.util.List; /** *

* 试卷考题请求类 *

-* 该类用于描述试卷中每个考题的详细信息,继承自PaperQuDTO,扩展了试题的图片、内容和答案列表等字段。 +* * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷题目详情类", description="试卷题目详情类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperQuDetailDTO extends PaperQuDTO { // 继承自PaperQuDTO类,扩展了额外属性 +@Data +@ApiModel(value="试卷题目详情类", description="试卷题目详情类") +public class PaperQuDetailDTO extends PaperQuDTO { - private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 + private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "图片", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String image; // 题目的图片内容 + @ApiModelProperty(value = "图片", required=true) + private String image; - @ApiModelProperty(value = "题目内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String content; // 试题的具体内容 + @ApiModelProperty(value = "题目内容", required=true) + private String content; - @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List answerList; // 存储该题目的备选答案,使用List集合存储多个答案 + @ApiModelProperty(value = "答案内容", required=true) + List answerList; } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java index 25df4c6..ccbe3ce 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperAnswerDTO.java @@ -1,25 +1,22 @@ -package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.request; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入List集合,用于存储多个答案 + import java.util.List; /** * @author bool - * 查找试卷题目详情请求类,用于接收查找试卷题目详情的请求数据。 - * 继承自PaperQuQueryDTO,扩展了回答列表和主观答案字段。 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperAnswerDTO extends PaperQuQueryDTO { // 继承自PaperQuQueryDTO类,扩展了额外属性 +@Data +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") +public class PaperAnswerDTO extends PaperQuQueryDTO { + + @ApiModelProperty(value = "回答列表", required=true) + private List answers; - @ApiModelProperty(value = "回答列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List answers; // 存储多个选择题答案的列表 + @ApiModelProperty(value = "主观答案", required=true) + private String answer; - @ApiModelProperty(value = "主观答案", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String answer; // 存储主观题的答案内容 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java index 22d11e9..6a8f8c5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperCreateReqDTO.java @@ -1,26 +1,22 @@ -package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.request; -// 引入父类BaseDTO,用于继承基础字段和功能 import com.yf.exam.core.api.dto.BaseDTO; -// 引入Jackson注解,用于处理JSON序列化时忽略某些字段 import com.fasterxml.jackson.annotation.JsonIgnore; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** * @author bool - * 试卷创建请求类,用于接收试卷创建的请求数据,包含考试ID和用户ID等字段。 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷创建请求类", description="试卷创建请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperCreateReqDTO extends BaseDTO { // 继承自BaseDTO类,扩展了考试ID和用户ID字段 +@Data +@ApiModel(value="试卷创建请求类", description="试卷创建请求类") +public class PaperCreateReqDTO extends BaseDTO { - @JsonIgnore // Jackson注解,表示在进行JSON序列化/反序列化时忽略该字段 - private String userId; // 存储用户ID,通常用于标识发起请求的用户,但在JSON序列化中不会被传递 + @JsonIgnore + private String userId; + + @ApiModelProperty(value = "考试ID", required=true) + private String examId; - @ApiModelProperty(value = "考试ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String examId; // 存储考试ID,用于创建试卷时指定关联的考试 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java index a166dc8..c333241 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperListReqDTO.java @@ -1,40 +1,39 @@ -package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.request; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Serializable接口,用于对象序列化 + import java.io.Serializable; /** *

* 试卷请求类 *

-* 该类用于接收请求数据,包含用户ID、部门ID、规则ID、用户昵称和试卷状态等信息, -* 用于查询试卷列表。 +* * @author 聪明笨狗 * @since 2020-05-25 17:31 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷", description="试卷") // Swagger注解,描述该类在API文档中的作用和说明 -public class PaperListReqDTO implements Serializable { // 实现Serializable接口,支持对象的序列化 +@Data +@ApiModel(value="试卷", description="试卷") +public class PaperListReqDTO implements Serializable { + + private static final long serialVersionUID = 1L; - private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化时的版本控制 + @ApiModelProperty(value = "用户ID", required=true) + private String userId; - @ApiModelProperty(value = "用户ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String userId; // 存储请求发起者的用户ID,通常用于标识用户 + @ApiModelProperty(value = "部门ID", required=true) + private String departId; - @ApiModelProperty(value = "部门ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String departId; // 存储请求者所在部门的ID,用于查询特定部门的试卷 + @ApiModelProperty(value = "规则ID", required=true) + private String examId; - @ApiModelProperty(value = "规则ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String examId; // 存储与试卷相关的考试规则ID,用于标识试卷属于哪种考试 + @ApiModelProperty(value = "用户昵称", required=true) + private String realName; - @ApiModelProperty(value = "用户昵称", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String realName; // 存储用户的真实姓名,用于标识请求者 + @ApiModelProperty(value = "试卷状态", required=true) + private Integer state; - @ApiModelProperty(value = "试卷状态", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private Integer state; // 存储试卷的状态,可能的值如:未开始、进行中、已完成等 + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java index b91286c..48184b6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/request/PaperQuQueryDTO.java @@ -1,25 +1,21 @@ -package com.yf.exam.modules.paper.dto.request; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.request; -// 引入父类BaseDTO,用于继承基础字段和功能 import com.yf.exam.core.api.dto.BaseDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** * @author bool - * 查找试卷题目详情请求类,用于接收试卷和题目详情查询的请求数据。 - * 包含试卷ID和题目ID字段。 */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperQuQueryDTO extends BaseDTO { // 继承自BaseDTO类,扩展了试卷ID和题目ID字段 +@Data +@ApiModel(value="查找试卷题目详情请求类", description="查找试卷题目详情请求类") +public class PaperQuQueryDTO extends BaseDTO { - @ApiModelProperty(value = "试卷ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String paperId; // 存储试卷ID,用于查询特定试卷的题目详情 + @ApiModelProperty(value = "试卷ID", required=true) + private String paperId; + + @ApiModelProperty(value = "题目ID", required=true) + private String quId; - @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String quId; // 存储题目ID,用于查询指定试卷中的某一道题目 } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java index 12aecf2..c307c84 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamDetailRespDTO.java @@ -1,48 +1,38 @@ -package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.response; -// 引入父类PaperDTO,用于继承基础字段和功能 import com.yf.exam.modules.paper.dto.PaperDTO; -// 引入PaperQuDTO类,用于表示试题的DTO import com.yf.exam.modules.paper.dto.PaperQuDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Calendar类,用于时间计算 + import java.util.Calendar; -// 引入List集合,用于存储试题列表 import java.util.List; -/** - *

- * 考试详情响应类 - *

- * 该类继承自PaperDTO,扩展了多个属性,包含单选题、多选题、判断题的列表, - * 以及计算剩余时间的方法,用于提供考试的详细信息。 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="考试详情", description="考试详情") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class ExamDetailRespDTO extends PaperDTO { // 继承自PaperDTO,表示考试详情响应DTO +@Data +@ApiModel(value="考试详情", description="考试详情") +public class ExamDetailRespDTO extends PaperDTO { + - @ApiModelProperty(value = "单选题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List radioList; // 存储单选题的列表,使用PaperQuDTO表示单个试题 + @ApiModelProperty(value = "单选题列表", required=true) + private List radioList; - @ApiModelProperty(value = "多选题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List multiList; // 存储多选题的列表,使用PaperQuDTO表示单个试题 + @ApiModelProperty(value = "多选题列表", required=true) + private List multiList; - @ApiModelProperty(value = "判断题", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List judgeList; // 存储判断题的列表,使用PaperQuDTO表示单个试题 + @ApiModelProperty(value = "判断题", required=true) + private List judgeList; - @ApiModelProperty(value = "剩余结束秒数", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - public Long getLeftSeconds(){ // 计算剩余时间的方法,返回剩余的秒数 + + @ApiModelProperty(value = "剩余结束秒数", required=true) + public Long getLeftSeconds(){ // 结束时间 - Calendar cl = Calendar.getInstance(); // 获取当前时间的Calendar实例 - cl.setTime(this.getCreateTime()); // 设置Calendar的时间为试卷的创建时间 - cl.add(Calendar.MINUTE, getTotalTime()); // 在创建时间的基础上加上试卷的总时间(分钟) + Calendar cl = Calendar.getInstance(); + cl.setTime(this.getCreateTime()); + cl.add(Calendar.MINUTE, getTotalTime()); - // 计算剩余时间(单位:秒) - return (cl.getTimeInMillis() - System.currentTimeMillis()) / 1000; // 返回剩余时间(当前时间到结束时间的差值,以秒为单位) + return (cl.getTimeInMillis() - System.currentTimeMillis()) / 1000; } + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java index 26c9710..64af63d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/ExamResultRespDTO.java @@ -1,29 +1,18 @@ -package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.response; -// 引入父类PaperDTO,用于继承基础字段和功能 import com.yf.exam.modules.paper.dto.PaperDTO; -// 引入PaperQuDetailDTO类,用于表示试题详细信息 import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入List集合,用于存储试题列表 + import java.util.List; -/** - *

- * 考试结果展示响应类 - *

- * 该类继承自PaperDTO,扩展了问题列表字段,用于展示考试结果的详细信息。 - * 包含试题的详细信息列表,返回考试时各个问题的答案或状态。 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="考试结果展示响应类", description="考试结果展示响应类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class ExamResultRespDTO extends PaperDTO { // 继承自PaperDTO,表示考试结果展示响应DTO +@Data +@ApiModel(value="考试结果展示响应类", description="考试结果展示响应类") +public class ExamResultRespDTO extends PaperDTO { - @ApiModelProperty(value = "问题列表", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private List quList; // 存储试题详细信息的列表,使用PaperQuDetailDTO表示每个试题的详细数据 + @ApiModelProperty(value = "问题列表", required=true) + private List quList; } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java index 379de39..9e003e4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/dto/response/PaperListRespDTO.java @@ -1,29 +1,26 @@ -package com.yf.exam.modules.paper.dto.response; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.dto.response; -// 引入父类PaperDTO,用于继承基本的试卷信息 import com.yf.exam.modules.paper.dto.PaperDTO; -// 引入Swagger注解,用于API文档生成 import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** - *

- * 试卷列表响应类 - *

- * 该类继承自PaperDTO,扩展了人员(realName)字段,用于展示试卷列表响应数据。 - * 包含试卷的基本信息以及相关人员信息。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@ApiModel(value="试卷列表响应类", description="试卷列表响应类") // Swagger注解,用于描述该类在API文档中的作用和说明 -public class PaperListRespDTO extends PaperDTO { // 继承自PaperDTO,表示试卷列表响应DTO +*

+* 试卷请求类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@ApiModel(value="试卷列表响应类", description="试卷列表响应类") +public class PaperListRespDTO extends PaperDTO { - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 + private static final long serialVersionUID = 1L; - @ApiModelProperty(value = "人员", required=true) // Swagger注解,描述该字段在API文档中的含义,并标注该字段为必填项 - private String realName; // 存储人员姓名,用于表示与该试卷相关的人员信息 + @ApiModelProperty(value = "人员", required=true) + private String realName; + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java index f6baaac..e219471 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/Paper.java @@ -1,104 +1,125 @@ -package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.entity; -// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; -// 引入Date类,用于时间相关的字段 + import java.util.Date; /** - *

- * 试卷实体类 - *

- * 该类对应数据库中的 `el_paper` 表,用于表示试卷的相关信息。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@TableName("el_paper") // MyBatis Plus注解,指定该实体类对应的数据库表名 -public class Paper extends Model { // 继承MyBatis Plus的Model类,提供了CRUD等基础操作 - - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 +*

+* 试卷实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper") +public class Paper extends Model { + + private static final long serialVersionUID = 1L; /** * 试卷ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 - private String id; // 试卷ID,唯一标识符 + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** * 用户ID */ - @TableField("user_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String userId; // 用户ID,表示创建该试卷的用户 + @TableField("user_id") + private String userId; /** * 部门ID */ - @TableField("depart_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String departId; // 部门ID,表示该试卷所属的部门 + @TableField("depart_id") + private String departId; /** * 规则ID */ - @TableField("exam_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String examId; // 规则ID,表示该试卷所属的考试规则 + @TableField("exam_id") + private String examId; /** * 考试标题 */ - private String title; // 考试标题,表示试卷的名称或标题 + private String title; /** * 考试时长 */ - @TableField("total_time") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer totalTime; // 考试时长,单位为分钟 + @TableField("total_time") + private Integer totalTime; /** * 用户时长 */ - @TableField("user_time") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer userTime; // 用户实际用时,单位为分钟 + @TableField("user_time") + private Integer userTime; /** * 试卷总分 */ - @TableField("total_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer totalScore; // 试卷的总分数 + @TableField("total_score") + private Integer totalScore; /** * 及格分 */ - @TableField("qualify_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer qualifyScore; // 及格分数,表示通过该试卷的最低分数 + @TableField("qualify_score") + private Integer qualifyScore; /** * 客观分 */ - @TableField("obj_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer objScore; // 客观题部分的得分 + @TableField("obj_score") + private Integer objScore; /** * 主观分 */ - @TableField("subj_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer subjScore; // 主观题部分的得分 + @TableField("subj_score") + private Integer subjScore; /** * 用户得分 */ - @TableField("user_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer userScore; // 用户在该试卷上的得分 + @TableField("user_score") + private Integer userScore; /** * 是否包含简答题 */ - @TableField("has_saq") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - + @TableField("has_saq") + private Boolean hasSaq; + + /** + * 试卷状态 + */ + private Integer state; + + /** + * 创建时间 + */ + @TableField("create_time") + private Date createTime; + + /** + * 更新时间 + */ + @TableField("update_time") + private Date updateTime; + + /** + * 截止时间 + */ + @TableField("limit_time") + private Date limitTime; +} diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java index f6be46d..3723791 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQu.java @@ -1,82 +1,80 @@ -package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.entity; -// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** - *

- * 试卷考题实体类 - *

- * 该类对应数据库中的 `el_paper_qu` 表,用于表示与试卷相关的考题信息。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@TableName("el_paper_qu") // MyBatis Plus注解,指定该实体类对应的数据库表名 -public class PaperQu extends Model { // 继承MyBatis Plus的Model类,提供了基础的CRUD等操作 +*

+* 试卷考题实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper_qu") +public class PaperQu extends Model { - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 + private static final long serialVersionUID = 1L; /** * ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 - private String id; // 题目ID,唯一标识符 + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** * 试卷ID */ - @TableField("paper_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String paperId; // 试卷ID,表示该题目所属的试卷ID + @TableField("paper_id") + private String paperId; /** * 题目ID */ - @TableField("qu_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String quId; // 题目ID,唯一标识符 + @TableField("qu_id") + private String quId; /** * 题目类型 */ - @TableField("qu_type") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer quType; // 题目类型,表示该题目属于哪种类型(例如单选题、多选题、主观题等) + @TableField("qu_type") + private Integer quType; /** * 是否已答 */ - private Boolean answered; // 是否已经回答,布尔值,表示该题目是否已经被回答 + private Boolean answered; /** * 主观答案 */ - private String answer; // 主观题的答案,保存用户的回答内容 + private String answer; /** * 问题排序 */ - private Integer sort; // 问题在试卷中的排序,决定题目的显示顺序 + private Integer sort; /** * 单题分分值 */ - private Integer score; // 每道题的分值,表示该题目的得分值 + private Integer score; /** * 实际得分(主观题) */ - @TableField("actual_score") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Integer actualScore; // 主观题的实际得分,可能与用户给出的答案相关 + @TableField("actual_score") + private Integer actualScore; /** * 是否答对 */ - @TableField("is_right") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Boolean isRight; // 是否答对,布尔值,表示用户是否答对了该题目 + @TableField("is_right") + private Boolean isRight; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java index 78c17ce..b3999da 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/entity/PaperQuAnswer.java @@ -1,71 +1,68 @@ -package com.yf.exam.modules.paper.entity; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.entity; -// 引入MyBatis Plus的相关注解 import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.activerecord.Model; -// 引入Lombok注解,用于自动生成getter、setter等方法 import lombok.Data; /** - *

- * 试卷考题备选答案实体类 - *

- * 该类对应数据库中的 `el_paper_qu_answer` 表,用于表示试卷考题的备选答案。 - * - * @author 聪明笨狗 - * @since 2020-05-25 17:31 - */ -@Data // Lombok注解,自动生成getter、setter、toString、equals和hashCode方法 -@TableName("el_paper_qu_answer") // MyBatis Plus注解,指定该实体类对应的数据库表名 -public class PaperQuAnswer extends Model { // 继承MyBatis Plus的Model类,提供了基础的CRUD等操作 +*

+* 试卷考题备选答案实体类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 17:31 +*/ +@Data +@TableName("el_paper_qu_answer") +public class PaperQuAnswer extends Model { - private static final long serialVersionUID = 1L; // 序列化版本ID,用于序列化和反序列化操作 /** * 自增ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键字段及其生成策略 - private String id; // 唯一标识符ID,数据库中的主键 + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** * 试卷ID */ - @TableField("paper_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String paperId; // 该备选答案对应的试卷ID + @TableField("paper_id") + private String paperId; /** * 回答项ID */ - @TableField("answer_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String answerId; // 该备选答案的唯一标识符ID + @TableField("answer_id") + private String answerId; /** * 题目ID */ - @TableField("qu_id") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private String quId; // 该备选答案所属的题目ID + @TableField("qu_id") + private String quId; /** * 是否正确项 */ - @TableField("is_right") // MyBatis Plus注解,指定字段与数据库表字段的映射关系 - private Boolean isRight; // 是否是正确答案,布尔值(true 表示正确,false 表示错误) + @TableField("is_right") + private Boolean isRight; /** * 是否选中 */ - private Boolean checked; // 该备选答案是否被选中,布尔值(true 表示已选中,false 表示未选中) + private Boolean checked; /** * 排序 */ - private Integer sort; // 备选答案的排序,决定该答案在选项中的位置 + private Integer sort; /** * 选项标签 */ - private String abc; // 备选答案的标签,通常为A、B、C、D等,用于显示选项 + private String abc; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java b/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java index f681da9..a62f404 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/enums/ExamState.java @@ -1,38 +1,33 @@ -package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.enums; + /** - *

- * 考试状态枚举接口 - *

- * 该接口定义了考试的不同状态,作为常量使用,帮助系统在处理考试过程中进行状态标识。 - * - * @author bool + * 考试状态 + * @author bool * @date 2019-10-30 13:11 */ public interface ExamState { + /** * 考试中 - * 代表考试正在进行中,通常表示考试尚未结束,学生可以继续答题。 */ Integer ENABLE = 0; /** * 待阅卷 - * 代表考试已经结束,但还没有开始批阅试卷,通常表示考试已经提交,等待教师或系统自动阅卷。 */ Integer DISABLED = 1; /** * 已完成 - * 代表考试已经完成,阅卷完成,结果已公布,但没有开始考试。 */ Integer READY_START = 2; /** * 已结束 - * 代表考试已经结束,不再接受任何操作,考试时间已超出,无法继续答题。 */ Integer OVERDUE = 3; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java b/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java index 27e342c..ceed269 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/enums/PaperState.java @@ -1,38 +1,33 @@ -package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径 +package com.yf.exam.modules.paper.enums; + /** - *

- * 试卷状态枚举接口 - *

- * 该接口定义了试卷的不同状态,作为常量使用,帮助系统在处理试卷过程中进行状态标识。 - * - * @author bool + * 试卷状态 + * @author bool * @date 2019-10-30 13:11 */ public interface PaperState { + /** * 考试中 - * 代表试卷正在进行中,学生正在参与考试,答题环节尚未结束。 */ Integer ING = 0; /** * 待阅卷 - * 代表考试已经结束,试卷已经提交,正在等待阅卷(人工或系统自动阅卷)。 */ Integer WAIT_OPT = 1; /** * 已完成 - * 代表试卷已完成,包括考试、阅卷等所有环节,成绩已经确定。 */ Integer FINISHED = 2; /** * 弃考 - * 代表学生中途放弃考试,考试未完成,可能是由于学生主动退出或其他原因(如时间到期)导致考试中止。 */ Integer BREAK = 3; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java b/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java index 23a9762..fb14f53 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/job/BreakExamJob.java @@ -1,61 +1,45 @@ -package com.yf.exam.modules.paper.job; // 定义类所在的包路径 - -import com.yf.exam.ability.job.service.JobService; // 导入 JobService 类,用于获取任务数据 -import com.yf.exam.modules.paper.service.PaperService; // 导入 PaperService 类,用于处理试卷相关的业务逻辑 -import lombok.extern.log4j.Log4j2; // 引入 log4j2 日志工具 -import org.quartz.Job; // 导入 Quartz 作业接口 -import org.quartz.JobDetail; // 导入 Quartz JobDetail 类 -import org.quartz.JobExecutionContext; // 导入 Quartz JobExecutionContext 类 -import org.quartz.JobExecutionException; // 导入 Quartz JobExecutionException 类 -import org.springframework.beans.factory.annotation.Autowired; // 引入 Spring 注解,用于自动注入依赖 -import org.springframework.stereotype.Component; // 引入 Spring 组件注解,标识为 Spring Bean +package com.yf.exam.modules.paper.job; + +import com.yf.exam.ability.job.service.JobService; +import com.yf.exam.modules.paper.service.PaperService; +import lombok.extern.log4j.Log4j2; +import org.quartz.Job; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** * 超时自动交卷任务 - *

- * 该类是一个 Quartz 定时任务,用于在考试时间到期后强制交卷。 - * 它在定时任务触发时调用 PaperService 进行强制交卷操作。 - *

- * * @author bool */ -@Log4j2 // 启用 log4j2 日志记录 -@Component // 标识该类为一个 Spring 组件,Spring 会自动将其注册为 Bean +@Log4j2 +@Component public class BreakExamJob implements Job { - // 自动注入 PaperService,用于处理与试卷相关的业务逻辑 @Autowired private PaperService paperService; - /** - * 定时任务执行的方法 - * - *

- * Quartz 会在定时任务触发时调用此方法。该方法获取任务的详细信息, - * 并通过 PaperService 强制提交超时的考试。 - *

- * - * @param jobExecutionContext 包含了 Quartz 定时任务的上下文信息 - * @throws JobExecutionException 如果任务执行过程中出现异常,将抛出该异常 - */ @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { - // 从 jobExecutionContext 中获取任务的详细信息 - JobDetail detail = jobExecutionContext.getJobDetail(); // 获取任务详情 - String name = detail.getKey().getName(); // 获取任务名称 - String group = detail.getKey().getGroup(); // 获取任务分组 - // 获取任务的附加数据,通常是任务触发时的相关参数 + JobDetail detail = jobExecutionContext.getJobDetail(); + String name = detail.getKey().getName(); + String group = detail.getKey().getGroup(); String data = String.valueOf(detail.getJobDataMap().get(JobService.TASK_DATA)); - // 打印任务执行日志,便于调试和跟踪 log.info("++++++++++定时任务:处理到期的交卷"); log.info("++++++++++jobName:{}", name); log.info("++++++++++jobGroup:{}", group); log.info("++++++++++taskData:{}", data); - // 调用 PaperService 进行强制交卷操作 - // data 参数通常是考试 ID 或者某种标识符,用于识别需要交卷的考试 + + // 强制交卷 paperService.handExam(data); + } + + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java index 833c518..1a52de5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperMapper.java @@ -1,46 +1,39 @@ -package com.yf.exam.modules.paper.mapper; // 定义类所在的包路径 +package com.yf.exam.modules.paper.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 引入 MyBatis-Plus 的 BaseMapper -import com.baomidou.mybatisplus.core.metadata.IPage; // 引入分页结果接口 IPage -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 引入分页插件 Page -import com.yf.exam.modules.paper.dto.PaperDTO; // 引入 DTO 类,表示试卷数据传输对象 -import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; // 引入请求 DTO 类,表示查询试卷时的请求参数 -import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; // 引入响应 DTO 类,表示查询试卷时的响应结果 -import com.yf.exam.modules.paper.entity.Paper; // 引入实体类,表示试卷数据表中的记录 -import org.apache.ibatis.annotations.Param; // 引入 MyBatis 注解,用于指定 SQL 查询中的参数 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.paper.dto.PaperDTO; +import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; +import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; +import com.yf.exam.modules.paper.entity.Paper; +import org.apache.ibatis.annotations.Param; import java.util.List; /** - *

- * 试卷Mapper接口,用于操作试卷数据表 - *

- * - * @author 聪明笨狗 - * @since 2020-05-25 16:33 - */ -public interface PaperMapper extends BaseMapper { // 继承 MyBatis-Plus 提供的 BaseMapper,自动实现 CRUD 操作 +*

+* 试卷Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ +public interface PaperMapper extends BaseMapper { /** * 查找试卷分页 - *

- * 根据分页参数 `Page` 和查询条件 `PaperListReqDTO` 返回试卷的分页结果。 - *

- * - * @param page 分页参数,包含当前页、每页大小等 - * @param query 查询条件,通常包含用户 ID、考试 ID 等信息 - * @return 返回一个分页结果 `IPage`,包含了试卷数据和分页信息 + * @param page + * @param query + * @return */ IPage paging(Page page, @Param("query") PaperListReqDTO query); + /** * 试卷列表响应类 - *

- * 根据查询条件返回试卷的列表数据,通常用于返回所有试卷的列表。 - *

- * - * @param query 查询条件,通常是试卷的基本信息,如试卷 ID、考试 ID 等 - * @return 返回一个试卷列表 `List`,每一项是试卷的响应 DTO + * @param query + * @return */ List list(@Param("query") PaperDTO query); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java index 8ab65ee..e795ba9 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuAnswerMapper.java @@ -1,33 +1,27 @@ -package com.yf.exam.modules.paper.mapper; // 指定该类所在的包路径 +package com.yf.exam.modules.paper.mapper; -// 导入BaseMapper接口,提供通用的CRUD操作 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -// 导入PaperQuAnswerExtDTO类,表示试卷考题备选答案的扩展数据传输对象 -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -// 导入PaperQuAnswer实体类,表示试卷考题备选答案的数据模型 -import com.yf.exam.modules.paper.entity.PaperQuAnswer; -// 导入MyBatis的注解,指定方法参数在SQL中的名称 -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +import com.yf.exam.modules.paper.entity.PaperQuAnswer; +import org.apache.ibatis.annotations.Param; -// 导入List接口,表示返回类型为List集合,用于存储多个备选答案 -import java.util.List; +import java.util.List; /** *

-* 试卷考题备选答案Mapper接口 +* 试卷考题备选答案Mapper *

-* 该接口用于处理试卷考题备选答案的数据库操作,继承自MyBatis-Plus的BaseMapper,提供通用的CRUD方法。 -* +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -public interface PaperQuAnswerMapper extends BaseMapper { // 继承自BaseMapper接口,提供了所有的基本CRUD操作 +public interface PaperQuAnswerMapper extends BaseMapper { /** * 查找试卷试题答案列表 - * @param paperId 试卷ID,标识要查询的试卷 - * @param quId 题目ID,标识要查询的题目 - * @return 返回与试卷ID和题目ID相关的备选答案列表,包含更多的答案细节 + * @param paperId + * @param quId + * @return */ - List list(@Param("paperId") String paperId, @Param("quId") String quId); // 根据试卷ID和题目ID查询对应的备选答案列表 + List list(@Param("paperId") String paperId, @Param("quId") String quId); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java index a9b2257..f833a1b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/mapper/PaperQuMapper.java @@ -1,46 +1,42 @@ -package com.yf.exam.modules.paper.mapper; // 定义该类所在的包路径 +package com.yf.exam.modules.paper.mapper; -// 导入BaseMapper接口,提供MyBatis-Plus的通用CRUD操作 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -// 导入PaperQuDetailDTO类,表示试卷考题详细数据传输对象 -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -// 导入PaperQu实体类,表示试卷考题的数据模型 -import com.yf.exam.modules.paper.entity.PaperQu; -// 导入MyBatis的@Param注解,用于方法参数与SQL查询中的参数进行映射 -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +import com.yf.exam.modules.paper.entity.PaperQu; +import org.apache.ibatis.annotations.Param; -// 导入List接口,用于返回多个试题 -import java.util.List; +import java.util.List; /** *

-* 试卷考题Mapper接口 +* 试卷考题Mapper *

-* 该接口用于处理与试卷考题相关的数据库操作,继承自MyBatis-Plus的BaseMapper,提供通用的CRUD操作。 -* +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -public interface PaperQuMapper extends BaseMapper { // 继承自BaseMapper接口,提供通用的CRUD操作 +public interface PaperQuMapper extends BaseMapper { /** * 统计客观分 - * @param paperId 试卷ID,用于查询指定试卷的客观分数 - * @return 返回试卷的客观分数总和 + * @param paperId + * @return */ - int sumObjective(@Param("paperId") String paperId); // 根据试卷ID统计所有客观题的分数总和 + int sumObjective(@Param("paperId") String paperId); /** * 统计主观分 - * @param paperId 试卷ID,用于查询指定试卷的主观分数 - * @return 返回试卷的主观分数总和 + * @param paperId + * @return */ - int sumSubjective(@Param("paperId") String paperId); // 根据试卷ID统计所有主观题的分数总和 + int sumSubjective(@Param("paperId") String paperId); /** * 找出全部试题列表 - * @param paperId 试卷ID,用于查询指定试卷的所有试题 - * @return 返回试卷中的所有试题列表,类型为PaperQuDetailDTO + * @param paperId + * @return */ - List listByPaper(@Param("paperId") String paperId); // 根据试卷ID查询所有试题的详细信息 + List listByPaper(@Param("paperId") String paperId); } + + diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java index 3d2f1d5..a1cfffa 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuAnswerService.java @@ -1,20 +1,18 @@ -// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 -import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 -import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO -import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; // 试卷问题答案DTO -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; // 扩展的试卷问题答案DTO -import com.yf.exam.modules.paper.entity.PaperQuAnswer; // 试卷问题答案实体类 +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +import com.yf.exam.modules.paper.entity.PaperQuAnswer; -import java.util.List; // 导入List类,用于处理集合数据 +import java.util.List; /** *

* 试卷考题备选答案业务类 *

-* 该接口定义了与试卷考题备选答案相关的业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -23,24 +21,24 @@ public interface PaperQuAnswerService extends IService { /** * 分页查询数据 - * @param reqDTO 分页请求DTO,包含查询的分页信息和条件 - * @return 返回分页查询结果,包含 PaperQuAnswerDTO 对象的数据 + * @param reqDTO + * @return */ IPage paging(PagingReqDTO reqDTO); /** - * 查找试卷试题的答案列表 - * @param paperId 试卷ID,用于定位试卷 - * @param quId 试题ID,用于定位具体的试题 - * @return 返回该试卷和试题的所有答案列表,数据类型为 PaperQuAnswerExtDTO + * 查找试卷试题答案列表 + * @param paperId + * @param quId + * @return */ List listForExam(String paperId, String quId); /** - * 查找答案列表,用来填充试卷答案 - * @param paperId 试卷ID,用于定位试卷 - * @param quId 试题ID,用于定位具体试题的答案 - * @return 返回对应试题的答案列表,数据类型为 PaperQuAnswer 实体 + * 查找答案列表,用来填充 + * @param paperId + * @param quId + * @return */ List listForFill(String paperId, String quId); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java index 23d0af8..d0cc2e3 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperQuService.java @@ -1,20 +1,18 @@ -// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 -import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 -import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO -import com.yf.exam.modules.paper.dto.PaperQuDTO; // 试卷问题DTO -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; // 试卷问题详情DTO -import com.yf.exam.modules.paper.entity.PaperQu; // 试卷问题实体类 +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.paper.dto.PaperQuDTO; +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +import com.yf.exam.modules.paper.entity.PaperQu; -import java.util.List; // 导入List类,用于处理集合数据 +import java.util.List; /** *

* 试卷考题业务类 *

-* 该接口定义了与试卷考题相关的业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -23,50 +21,50 @@ public interface PaperQuService extends IService { /** * 分页查询数据 - * @param reqDTO 分页请求DTO,包含查询的分页信息和条件 - * @return 返回分页查询结果,包含 PaperQuDTO 对象的数据 + * @param reqDTO + * @return */ IPage paging(PagingReqDTO reqDTO); /** * 根据试卷找出题目列表 - * @param paperId 试卷ID,用于定位试卷 - * @return 返回该试卷的所有题目列表,数据类型为 PaperQuDTO + * @param paperId + * @return */ List listByPaper(String paperId); /** - * 查找试卷中某个问题的详细信息 - * @param paperId 试卷ID - * @param quId 试题ID,用于定位具体的试题 - * @return 返回该试卷和试题的详细信息,数据类型为 PaperQu + * 查找详情 + * @param paperId + * @param quId + * @return */ PaperQu findByKey(String paperId, String quId); /** - * 根据组合索引更新试题 - * @param qu 试题实体,用于更新试卷中的试题 + * 根据组合索引更新 + * @param qu */ void updateByKey(PaperQu qu); /** - * 统计试卷中所有客观题的总分 - * @param paperId 试卷ID - * @return 返回该试卷客观题的总分 + * 统计客观分 + * @param paperId + * @return */ int sumObjective(String paperId); /** - * 统计试卷中所有主观题的总分 - * @param paperId 试卷ID - * @return 返回该试卷主观题的总分 + * 统计主观分 + * @param paperId + * @return */ int sumSubjective(String paperId); /** - * 查找试卷的全部试题列表(用于展示结果) - * @param paperId 试卷ID - * @return 返回该试卷的详细试题列表,数据类型为 PaperQuDetailDTO + * 找出全部试题列表 + * @param paperId + * @return */ List listForPaperResult(String paperId); } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java index ec5f724..042bb7d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/PaperService.java @@ -1,23 +1,21 @@ -// 导入所需的包 package com.yf.exam.modules.paper.service; -import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页查询 -import com.baomidou.mybatisplus.extension.service.IService; // 用于继承通用服务接口 -import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO -import com.yf.exam.modules.paper.dto.PaperDTO; // 试卷DTO -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; // 试卷题目详情DTO -import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; // 提交答案请求DTO -import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; // 试卷列表请求DTO -import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; // 考试详情响应DTO -import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; // 考试结果响应DTO -import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; // 试卷列表响应DTO -import com.yf.exam.modules.paper.entity.Paper; // 试卷实体类 +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.service.IService; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.paper.dto.PaperDTO; +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; +import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; +import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; +import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; +import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; +import com.yf.exam.modules.paper.entity.Paper; /** *

* 试卷业务类 *

-* 该接口定义了与试卷相关的所有业务操作 * * @author 聪明笨狗 * @since 2020-05-25 16:33 @@ -26,57 +24,60 @@ public interface PaperService extends IService { /** * 创建试卷 - * @param userId 用户ID,表示试卷创建者 - * @param examId 考试ID,表示该试卷属于哪个考试 - * @return 返回创建的试卷ID + * @param userId + * @param examId + * @return */ String createPaper(String userId, String examId); + /** - * 查找试卷详情 - * @param paperId 试卷ID,表示要查找的试卷 - * @return 返回试卷的详细信息,数据类型为 ExamDetailRespDTO + * 查找详情 + * @param paperId + * @return */ ExamDetailRespDTO paperDetail(String paperId); /** - * 获取考试结果 - * @param paperId 试卷ID,表示要查询结果的试卷 - * @return 返回该试卷的考试结果,数据类型为 ExamResultRespDTO + * 考试结果 + * @param paperId + * @return */ ExamResultRespDTO paperResult(String paperId); /** - * 查找试卷题目详情 - * @param paperId 试卷ID - * @param quId 题目ID,表示要查询的具体题目 - * @return 返回该试卷和题目的详细信息,数据类型为 PaperQuDetailDTO + * 查找题目详情 + * @param paperId + * @param quId + * @return */ PaperQuDetailDTO findQuDetail(String paperId, String quId); /** - * 填充试卷答案 - * @param reqDTO 填写答案的请求DTO,包含试卷答案信息 + * 填充答案 + * @param reqDTO */ void fillAnswer(PaperAnswerDTO reqDTO); /** - * 提交试卷(交卷) - * @param paperId 试卷ID,表示要交卷的试卷 + * 交卷操作 + * @param paperId + * @return */ void handExam(String paperId); /** - * 分页查询试卷列表 - * @param reqDTO 分页请求DTO,包含分页信息和查询条件 - * @return 返回分页后的试卷列表,数据类型为 IPage + * 试卷列表响应类 + * @param reqDTO + * @return */ IPage paging(PagingReqDTO reqDTO); /** - * 检查用户是否有正在进行的考试 - * @param userId 用户ID,用于查找该用户是否有未完成的考试 - * @return 返回该用户正在进行的考试试卷信息,数据类型为 PaperDTO + * 检测是否有进行中的考试 + * @param userId + * @return */ PaperDTO checkProcess(String userId); + } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java index 14e8306..c2dc0b7 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuAnswerServiceImpl.java @@ -1,95 +1,61 @@ -package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径 - -// 导入FastJSON库,用于处理JSON格式数据的转换 -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -// 导入MyBatis-Plus的条件查询构造器 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -// 导入分页接口 -import com.baomidou.mybatisplus.core.metadata.IPage; -// 导入分页Page类 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -// 导入MyBatis-Plus的服务实现类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -// 导入分页请求DTO,用于分页查询 -import com.yf.exam.core.api.dto.PagingReqDTO; -// 导入试卷考题备选答案DTO类 -import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; -// 导入试卷考题备选答案扩展DTO类 -import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -// 导入试卷考题备选答案实体类 -import com.yf.exam.modules.paper.entity.PaperQuAnswer; -// 导入试卷考题备选答案Mapper接口 -import com.yf.exam.modules.paper.mapper.PaperQuAnswerMapper; -// 导入试卷考题备选答案服务接口 -import com.yf.exam.modules.paper.service.PaperQuAnswerService; -// 导入Spring的Service注解,表示这是一个服务实现类 -import org.springframework.stereotype.Service; - -import java.util.List; // 导入List接口,用于返回多个结果 +package com.yf.exam.modules.paper.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.paper.dto.PaperQuAnswerDTO; +import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; +import com.yf.exam.modules.paper.entity.PaperQuAnswer; +import com.yf.exam.modules.paper.mapper.PaperQuAnswerMapper; +import com.yf.exam.modules.paper.service.PaperQuAnswerService; +import org.springframework.stereotype.Service; + +import java.util.List; /** *

-* 试卷考题备选答案 服务实现类 +* 语言设置 服务实现类 *

-* 该类实现了PaperQuAnswerService接口,处理与试卷考题备选答案相关的业务逻辑。 -* +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Service // 标注为Spring的服务类 -public class PaperQuAnswerServiceImpl extends ServiceImpl implements PaperQuAnswerService { // 继承ServiceImpl类,提供基本的数据库操作功能 +@Service +public class PaperQuAnswerServiceImpl extends ServiceImpl implements PaperQuAnswerService { - /** - * 分页查询试卷考题备选答案 - * @param reqDTO 分页请求参数,包括当前页和页面大小 - * @return 分页后的试卷考题备选答案列表 - */ @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象 + //创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - // 查询条件,可以根据需要添加更多过滤条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - // 执行分页查询操作 + //获得数据 IPage page = this.page(query, wrapper); - - // 将查询结果转换为DTO对象,返回分页后的结果 + //转换结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); - - return pageData; // 返回分页结果 - } + return pageData; + } - /** - * 根据试卷ID和题目ID查询试题的备选答案列表 - * @param paperId 试卷ID - * @param quId 题目ID - * @return 试卷考题备选答案的扩展DTO列表 - */ @Override public List listForExam(String paperId, String quId) { - // 调用Mapper中的list方法,查询并返回试题的备选答案列表 return baseMapper.list(paperId, quId); } - /** - * 查询填空题的备选答案 - * @param paperId 试卷ID - * @param quId 题目ID - * @return 填空题的备选答案列表 - */ @Override public List listForFill(String paperId, String quId) { - // 创建查询条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() // 使用Lambda表达式,进行条件构造 - .eq(PaperQuAnswer::getPaperId, paperId) // 通过试卷ID过滤 - .eq(PaperQuAnswer::getQuId, quId); // 通过题目ID过滤 + wrapper.lambda() + .eq(PaperQuAnswer::getPaperId, paperId) + .eq(PaperQuAnswer::getQuId, quId); - // 查询并返回符合条件的结果列表 return this.list(wrapper); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java index 46c9635..a0d9a1d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperQuServiceImpl.java @@ -1,150 +1,94 @@ -package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径 - -// 导入FastJSON库,用于处理JSON格式数据的转换 -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -// 导入MyBatis-Plus的条件查询构造器 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -// 导入分页接口 -import com.baomidou.mybatisplus.core.metadata.IPage; -// 导入分页Page类 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -// 导入MyBatis-Plus的服务实现类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -// 导入分页请求DTO,用于分页查询 -import com.yf.exam.core.api.dto.PagingReqDTO; -// 导入BeanMapper工具类,用于对象间的转换 -import com.yf.exam.core.utils.BeanMapper; -// 导入试卷考题DTO类 -import com.yf.exam.modules.paper.dto.PaperQuDTO; -// 导入试卷考题详情DTO类 -import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -// 导入试卷考题实体类 -import com.yf.exam.modules.paper.entity.PaperQu; -// 导入试卷考题Mapper接口 -import com.yf.exam.modules.paper.mapper.PaperQuMapper; -// 导入试卷考题服务接口 -import com.yf.exam.modules.paper.service.PaperQuService; -// 导入Spring的Service注解,表示这是一个服务实现类 -import org.springframework.stereotype.Service; - -import java.util.List; // 导入List接口,用于返回多个结果 +package com.yf.exam.modules.paper.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.paper.dto.PaperQuDTO; +import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; +import com.yf.exam.modules.paper.entity.PaperQu; +import com.yf.exam.modules.paper.mapper.PaperQuMapper; +import com.yf.exam.modules.paper.service.PaperQuService; +import org.springframework.stereotype.Service; + +import java.util.List; /** *

-* 试卷考题 服务实现类 +* 语言设置 服务实现类 *

-* 该类实现了PaperQuService接口,处理与试卷考题相关的业务逻辑。 -* +* * @author 聪明笨狗 * @since 2020-05-25 16:33 */ -@Service // 标注为Spring的服务类 -public class PaperQuServiceImpl extends ServiceImpl implements PaperQuService { // 继承ServiceImpl类,提供基本的数据库操作功能 - - /** - * 分页查询试卷考题 - * @param reqDTO 分页请求参数,包括当前页和页面大小 - * @return 分页后的试卷考题列表 - */ +@Service +public class PaperQuServiceImpl extends ServiceImpl implements PaperQuService { + @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象 + //创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - // 查询条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - // 执行分页查询操作 + //获得数据 IPage page = this.page(query, wrapper); - - // 将查询结果转换为DTO对象,返回分页后的结果 + //转换结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); - - return pageData; // 返回分页结果 - } + return pageData; + } - /** - * 根据试卷ID查询试卷考题列表 - * @param paperId 试卷ID - * @return 试卷考题DTO列表 - */ @Override public List listByPaper(String paperId) { - // 查询条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, paperId) // 通过试卷ID过滤 - .orderByAsc(PaperQu::getSort); // 按照题目排序字段升序排列 + wrapper.lambda().eq(PaperQu::getPaperId, paperId) + .orderByAsc(PaperQu::getSort); - // 执行查询,获取试卷考题列表 List list = this.list(wrapper); - - // 使用BeanMapper工具类将实体对象列表转换为DTO对象列表 return BeanMapper.mapList(list, PaperQuDTO.class); } - /** - * 根据试卷ID和题目ID查找单个试卷考题 - * @param paperId 试卷ID - * @param quId 题目ID - * @return 找到的试卷考题对象 - */ @Override public PaperQu findByKey(String paperId, String quId) { - // 查询条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, paperId) // 通过试卷ID过滤 - .eq(PaperQu::getQuId, quId); // 通过题目ID过滤 + wrapper.lambda().eq(PaperQu::getPaperId, paperId) + .eq(PaperQu::getQuId, quId); - // 获取匹配的单个试卷考题对象 - return this.getOne(wrapper, false); // 返回查询到的结果,false表示未查询到时返回null + return this.getOne(wrapper, false); } - /** - * 根据试卷ID和题目ID更新试卷考题 - * @param qu 需要更新的试卷考题对象 - */ @Override public void updateByKey(PaperQu qu) { - // 查询条件 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(PaperQu::getPaperId, qu.getPaperId()) // 通过试卷ID过滤 - .eq(PaperQu::getQuId, qu.getQuId()); // 通过题目ID过滤 + wrapper.lambda().eq(PaperQu::getPaperId, qu.getPaperId()) + .eq(PaperQu::getQuId, qu.getQuId()); - // 执行更新操作 - this.update(qu, wrapper); // 更新满足条件的试卷考题 + this.update(qu, wrapper); } - /** - * 统计试卷中的客观题分数 - * @param paperId 试卷ID - * @return 客观题的总分 - */ @Override public int sumObjective(String paperId) { - return baseMapper.sumObjective(paperId); // 调用Mapper方法,统计客观题总分 + return baseMapper.sumObjective(paperId); } - /** - * 统计试卷中的主观题分数 - * @param paperId 试卷ID - * @return 主观题的总分 - */ @Override public int sumSubjective(String paperId) { - return baseMapper.sumSubjective(paperId); // 调用Mapper方法,统计主观题总分 + return baseMapper.sumSubjective(paperId); } - /** - * 根据试卷ID查询试卷考题的详细信息 - * @param paperId 试卷ID - * @return 试卷考题详细信息列表 - */ @Override public List listForPaperResult(String paperId) { - return baseMapper.listByPaper(paperId); // 调用Mapper方法,获取试卷考题详细信息 + return baseMapper.listByPaper(paperId); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java index 8f28028..2eefec8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/paper/service/impl/PaperServiceImpl.java @@ -1,167 +1,103 @@ -// 定义包名,表示该类属于com.yf.exam.modules.paper.service.impl包下 package com.yf.exam.modules.paper.service.impl; -// 导入MyBatis Plus框架的核心类,用于构建查询条件 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; -// 导入MyBatis Plus框架的工具类,用于生成唯一ID import com.baomidou.mybatisplus.core.toolkit.IdWorker; -// 导入MyBatis Plus框架的服务实现类 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -// 导入项目中定义的作业组枚举 import com.yf.exam.ability.job.enums.JobGroup; -// 导入项目中定义的作业前缀枚举 import com.yf.exam.ability.job.enums.JobPrefix; -// 导入项目中的作业服务接口 import com.yf.exam.ability.job.service.JobService; -// 导入项目中定义的API错误码类 import com.yf.exam.core.api.ApiError; -// 导入项目中定义的DTO类,用于分页请求 import com.yf.exam.core.api.dto.PagingReqDTO; -// 导入项目中的服务异常类 import com.yf.exam.core.exception.ServiceException; -// 导入项目中定义的Bean映射工具类 import com.yf.exam.core.utils.BeanMapper; -// 导入项目中定义的Cron表达式工具类 import com.yf.exam.core.utils.CronUtils; -// 导入项目中定义的考试DTO类 import com.yf.exam.modules.exam.dto.ExamDTO; -// 导入项目中定义的考试题库DTO类 import com.yf.exam.modules.exam.dto.ExamRepoDTO; -// 导入项目中定义的扩展考试题库DTO类 import com.yf.exam.modules.exam.dto.ext.ExamRepoExtDTO; -// 导入项目中的考试服务接口 import com.yf.exam.modules.exam.service.ExamRepoService; -// 导入项目中的考试服务接口 import com.yf.exam.modules.exam.service.ExamService; -// 导入项目中定义的试卷DTO类 import com.yf.exam.modules.paper.dto.PaperDTO; -// 导入项目中定义的试卷题目DTO类 import com.yf.exam.modules.paper.dto.PaperQuDTO; -// 导入项目中定义的扩展试卷题目答案DTO类 import com.yf.exam.modules.paper.dto.ext.PaperQuAnswerExtDTO; -// 导入项目中定义的试卷题目详情DTO类 import com.yf.exam.modules.paper.dto.ext.PaperQuDetailDTO; -// 导入项目中定义的试卷答案DTO类 import com.yf.exam.modules.paper.dto.request.PaperAnswerDTO; -// 导入项目中定义的试卷列表请求DTO类 import com.yf.exam.modules.paper.dto.request.PaperListReqDTO; -// 导入项目中定义的试卷列表响应DTO类 import com.yf.exam.modules.paper.dto.response.ExamDetailRespDTO; -// 导入项目中定义的考试结果响应DTO类 import com.yf.exam.modules.paper.dto.response.ExamResultRespDTO; -// 导入项目中定义的试卷列表响应DTO类 import com.yf.exam.modules.paper.dto.response.PaperListRespDTO; -// 导入项目中定义的试卷实体类 import com.yf.exam.modules.paper.entity.Paper; -// 导入项目中定义的试卷题目实体类 import com.yf.exam.modules.paper.entity.PaperQu; -// 导入项目中定义的试卷题目答案实体类 import com.yf.exam.modules.paper.entity.PaperQuAnswer; -// 导入项目中定义的考试状态枚举 import com.yf.exam.modules.paper.enums.ExamState; -// 导入项目中定义的试卷状态枚举 import com.yf.exam.modules.paper.enums.PaperState; -// 导入项目中定义的强制交卷作业类 import com.yf.exam.modules.paper.job.BreakExamJob; -// 导入项目中定义的试卷Mapper接口 import com.yf.exam.modules.paper.mapper.PaperMapper; -// 导入项目中定义的试卷题目服务接口 import com.yf.exam.modules.paper.service.PaperQuAnswerService; -// 导入项目中定义的试卷题目服务接口 import com.yf.exam.modules.paper.service.PaperQuService; -// 导入项目中定义的试卷服务接口 import com.yf.exam.modules.paper.service.PaperService; -// 导入项目中定义的题目实体类 import com.yf.exam.modules.qu.entity.Qu; -// 导入项目中定义的题目答案实体类 import com.yf.exam.modules.qu.entity.QuAnswer; -// 导入项目中定义的题目类型枚举 import com.yf.exam.modules.qu.enums.QuType; -// 导入项目中定义的题目服务接口 import com.yf.exam.modules.qu.service.QuAnswerService; -// 导入项目中定义的题目服务接口 import com.yf.exam.modules.qu.service.QuService; -// 导入项目中定义的系统用户实体类 import com.yf.exam.modules.sys.user.entity.SysUser; -// 导入项目中定义的系统用户服务接口 import com.yf.exam.modules.sys.user.service.SysUserService; -// 导入项目中定义的用户书籍服务接口 import com.yf.exam.modules.user.book.service.UserBookService; -// 导入项目中定义的用户考试服务接口 import com.yf.exam.modules.user.exam.service.UserExamService; -// 导入Apache Commons Lang库中的StringUtils类,用于字符串操作 import org.apache.commons.lang3.StringUtils; -// 导入Spring框架中的注解,用于自动注入依赖 import org.springframework.beans.factory.annotation.Autowired; -// 导入Spring框架中的注解,用于声明服务组件 import org.springframework.stereotype.Service; -// 导入Spring框架中的注解,用于声明事务管理 import org.springframework.transaction.annotation.Transactional; -// 导入Spring框架中的类,用于工具操作 import org.springframework.util.CollectionUtils; -// 导入Java.util包下的类,用于集合操作 import java.util.*; -// 定义语言设置服务实现类,继承自ServiceImpl,并实现PaperService接口 /** - *

- * 语言设置 服务实现类 - *

- * - * @author 聪明笨狗 - * @since 2020-05-25 16:33 - */ +*

+* 语言设置 服务实现类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 16:33 +*/ @Service public class PaperServiceImpl extends ServiceImpl implements PaperService { - // 自动注入系统用户服务 + @Autowired private SysUserService sysUserService; - // 自动注入考试服务 @Autowired private ExamService examService; - // 自动注入题目服务 @Autowired private QuService quService; - // 自动注入题目答案服务 @Autowired private QuAnswerService quAnswerService; - // 自动注入试卷服务 @Autowired private PaperService paperService; - // 自动注入试卷题目服务 @Autowired private PaperQuService paperQuService; - // 自动注入试卷题目答案服务 @Autowired private PaperQuAnswerService paperQuAnswerService; - // 自动注入用户书籍服务 @Autowired private UserBookService userBookService; - // 自动注入考试题库服务 @Autowired private ExamRepoService examRepoService; - // 自动注入用户考试服务 @Autowired private UserExamService userExamService; - // 自动注入作业服务 @Autowired private JobService jobService; - // 定义展示的选项,如ABC这样的选项列表 /** * 展示的选项,ABC这样 */ @@ -170,503 +106,437 @@ public class PaperServiceImpl extends ServiceImpl implements ,"Y","Z" }); - // 声明创建试卷的方法,使用事务管理,如果发生异常则回滚 - /** - * 创建试卷的方法 - * @param userId 用户ID - * @param examId 考试ID - * @return 返回试卷ID - */ + + + + @Transactional(rollbackFor = Exception.class) @Override public String createPaper(String userId, String examId) { - // 构建查询条件,查询是否有正在考试的试卷 + // 校验是否有正在考试的试卷 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() .eq(Paper::getUserId, userId) .eq(Paper::getState, PaperState.ING); - // 统计符合条件的试卷数量 int exists = this.count(wrapper); - // 如果存在正在考试的试卷,则抛出服务异常 + if (exists > 0) { throw new ServiceException(ApiError.ERROR_20010002); } - // 根据考试ID查询考试信息 + // 查找考试 ExamDTO exam = examService.findById(examId); - // 如果考试信息不存在,则抛出服务异常 if(exam == null){ throw new ServiceException(1, "考试不存在!"); } - // 如果考试状态不正确,则抛出服务异常 if(!ExamState.ENABLE.equals(exam.getState())){ throw new ServiceException(1, "考试状态不正确!"); } - // 根据考试ID生成试卷题目列表 + // 考试题目列表 + List quList = this.generateByRepo(examId); + + if(CollectionUtils.isEmpty(quList)){ + throw new ServiceException(1, "规则不正确,无对应的考题!"); + } + + //保存试卷内容 + Paper paper = this.savePaper(userId, exam, quList); - List quList = this.generateByRepo(examId); + // 强制交卷任务 + String jobName = JobPrefix.BREAK_EXAM + paper.getId(); + jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId()); - // 如果题目列表为空,则抛出服务异常 - if(CollectionUtils.isEmpty(quList)){ - throw new ServiceException(1, "规则不正确,无对应的考题!"); + return paper.getId(); } - // 保存试卷内容,并返回试卷ID - Paper paper = this.savePaper(userId, exam, quList); + @Override + public ExamDetailRespDTO paperDetail(String paperId) { - // 添加强制交卷任务 - String jobName = JobPrefix.BREAK_EXAM + paper.getId(); - jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId()); - return paper.getId(); -} + ExamDetailRespDTO respDTO = new ExamDetailRespDTO(); -// 声明查询试卷详情的方法 -/** - * 查询试卷详情的方法 - * @param paperId 试卷ID - * @return 返回考试详情响应DTO - */ -@Override -public ExamDetailRespDTO paperDetail(String paperId) { - - // 创建考试详情响应DTO对象 - ExamDetailRespDTO respDTO = new ExamDetailRespDTO(); - - // 根据试卷ID查询试卷基本信息,并复制到响应DTO中 - Paper paper = paperService.getById(paperId); - BeanMapper.copy(paper, respDTO); - - // 根据试卷ID查询题目列表 - List list = paperQuService.listByPaper(paperId); - - // 分类题目列表 - List radioList = new ArrayList<>(); - List multiList = new ArrayList<>(); - List judgeList = new ArrayList<>(); - for(PaperQuDTO item: list){ - if(QuType.RADIO.equals(item.getQuType())){ - radioList.add(item); - } - if(QuType.MULTI.equals(item.getQuType())){ - multiList.add(item); - } - if(QuType.JUDGE.equals(item.getQuType())){ - judgeList.add(item); + // 试题基本信息 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); + + // 查找题目列表 + List list = paperQuService.listByPaper(paperId); + + List radioList = new ArrayList<>(); + List multiList = new ArrayList<>(); + List judgeList = new ArrayList<>(); + for(PaperQuDTO item: list){ + if(QuType.RADIO.equals(item.getQuType())){ + radioList.add(item); + } + if(QuType.MULTI.equals(item.getQuType())){ + multiList.add(item); + } + if(QuType.JUDGE.equals(item.getQuType())){ + judgeList.add(item); + } } + + respDTO.setRadioList(radioList); + respDTO.setMultiList(multiList); + respDTO.setJudgeList(judgeList); + return respDTO; } - // 设置分类后的题目列表到响应DTO中 - respDTO.setRadioList(radioList); - respDTO.setMultiList(multiList); - respDTO.setJudgeList(judgeList); - return respDTO; -} + @Override + public ExamResultRespDTO paperResult(String paperId) { -// 声明查询试卷结果的方法 -/** - * 查询试卷结果的方法 - * @param paperId 试卷ID - * @return 返回考试结果响应DTO - */ -@Override -public ExamResultRespDTO paperResult(String paperId) { + ExamResultRespDTO respDTO = new ExamResultRespDTO(); - // 创建考试结果响应DTO对象 - ExamResultRespDTO respDTO = new ExamResultRespDTO(); + // 试题基本信息 + Paper paper = paperService.getById(paperId); + BeanMapper.copy(paper, respDTO); - // 根据试卷ID查询试卷基本信息,并复制到响应DTO中 - Paper paper = paperService.getById(paperId); - BeanMapper.copy(paper, respDTO); + List quList = paperQuService.listForPaperResult(paperId); + respDTO.setQuList(quList); - // 根据试卷ID查询题目列表 - List quList = paperQuService.listForPaperResult(paperId); - respDTO.setQuList(quList); + return respDTO; + } - return respDTO; -} + @Override + public PaperQuDetailDTO findQuDetail(String paperId, String quId) { -// 声明查询题目详情的方法 -/** - * 查询题目详情的方法 - * @param paperId 试卷ID - * @param quId 题目ID - * @return 返回题目详情DTO - */ -@Override -public PaperQuDetailDTO findQuDetail(String paperId, String quId) { - - // 创建题目详情DTO对象 - PaperQuDetailDTO respDTO = new PaperQuDetailDTO(); - // 根据题目ID查询题目信息 - Qu qu = quService.getById(quId); - - // 根据试卷ID和题目ID查询试卷题目信息,并复制到响应DTO中 - PaperQu paperQu = paperQuService.findByKey(paperId, quId); - BeanMapper.copy(paperQu, respDTO); - respDTO.setContent(qu.getContent()); - respDTO.setImage(qu.getImage()); - - // 根据试卷ID和题目ID查询答案列表,并设置到响应DTO中 - List list = paperQuAnswerService.listForExam(paperId, quId); - respDTO.setAnswerList(list); - - return respDTO; -} + PaperQuDetailDTO respDTO = new PaperQuDetailDTO(); + // 问题 + Qu qu = quService.getById(quId); -// 声明题库组题方式产生题目列表的私有方法 -/** - * 题库组题方式产生题目列表的方法 - * @param examId 考试ID - * @return 返回题目列表 - */ -private List generateByRepo(String examId){ - - // 查询规则指定的题库 - List list = examRepoService.listByExam(examId); - - // 最终的题目列表 - List quList = new ArrayList<>(); - - // 排除ID,避免题目重复 - List excludes = new ArrayList<>(); - excludes.add("none"); - - // 如果题库列表不为空,则进行题目抽取 - if (!CollectionUtils.isEmpty(list)) { - for (ExamRepoExtDTO item : list) { - - // 抽取单选题 - if(item.getRadioCount() > 0){ - List radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount()); - for (Qu qu : radioList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); + // 基本信息 + PaperQu paperQu = paperQuService.findByKey(paperId, quId); + BeanMapper.copy(paperQu, respDTO); + respDTO.setContent(qu.getContent()); + respDTO.setImage(qu.getImage()); + + // 答案列表 + List list = paperQuAnswerService.listForExam(paperId, quId); + respDTO.setAnswerList(list); + + return respDTO; + } + + + /** + * 题库组题方式产生题目列表 + * @param examId + * @return + */ + private List generateByRepo(String examId){ + + // 查找规则指定的题库 + List list = examRepoService.listByExam(examId); + + //最终的题目列表 + List quList = new ArrayList<>(); + + //排除ID,避免题目重复 + List excludes = new ArrayList<>(); + excludes.add("none"); + + if (!CollectionUtils.isEmpty(list)) { + for (ExamRepoExtDTO item : list) { + + // 单选题 + if(item.getRadioCount() > 0){ + List radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount()); + for (Qu qu : radioList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } } - } - // 抽取多选题 - if(item.getMultiCount() > 0) { - List multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes, - item.getMultiCount()); - for (Qu qu : multiList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); + //多选题 + if(item.getMultiCount() > 0) { + List multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes, + item.getMultiCount()); + for (Qu qu : multiList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } } - } - // 抽取判断题 - if(item.getJudgeCount() > 0) { - List judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes, - item.getJudgeCount()); - for (Qu qu : judgeList) { - PaperQu paperQu = this.processPaperQu(item, qu); - quList.add(paperQu); - excludes.add(qu.getId()); + // 判断题 + if(item.getJudgeCount() > 0) { + List judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes, + item.getJudgeCount()); + for (Qu qu : judgeList) { + PaperQu paperQu = this.processPaperQu(item, qu); + quList.add(paperQu); + excludes.add(qu.getId()); + } } } } + return quList; } - return quList; -} -// 声明填充试题题目信息的私有方法 -/** - * 填充试题题目信息的方法 - * @param repo 考试题库DTO - * @param qu 题目实体 - * @return 返回试卷题目实体 - */ -private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) { - - // 创建试卷题目实体 - PaperQu paperQu = new PaperQu(); - paperQu.setQuId(qu.getId()); - paperQu.setAnswered(false); - paperQu.setIsRight(false); - paperQu.setQuType(qu.getQuType()); - - // 设置单选题分数 - if (QuType.RADIO.equals(qu.getQuType())) { - paperQu.setScore(repo.getRadioScore()); - paperQu.setActualScore(repo.getRadioScore()); - } - // 设置多选题分数 - if (QuType.MULTI.equals(qu.getQuType())) { - paperQu.setScore(repo.getMultiScore()); - paperQu.setActualScore(repo.getMultiScore()); - } - // 设置判断题分数 - if (QuType.JUDGE.equals(qu.getQuType())) { - paperQu.setScore(repo.getJudgeScore()); - paperQu.setActualScore(repo.getJudgeScore()); + /** + * 填充试题题目信息 + * @param repo + * @param qu + * @return + */ + private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) { + + //保存试题信息 + PaperQu paperQu = new PaperQu(); + paperQu.setQuId(qu.getId()); + paperQu.setAnswered(false); + paperQu.setIsRight(false); + paperQu.setQuType(qu.getQuType()); + + if (QuType.RADIO.equals(qu.getQuType())) { + paperQu.setScore(repo.getRadioScore()); + paperQu.setActualScore(repo.getRadioScore()); + } + + if (QuType.MULTI.equals(qu.getQuType())) { + paperQu.setScore(repo.getMultiScore()); + paperQu.setActualScore(repo.getMultiScore()); + } + + if (QuType.JUDGE.equals(qu.getQuType())) { + paperQu.setScore(repo.getJudgeScore()); + paperQu.setActualScore(repo.getJudgeScore()); + } + + return paperQu; } - return paperQu; -} -// 声明保存试卷的私有方法 -/** - * 保存试卷的方法 - * @param userId 用户ID - * @param exam 考试DTO - * @param quList 题目列表 - * @return 返回试卷实体 - */ -private Paper savePaper(String userId, ExamDTO exam, List quList) { - - - // 根据用户ID查询用户信息 - SysUser user = sysUserService.getById(userId); - - // 创建试卷基本信息,并设置属性 - Paper paper = new Paper(); - paper.setDepartId(user.getDepartId()); - paper.setExamId(exam.getId()); - paper.setTitle(exam.getTitle()); - paper.setTotalScore(exam.getTotalScore()); - paper.setTotalTime(exam.getTotalTime()); - paper.setUserScore(0); - paper.setUserId(userId); - paper.setCreateTime(new Date()); - paper.setUpdateTime(new Date()); - paper.setQualifyScore(exam.getQualifyScore()); - paper.setState(PaperState.ING); - paper.setHasSaq(false); - - // 计算截止时间 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - cl.add(Calendar.MINUTE, exam.getTotalTime()); - paper.setLimitTime(cl.getTime()); - - // 保存试卷基本信息 - paperService.save(paper); - - // 如果题目列表不为空,则保存试卷题目列表 - if (!CollectionUtils.isEmpty(quList)) { - this.savePaperQu(paper.getId(), quList); + /** + * 保存试卷 + * @param userId + * @param exam + * @param quList + * @return + */ + private Paper savePaper(String userId, ExamDTO exam, List quList) { + + + // 查找用户 + SysUser user = sysUserService.getById(userId); + + //保存试卷基本信息 + Paper paper = new Paper(); + paper.setDepartId(user.getDepartId()); + paper.setExamId(exam.getId()); + paper.setTitle(exam.getTitle()); + paper.setTotalScore(exam.getTotalScore()); + paper.setTotalTime(exam.getTotalTime()); + paper.setUserScore(0); + paper.setUserId(userId); + paper.setCreateTime(new Date()); + paper.setUpdateTime(new Date()); + paper.setQualifyScore(exam.getQualifyScore()); + paper.setState(PaperState.ING); + paper.setHasSaq(false); + + // 截止时间 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + cl.add(Calendar.MINUTE, exam.getTotalTime()); + paper.setLimitTime(cl.getTime()); + + paperService.save(paper); + + if (!CollectionUtils.isEmpty(quList)) { + this.savePaperQu(paper.getId(), quList); + } + + return paper; } - return paper; -} -// 声明保存试卷试题列表的私有方法 -/** - * 保存试卷试题列表的方法 - * @param paperId 试卷ID - * @param quList 题目列表 - */ -private void savePaperQu(String paperId, List quList){ - - // 创建批量保存的题目列表和答案列表 - List batchQuList = new ArrayList<>(); - List batchAnswerList = new ArrayList<>(); - - // 初始化排序号 - int sort = 0; - for (PaperQu item : quList) { - - // 设置试卷ID和排序号,并生成ID - item.setPaperId(paperId); - item.setSort(sort); - item.setId(IdWorker.getIdStr()); - - // 查询题目的答案列表 - List answerList = quAnswerService.listAnswerByRandom(item.getQuId()); - - // 如果答案列表不为空,则进行处理 - if (!CollectionUtils.isEmpty(answerList)) { - - // 初始化答案排序号 - int ii = 0; - for (QuAnswer answer : answerList) { - PaperQuAnswer paperQuAnswer = new PaperQuAnswer(); - paperQuAnswer.setId(UUID.randomUUID().toString()); - paperQuAnswer.setPaperId(paperId); - paperQuAnswer.setQuId(answer.getQuId()); - paperQuAnswer.setAnswerId(answer.getId()); - paperQuAnswer.setChecked(false); - paperQuAnswer.setSort(ii); - paperQuAnswer.setAbc(ABC.get(ii)); - paperQuAnswer.setIsRight(answer.getIsRight()); - ii++; - batchAnswerList.add(paperQuAnswer); + + /** + * 保存试卷试题列表 + * @param paperId + * @param quList + */ + private void savePaperQu(String paperId, List quList){ + + List batchQuList = new ArrayList<>(); + List batchAnswerList = new ArrayList<>(); + + int sort = 0; + for (PaperQu item : quList) { + + item.setPaperId(paperId); + item.setSort(sort); + item.setId(IdWorker.getIdStr()); + + //回答列表 + List answerList = quAnswerService.listAnswerByRandom(item.getQuId()); + + if (!CollectionUtils.isEmpty(answerList)) { + + int ii = 0; + for (QuAnswer answer : answerList) { + PaperQuAnswer paperQuAnswer = new PaperQuAnswer(); + paperQuAnswer.setId(UUID.randomUUID().toString()); + paperQuAnswer.setPaperId(paperId); + paperQuAnswer.setQuId(answer.getQuId()); + paperQuAnswer.setAnswerId(answer.getId()); + paperQuAnswer.setChecked(false); + paperQuAnswer.setSort(ii); + paperQuAnswer.setAbc(ABC.get(ii)); + paperQuAnswer.setIsRight(answer.getIsRight()); + ii++; + batchAnswerList.add(paperQuAnswer); + } } + + batchQuList.add(item); + sort++; } - // 添加到批量保存的题目列表中 - batchQuList.add(item); - sort++; + //添加问题 + paperQuService.saveBatch(batchQuList); + + //批量添加问题答案 + paperQuAnswerService.saveBatch(batchAnswerList); } - // 批量添加题目 - paperQuService.saveBatch(batchQuList); + @Transactional(rollbackFor = Exception.class) + @Override + public void fillAnswer(PaperAnswerDTO reqDTO) { - // 批量添加答案 - paperQuAnswerService.saveBatch(batchAnswerList); -} -// 声明填充答案的方法,使用事务管理 -/** - * 填充答案的方法 - * @param reqDTO 试卷答案DTO - */ -@Transactional(rollbackFor = Exception.class) -@Override -public void fillAnswer(PaperAnswerDTO reqDTO) { - - // 如果答案列表为空且答案字符串也为空,则直接返回 - if(CollectionUtils.isEmpty(reqDTO.getAnswers()) - && StringUtils.isBlank(reqDTO.getAnswer())){ - return; - } + // 未作答 + if(CollectionUtils.isEmpty(reqDTO.getAnswers()) + && StringUtils.isBlank(reqDTO.getAnswer())){ + return; + } - // 查询答案列表 - List list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId()); + //查找答案列表 + List list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId()); - // 初始化是否正确的标记 - boolean right = true; + //是否正确 + boolean right = true; - // 更新正确答案 - for (PaperQuAnswer item : list) { + //更新正确答案 + for (PaperQuAnswer item : list) { - // 设置答案是否被选中 - if (reqDTO.getAnswers().contains(item.getId())) { - item.setChecked(true); - } else { - item.setChecked(false); - } + if (reqDTO.getAnswers().contains(item.getId())) { + item.setChecked(true); + } else { + item.setChecked(false); + } - // 如果有一个答案不正确,则标记为错误 - if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) { - right = false; + //有一个对不上就是错的 + if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) { + right = false; + } + paperQuAnswerService.updateById(item); } - paperQuAnswerService.updateById(item); + + //修改为已回答 + PaperQu qu = new PaperQu(); + qu.setQuId(reqDTO.getQuId()); + qu.setPaperId(reqDTO.getPaperId()); + qu.setIsRight(right); + qu.setAnswer(reqDTO.getAnswer()); + qu.setAnswered(true); + + paperQuService.updateByKey(qu); + } - // 修改为已回答 - PaperQu qu = new PaperQu(); - qu.setQuId(reqDTO.getQuId()); - qu.setPaperId(reqDTO.getPaperId()); - qu.setIsRight(right); - qu.setAnswer(reqDTO.getAnswer()); - qu.setAnswered(true); + @Transactional(rollbackFor = Exception.class) + @Override + public void handExam(String paperId) { + + //获取试卷信息 + Paper paper = paperService.getById(paperId); - paperQuService.updateByKey(qu); + //如果不是正常的,抛出异常 + if(!PaperState.ING.equals(paper.getState())){ + throw new ServiceException(1, "试卷状态不正确!"); + } -} + // 客观分 + int objScore = paperQuService.sumObjective(paperId); + paper.setObjScore(objScore); + paper.setUserScore(objScore); -// 声明交卷的方法,使用事务管理 -/** - * 交卷的方法 - * @param paperId 试卷ID - */ -@Transactional(rollbackFor = Exception.class) -@Override -public void handExam(String paperId) { - - // 获取试卷信息 - Paper paper = paperService.getById(paperId); - - // 如果试卷状态不正确,则抛出服务异常 - if(!PaperState.ING.equals(paper.getState())){ - throw new ServiceException(1, "试卷状态不正确!"); - } + // 主观分,因为要阅卷,所以给0 + paper.setSubjScore(0); + + // 待阅卷 + if(paper.getHasSaq()) { + paper.setState(PaperState.WAIT_OPT); + }else { - // 计算客观题分数 - int objScore = paperQuService.sumObjective(paperId); - paper.setObjScore(objScore); - paper.setUserScore(objScore); + // 同步保存考试成绩 + userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore()); - // 设置主观题分数为0 - paper.setSubjScore(0); + paper.setState(PaperState.FINISHED); + } + paper.setUpdateTime(new Date()); + + //计算考试时长 + Calendar cl = Calendar.getInstance(); + cl.setTimeInMillis(System.currentTimeMillis()); + int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60); + if(userTime == 0){ + userTime = 1; + } + paper.setUserTime(userTime); - // 如果有主观题,则设置状态为待阅卷 - if(paper.getHasSaq()) { - paper.setState(PaperState.WAIT_OPT); - }else { + //更新试卷 + paperService.updateById(paper); - // 同步保存考试成绩 - userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore()); - // 设置状态为已完成 - paper.setState(PaperState.FINISHED); + // 终止定时任务 + String name = JobPrefix.BREAK_EXAM + paperId; + jobService.deleteJob(name, JobGroup.SYSTEM); + + //把打错的问题加入错题本 + List list = paperQuService.listByPaper(paperId); + for(PaperQuDTO qu: list){ + // 主观题和对的都不加入错题库 + if(qu.getIsRight()){ + continue; + } + //加入错题本 + new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run(); + } } - paper.setUpdateTime(new Date()); - - // 计算考试时长 - Calendar cl = Calendar.getInstance(); - cl.setTimeInMillis(System.currentTimeMillis()); - int userTime = (int)((System.currentTimeMillis() - paper.getCreateTime().getTime()) / 1000 / 60); - if(userTime == 0){ - userTime = 1; + + @Override + public IPage paging(PagingReqDTO reqDTO) { + return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); } - paper.setUserTime(userTime); - // 更新试卷信息 - paperService.updateById(paper); - // 终止定时任务 - String name = JobPrefix.BREAK_EXAM + paperId; - jobService.deleteJob(name, JobGroup.SYSTEM); + @Override + public PaperDTO checkProcess(String userId) { - // 把打错的问题加入错题本 - List list = paperQuService.listByPaper(paperId); - for(PaperQuDTO qu: list){ - // 主观题和对的都不加入错题库 - if(qu.getIsRight()){ - continue; - } - //加入错题本 - new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run(); - } -} + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda() + .eq(Paper::getUserId, userId) + .eq(Paper::getState, PaperState.ING); -// 声明分页查询试卷列表的方法 -/** - * 分页查询试卷列表的方法 - * @param reqDTO 分页请求DTO - * @return 返回分页响应 - */ -@Override -public IPage paging(PagingReqDTO reqDTO) { - return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); -} + Paper paper = this.getOne(wrapper, false); -// 声明检查考试进度的方法 -/** - * 检查考试进度的方法 - * @param userId 用户ID - * @return 返回试卷DTO - */ -@Override -public PaperDTO checkProcess(String userId) { - - // 构建查询条件,查询是否有正在进行的考试 - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda() - .eq(Paper::getUserId, userId) - .eq(Paper::getState, PaperState.ING); - - // 查询正在进行的考试 - Paper paper = this.getOne(wrapper, false); - - // 如果存在正在进行的考试,则返回试卷DTO - if (paper != null) { - return BeanMapper.map(paper, PaperDTO.class); - } + if (paper != null) { + return BeanMapper.map(paper, PaperDTO.class); + } - // 如果不存在正在进行的考试,则返回null - return null; + return null; + } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java b/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java index 99f62b6..07e7d76 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/controller/QuController.java @@ -1,129 +1,137 @@ -// 导入所需的包 package com.yf.exam.modules.qu.controller; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 用于构建查询条件 -import com.baomidou.mybatisplus.core.metadata.IPage; // 用于分页 -import com.google.common.collect.Lists; // 用于操作列表 -import com.yf.exam.core.api.ApiRest; // API响应封装类 -import com.yf.exam.core.api.controller.BaseController; // 基础控制器类 -import com.yf.exam.core.api.dto.BaseIdReqDTO; // 基础ID请求DTO -import com.yf.exam.core.api.dto.BaseIdRespDTO; // 基础ID响应DTO -import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 基础ID数组请求DTO -import com.yf.exam.core.api.dto.PagingReqDTO; // 分页请求DTO -import com.yf.exam.core.exception.ServiceException; // 自定义服务异常 -import com.yf.exam.core.utils.BeanMapper; // Bean映射工具 -import com.yf.exam.core.utils.excel.ExportExcel; // 导出Excel工具 -import com.yf.exam.core.utils.excel.ImportExcel; // 导入Excel工具 -import com.yf.exam.modules.qu.dto.QuDTO; // 问题DTO -import com.yf.exam.modules.qu.dto.export.QuExportDTO; // 问题导出DTO -import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; // 问题详情DTO -import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; // 问题查询请求DTO -import com.yf.exam.modules.qu.entity.Qu; // 问题实体类 -import com.yf.exam.modules.qu.service.QuService; // 问题服务类 -import io.swagger.annotations.Api; // Swagger API注释 -import io.swagger.annotations.ApiOperation; // Swagger API操作注释 -import org.apache.commons.lang3.StringUtils; // 字符串操作工具类 -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; // 用于处理Excel格式异常 -import org.apache.shiro.authz.annotation.RequiresRoles; // Shiro权限控制注解 -import org.springframework.beans.factory.annotation.Autowired; // 自动注入依赖 -import org.springframework.util.CollectionUtils; // 集合工具类 -import org.springframework.web.bind.annotation.RequestBody; // 请求体注解 -import org.springframework.web.bind.annotation.RequestMapping; // 请求映射注解 -import org.springframework.web.bind.annotation.RequestMethod; // 请求方法类型注解 -import org.springframework.web.bind.annotation.RequestParam; // 请求参数注解 -import org.springframework.web.bind.annotation.ResponseBody; // 响应体注解 -import org.springframework.web.bind.annotation.RestController; // REST控制器注解 -import org.springframework.web.multipart.MultipartFile; // 用于处理文件上传 - -import javax.servlet.http.HttpServletResponse; // 用于处理HTTP响应 -import java.io.IOException; // IO异常处理 -import java.util.Arrays; // 数组工具类 -import java.util.List; // 列表工具类 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.google.common.collect.Lists; +import com.yf.exam.core.api.ApiRest; +import com.yf.exam.core.api.controller.BaseController; +import com.yf.exam.core.api.dto.BaseIdReqDTO; +import com.yf.exam.core.api.dto.BaseIdRespDTO; +import com.yf.exam.core.api.dto.BaseIdsReqDTO; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.exception.ServiceException; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.core.utils.excel.ExportExcel; +import com.yf.exam.core.utils.excel.ImportExcel; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import com.yf.exam.modules.qu.service.QuService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.shiro.authz.annotation.RequiresRoles; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.CollectionUtils; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; /** *

* 问题题目控制器 *

-* 该控制器类负责管理题目相关的操作,包括添加、修改、删除、查询等 * * @author 聪明笨狗 * @since 2020-05-25 13:25 */ -@Api(tags={"问题题目"}) // Swagger注解,表示该控制器处理"问题题目"相关的请求 -@RestController // Spring注解,表示这是一个RESTful API控制器 -@RequestMapping("/exam/api/qu/qu") // 设置基础路径 +@Api(tags={"问题题目"}) +@RestController +@RequestMapping("/exam/api/qu/qu") public class QuController extends BaseController { @Autowired - private QuService baseService; // 自动注入问题服务类 + private QuService baseService; /** - * 添加或修改问题题目 + * 添加或修改 * - * @param reqDTO 请求的详细数据,包含问题题目的详细信息 - * @return 返回操作结果 + * @param reqDTO + * @return */ - @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 - @ApiOperation(value = "添加或修改") // Swagger注解,描述该方法的功能 - @RequestMapping(value = "/save", method = {RequestMethod.POST}) // POST请求,表示保存操作 + @RequiresRoles("sa") + @ApiOperation(value = "添加或修改") + @RequestMapping(value = "/save", method = {RequestMethod.POST}) public ApiRest save(@RequestBody QuDetailDTO reqDTO) { - baseService.save(reqDTO); // 调用服务层保存或更新问题数据 - return super.success(); // 返回成功响应 + baseService.save(reqDTO); + return super.success(); } /** - * 批量删除问题题目 + * 批量删除 * - * @param reqDTO 请求的ID数组,包含要删除的题目ID列表 - * @return 返回操作结果 + * @param reqDTO + * @return */ - @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 - @ApiOperation(value = "批量删除") // Swagger注解,描述该方法的功能 - @RequestMapping(value = "/delete", method = {RequestMethod.POST}) // POST请求,表示删除操作 + @RequiresRoles("sa") + @ApiOperation(value = "批量删除") + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - baseService.delete(reqDTO.getIds()); // 调用服务层进行批量删除 - return super.success(); // 返回成功响应 + //根据ID删除 + baseService.delete(reqDTO.getIds()); + return super.success(); } /** - * 查找问题题目详情 + * 查找详情 * - * @param reqDTO 请求的ID数据,包含要查找的题目ID - * @return 返回问题题目的详细信息 + * @param reqDTO + * @return */ - @ApiOperation(value = "查找详情") // Swagger注解,描述该方法的功能 - @RequestMapping(value = "/detail", method = {RequestMethod.POST}) // POST请求,表示获取详情操作 + @ApiOperation(value = "查找详情") + @RequestMapping(value = "/detail", method = {RequestMethod.POST}) public ApiRest detail(@RequestBody BaseIdReqDTO reqDTO) { - QuDetailDTO dto = baseService.detail(reqDTO.getId()); // 调用服务层获取问题题目详情 - return super.success(dto); // 返回问题详情 + QuDetailDTO dto = baseService.detail(reqDTO.getId()); + return super.success(dto); } /** - * 分页查询问题题目 + * 分页查找 * - * @param reqDTO 分页请求数据,包含查询条件和分页参数 - * @return 返回分页结果 + * @param reqDTO + * @return */ - @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 - @ApiOperation(value = "分页查找") // Swagger注解,描述该方法的功能 - @RequestMapping(value = "/paging", method = {RequestMethod.POST}) // POST请求,表示分页查询操作 + @RequiresRoles("sa") + @ApiOperation(value = "分页查找") + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - IPage page = baseService.paging(reqDTO); // 调用服务层进行分页查询 - return super.success(page); // 返回分页结果 + + //分页查询并转换 + IPage page = baseService.paging(reqDTO); + + return super.success(page); } + /** - * 导出问题题目的Excel文件 + * 导出excel文件 */ - @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 - @ResponseBody // 标明返回内容直接作为响应体 - @RequestMapping(value = "/export") // 导出请求路径 + @RequiresRoles("sa") + @ResponseBody + @RequestMapping(value = "/export") public ApiRest exportFile(HttpServletResponse response, @RequestBody QuQueryReqDTO reqDTO) { - String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx"; // 设置导出的文件名 + + + // 导出文件名 + String fileName = "导出的试题-" + System.currentTimeMillis() + ".xlsx"; + try { + int no = 0; String quId = ""; - List list = baseService.listForExport(reqDTO); // 获取导出数据 + List list = baseService.listForExport(reqDTO); for (QuExportDTO item : list) { if (!quId.equals(item.getQId())) { quId = item.getQId(); @@ -136,101 +144,135 @@ public class QuController extends BaseController { item.setQImage(""); item.setQVideo(""); } - item.setNo(String.valueOf(no)); // 设置题目序号 + item.setNo(String.valueOf(no)); } - new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose(); // 导出数据到Excel文件 - return super.success(); // 返回成功响应 + new ExportExcel("试题", QuExportDTO.class).setDataList(list).write(response, fileName).dispose(); + return super.success(); } catch (Exception e) { - return failure(e.getMessage()); // 捕获异常并返回失败响应 + return failure(e.getMessage()); } } /** - * 导入问题题目的Excel文件 + * 导入Excel * - * @param file 上传的Excel文件 - * @return 返回操作结果 + * @param file + * @return */ - @RequiresRoles("sa") // 限制只有角色为"sa"的用户可以访问此方法 - @ResponseBody // 标明返回内容直接作为响应体 - @RequestMapping(value = "/import") // 导入请求路径 + @RequiresRoles("sa") + @ResponseBody + @RequestMapping(value = "/import") public ApiRest importFile(@RequestParam("file") MultipartFile file) { + try { - ImportExcel ei = new ImportExcel(file, 1, 0); // 创建导入Excel对象 - List list = ei.getDataList(QuExportDTO.class); // 获取Excel中的数据列表 - this.checkExcel(list); // 校验数据 - baseService.importExcel(list); // 调用服务层进行导入操作 - return super.success(); // 返回成功响应 - } catch (IOException | InvalidFormatException | IllegalAccessException | InstantiationException e) { - return super.failure(); // 捕获各种异常并返回失败响应 + + ImportExcel ei = new ImportExcel(file, 1, 0); + List list = ei.getDataList(QuExportDTO.class); + + // 校验数据 + this.checkExcel(list); + + // 导入数据条数 + baseService.importExcel(list); + + // 导入成功 + return super.success(); + + } catch (IOException e) { + + } catch (InvalidFormatException e) { + + } catch (IllegalAccessException e) { + + } catch (InstantiationException e) { + } + + return super.failure(); } /** - * 校验Excel文件中的数据 + * 校验Excel * - * @param list 导入的题目数据列表 - * @throws ServiceException 可能抛出服务异常 + * @param list + * @throws Exception */ private void checkExcel(List list) throws ServiceException { - // 校验Excel数据的逻辑,检查每一行数据的有效性 + + // 约定第三行开始导入 int line = 3; StringBuffer sb = new StringBuffer(); + if (CollectionUtils.isEmpty(list)) { - throw new ServiceException(1, "您导入的数据似乎是一个空表格!"); // 如果表格为空,抛出异常 + throw new ServiceException(1, "您导入的数据似乎是一个空表格!"); } + Integer quNo = null; for (QuExportDTO item : list) { + + System.out.println(item.getNo()); if (StringUtils.isBlank(item.getNo())) { line++; continue; } + + System.out.println(item.getQContent()); Integer no; + try { - no = Integer.parseInt(item.getNo()); // 转换题目序号 + no = Integer.parseInt(item.getNo()); } catch (Exception e) { line++; continue; } + if (no == null) { sb.append("第" + line + "行,题目序号不能为空!
"); } - // 校验题目内容和其他字段是否为空 + if (quNo == null || !quNo.equals(no)) { + if (item.getQuType() == null) { sb.append("第" + line + "行,题目类型不能为空
"); } + if (StringUtils.isBlank(item.getQContent())) { sb.append("第" + line + "行,题目内容不能为空
"); } + if (CollectionUtils.isEmpty(item.getRepoList())) { sb.append("第" + line + "行,题目必须包含一个题库
"); } } + if (StringUtils.isBlank(item.getAIsRight())) { sb.append("第" + line + "行,选项是否正确不能为空
"); } + if (StringUtils.isBlank(item.getAContent()) && StringUtils.isBlank(item.getAImage())) { sb.append("第" + line + "行,选项内容和选项图片必须有一个不为空
"); } + quNo = no; line++; } + + // 存在错误 if (!"".equals(sb.toString())) { - throw new ServiceException(1, sb.toString()); // 如果有校验错误,抛出异常 + throw new ServiceException(1, sb.toString()); } } /** - * 下载试题导入模板 + * 下载导入试题数据模板 */ @ResponseBody - @RequestMapping(value = "import/template") // 导入模板下载路径 + @RequestMapping(value = "import/template") public ApiRest importFileTemplate(HttpServletResponse response) { try { - String fileName = "试题导入模板.xlsx"; // 设置文件名 - List list = Lists.newArrayList(); // 创建模板数据列表 - // 模板数据(包含问题内容、题型、选项等) + String fileName = "试题导入模板.xlsx"; + List list = Lists.newArrayList(); + QuExportDTO l1 = new QuExportDTO(); l1.setNo("正式导入,请删除此说明行:数字,相同的数字表示同一题的序列"); l1.setQContent("问题内容"); @@ -244,17 +286,39 @@ public class QuController extends BaseController { l1.setAIsRight("只能填写0或1,0表示否,1表示是"); l1.setAAnalysis("这个项是正确的"); - // 添加模板示例数据 + + QuExportDTO l2 = new QuExportDTO(); + l2.setQContent("找出以下可以被2整除的数(多选)"); + l2.setQAnalysis("最基本的数学题,不做过多解析"); + l2.setQuType("2"); + l2.setNo("1"); + l2.setAIsRight("1"); + l2.setAContent("数字:2"); + l2.setAAnalysis("2除以2=1,对的"); + + QuExportDTO l3 = new QuExportDTO(); + l3.setNo("1"); + l3.setAIsRight("0"); + l3.setAContent("数字:3"); + l3.setAAnalysis("3除以2=1.5,不能被整除"); + + QuExportDTO l4 = new QuExportDTO(); + l4.setNo("1"); + l4.setAIsRight("1"); + l4.setAContent("数字:6"); + l4.setAAnalysis("6除以2=3,对的"); + + + list.add(l1); list.add(l2); list.add(l3); list.add(l4); - // 导出模板文件 new ExportExcel("试题数据", QuExportDTO.class, 1).setDataList(list).write(response, fileName).dispose(); - return super.success(); // 返回成功响应 + return super.success(); } catch (Exception e) { - return super.failure("导入模板下载失败!失败信息:"+e.getMessage()); // 返回失败响应 + return super.failure("导入模板下载失败!失败信息:"+e.getMessage()); } } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java index 9a6a160..3b9c3a1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuAnswerDTO.java @@ -1,66 +1,42 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 可序列化接口 +import java.io.Serializable; /** *

* 候选答案请求类 *

* -* 该类用于封装候选答案的请求信息,包含每个答案的具体内容、是否正确、答案分析等信息。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="候选答案", description="候选答案") public class QuAnswerDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; - /** - * 答案ID - * 用于唯一标识每个候选答案,通常由数据库自动生成。 - */ - @ApiModelProperty(value = "答案ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String id; // 答案ID - /** - * 题目ID - * 该字段表示该答案对应的题目ID。 - */ - @ApiModelProperty(value = "问题ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String quId; // 题目ID + @ApiModelProperty(value = "答案ID", required=true) + private String id; - /** - * 是否正确 - * 标记该答案是否为正确答案,`true`表示正确,`false`表示错误。 - */ - @ApiModelProperty(value = "是否正确", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Boolean isRight; // 是否正确 + @ApiModelProperty(value = "问题ID", required=true) + private String quId; - /** - * 选项图片 - * 存储与该答案相关的图片URL,通常用于多媒体题目选项。 - */ - @ApiModelProperty(value = "选项图片", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String image; // 选项图片URL + @ApiModelProperty(value = "是否正确", required=true) + private Boolean isRight; - /** - * 答案内容 - * 该字段用于存储该答案的文本内容,通常为答案的描述或选项文本。 - */ - @ApiModelProperty(value = "答案内容", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String content; // 答案内容 + @ApiModelProperty(value = "选项图片", required=true) + private String image; - /** - * 答案分析 - * 用于对该答案进行详细解析,解释为什么该答案正确或错误。 - */ - @ApiModelProperty(value = "答案分析", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String analysis; // 答案分析 + @ApiModelProperty(value = "答案内容", required=true) + private String content; + + @ApiModelProperty(value = "答案分析", required=true) + private String analysis; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java index fe82154..8f45eec 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuDTO.java @@ -1,88 +1,53 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 可序列化接口 -import java.util.Date; // 日期类型 +import java.io.Serializable; +import java.util.Date; /** *

* 问题题目请求类 *

* -* 该类用于封装问题题目的基本信息,包括题目的类型、难度、内容、解析等。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="问题题目", description="问题题目") public class QuDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; - /** - * 题目ID - * 每个题目都拥有唯一的ID,用于标识题目。 - */ - @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String id; // 题目ID - /** - * 题目类型 - * 该字段用于标识题目的类型,例如选择题、填空题、判断题等。 - */ - @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Integer quType; // 题目类型 + @ApiModelProperty(value = "题目ID", required=true) + private String id; - /** - * 题目难度 - * 用于表示题目的难易程度。1表示普通,2表示较难,可能有更多级别。 - */ - @ApiModelProperty(value = "1普通,2较难", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Integer level; // 题目难度 + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; - /** - * 题目图片 - * 该字段存储与题目相关的图片URL,可以是题目内容的辅助说明。 - */ - @ApiModelProperty(value = "题目图片", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String image; // 题目图片URL + @ApiModelProperty(value = "1普通,2较难", required=true) + private Integer level; - /** - * 题目内容 - * 存储题目的具体内容,描述问题的文本部分。 - */ - @ApiModelProperty(value = "题目内容", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String content; // 题目内容 + @ApiModelProperty(value = "题目图片", required=true) + private String image; - /** - * 创建时间 - * 标识题目创建的时间,通常由系统自动生成。 - */ - @ApiModelProperty(value = "创建时间", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Date createTime; // 创建时间 + @ApiModelProperty(value = "题目内容", required=true) + private String content; - /** - * 更新时间 - * 记录题目最后一次更新时间,通常由系统自动更新。 - */ - @ApiModelProperty(value = "更新时间", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Date updateTime; // 更新时间 - /** - * 题目备注 - * 可选字段,用于记录关于题目的额外备注信息。 - */ - @ApiModelProperty(value = "题目备注", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String remark; // 题目备注 + @ApiModelProperty(value = "创建时间", required=true) + private Date createTime; - /** - * 整题解析 - * 提供该题目的完整解析,帮助用户理解解题思路及过程。 - */ - @ApiModelProperty(value = "整题解析", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String analysis; // 整题解析 + @ApiModelProperty(value = "更新时间", required=true) + private Date updateTime; + + @ApiModelProperty(value = "题目备注", required=true) + private String remark; + + @ApiModelProperty(value = "整题解析", required=true) + private String analysis; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java index 0fa058e..6e689b8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/QuRepoDTO.java @@ -1,58 +1,38 @@ package com.yf.exam.modules.qu.dto; -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 可序列化接口 +import java.io.Serializable; /** *

* 试题题库请求类 *

* -* 该类用于封装题库与题目之间的关联信息,包含题目的ID、题库ID、题目类型等信息。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="试题题库", description="试题题库") public class QuRepoDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化版本UID - - /** - * 试题ID - * 唯一标识一道试题。 - */ - private String id; // 试题ID - - /** - * 题目ID - * 与题目ID进行关联,表示该试题属于某个具体题目。 - */ - @ApiModelProperty(value = "试题", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String quId; // 题目ID - - /** - * 题库ID - * 标识该题目所属的题库。 - */ - @ApiModelProperty(value = "归属题库", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private String repoId; // 题库ID - - /** - * 题目类型 - * 表示该题目在题库中的类型,例如选择题、填空题等。 - */ - @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Integer quType; // 题目类型 - - /** - * 排序 - * 表示该题目在题库中的显示顺序,数字越小,顺序越靠前。 - */ - @ApiModelProperty(value = "排序", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Integer sort; // 排序 -} + private static final long serialVersionUID = 1L; + + + private String id; + + @ApiModelProperty(value = "试题", required=true) + private String quId; + + @ApiModelProperty(value = "归属题库", required=true) + private String repoId; + + @ApiModelProperty(value = "题目类型", required=true) + private Integer quType; + + @ApiModelProperty(value = "排序", required=true) + private Integer sort; + +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java index fff01c5..fe94dac 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuExportDTO.java @@ -1,59 +1,45 @@ package com.yf.exam.modules.qu.dto.export; -import com.yf.exam.core.utils.excel.annotation.ExcelField; // Excel导出注解 -import com.yf.exam.core.utils.excel.fieldtype.ListType; // 用于处理List类型字段的特殊注解 -import lombok.Data; // Lombok注解,用于自动生成getter、setter、toString等方法 +import com.yf.exam.core.utils.excel.annotation.ExcelField; +import com.yf.exam.core.utils.excel.fieldtype.ListType; +import lombok.Data; -import java.util.List; // 用于表示列表类型的字段 +import java.util.List; /** * 用于导出的数据结构 - * - * 该类是导出试题相关数据时所使用的DTO(数据传输对象),包含了题目序号、题目内容、题目解析、选项内容等信息。 - * 主要用于Excel导出时的数据映射。 - * * @author bool */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data public class QuExportDTO { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; /** - * 题目ID + * */ - private String qId; // 题目的唯一标识符 - - @ExcelField(title="题目序号", align=2, sort=1) // 导出Excel时的列标题和排序,align为居中对齐,sort为排序位置 - private String no; // 题目序号,表示题目的编号 - - @ExcelField(title="题目类型", align=2, sort=2) // Excel导出列的标题和排序 - private String quType; // 题目类型,可能是单选题、多选题等 - - @ExcelField(title="题目内容", align=2, sort=3) // Excel导出列的标题和排序 - private String qContent; // 题目内容,包含问题的具体描述 - - @ExcelField(title="整体解析", align=2, sort=4) // Excel导出列的标题和排序 - private String qAnalysis; // 整个题目的解析说明 - - @ExcelField(title="题目图片", align=2, sort=5) // Excel导出列的标题和排序 - private String qImage; // 题目图片,存储图片URL或路径 - - @ExcelField(title="题目视频", align=2, sort=6) // Excel导出列的标题和排序 - private String qVideo; // 题目视频,存储视频URL或路径 - - @ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class) // 题库列表,支持导出多个题库 - private List repoList; // 题目所属的题库列表 - - @ExcelField(title="是否正确项", align=2, sort=8) // Excel导出列的标题和排序 - private String aIsRight; // 是否为正确选项(0或1) - - @ExcelField(title="选项内容", align=2, sort=9) // Excel导出列的标题和排序 - private String aContent; // 选项内容,表示答案的具体内容 - - @ExcelField(title="选项解析", align=2, sort=10) // Excel导出列的标题和排序 - private String aAnalysis; // 选项解析,说明该选项的正确性或相关分析 - - @ExcelField(title="选项图片", align=2, sort=11) // Excel导出列的标题和排序 - private String aImage; // 选项图片,存储图片URL或路径 + private String qId; + + @ExcelField(title="题目序号", align=2, sort=1) + private String no; + @ExcelField(title="题目类型", align=2, sort=2) + private String quType; + @ExcelField(title="题目内容", align=2, sort=3) + private String qContent; + @ExcelField(title="整体解析", align=2, sort=4) + private String qAnalysis; + @ExcelField(title="题目图片", align=2, sort=5) + private String qImage; + @ExcelField(title="题目视频", align=2, sort=6) + private String qVideo; + @ExcelField(title="所属题库", align=2, sort=7, fieldType = ListType.class) + private List repoList; + @ExcelField(title="是否正确项", align=2, sort=8) + private String aIsRight; + @ExcelField(title="选项内容", align=2, sort=9) + private String aContent; + @ExcelField(title="选项解析", align=2, sort=10) + private String aAnalysis; + @ExcelField(title="选项图片", align=2, sort=11) + private String aImage; } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java index 79aa0fe..4ac03c0 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/export/QuImportDTO.java @@ -1,56 +1,23 @@ package com.yf.exam.modules.qu.dto.export; -import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 导入的选项答案DTO -import lombok.Data; // Lombok注解,用于自动生成getter、setter、toString等方法 +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import lombok.Data; -import java.util.List; // 用于表示列表类型的字段 +import java.util.List; /** * 用于导出的数据结构 - * - * 该类用于导入试题数据时的DTO(数据传输对象),包含了题目类型、题目内容、解析、题目图片等信息。 - * 同时还包含了该题目的多个答案选项。 - * * @author bool */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data public class QuImportDTO { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; - /** - * 题目类型 - * 例如:1代表单选题,2代表多选题,3代表判断题,4代表主观题等 - */ - private String quType; // 题目类型,表示题目的类别 - - /** - * 题目内容 - * 例如:问题的具体描述 - */ - private String qContent; // 题目内容,表示题目的实际问题 - - /** - * 题目解析 - * 例如:题目解析或解释说明 - */ - private String qAnalysis; // 题目解析,解释题目的答案或相关说明 - - /** - * 题目图片 - * 例如:题目相关的图片URL - */ - private String qImage; // 题目图片,存储图片URL或路径 - - /** - * 题库名称 - * 例如:题目所属的题库名称 - */ - private String repoName; // 题目所属的题库名称 - - /** - * 答案选项列表 - * 该字段存储了该题目的多个答案选项及其相关信息。 - */ - private List answerList; // 答案选项列表,包含该题目的所有答案选项 + private String quType; + private String qContent; + private String qAnalysis; + private String qImage; + private String repoName; + private List answerList; } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java index 0035a89..b36a4e8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/ext/QuDetailDTO.java @@ -1,43 +1,33 @@ package com.yf.exam.modules.qu.dto.ext; -import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 引入选项答案DTO -import com.yf.exam.modules.qu.dto.QuDTO; // 引入问题题目DTO -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.dto.QuDTO; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.util.List; // 用于表示列表类型的字段 +import java.util.List; /** *

* 问题题目请求类 *

* -* 该类用于表示问题的详细信息,继承自 `QuDTO`,包括题目的详细信息如备选项、题库列表等。 -* 主要用于在前后端交互时,传递包含问题详细信息的请求或响应数据。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="问题题目详情", description="问题题目详情") public class QuDetailDTO extends QuDTO { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; - /** - * 备选项列表 - * 该字段包含了该题目的所有答案选项列表。 - * 每个选项都包含了选项内容、是否为正确答案、解析等信息。 - */ - @ApiModelProperty(value = "备选项列表", required=true) // Swagger注解,用于生成文档 - private List answerList; // 备选项列表,包含该题目的所有答案选项 + + @ApiModelProperty(value = "备选项列表", required=true) + private List answerList; + + @ApiModelProperty(value = "题库列表", required=true) + private List repoIds; - /** - * 题库列表 - * 该字段包含了该题目所属的多个题库ID。 - * 用于标识该题目属于哪些题库,可能有多个题库关联。 - */ - @ApiModelProperty(value = "题库列表", required=true) // Swagger注解,用于生成文档 - private List repoIds; // 题库列表,存储题库ID的列表 + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java index 989cb8e..a927e9e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuQueryReqDTO.java @@ -1,54 +1,38 @@ package com.yf.exam.modules.qu.dto.request; -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 可序列化接口 -import java.util.List; // 用于表示列表类型的字段 +import java.io.Serializable; +import java.util.List; /** *

* 问题题目请求类 *

* -* 该类用于封装前端请求查询题目的参数。通过该请求类,前端可以传递多个查询条件, -* 如题目类型、题库ID、题目内容等,以便进行题目的筛选和查询。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="题目查询请求类", description="题目查询请求类") public class QuQueryReqDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化版本UID - - /** - * 题目类型 - * 用于指定查询的题目类型。例如,单选题、多选题、判断题等。 - */ - @ApiModelProperty(value = "题目类型") // Swagger注解,描述字段信息 - private Integer quType; // 题目类型,通常是数字表示不同题型 - - /** - * 归属题库 - * 用于指定题目所属的题库ID列表。如果该字段不为空,查询会限制在指定的题库中。 - */ - @ApiModelProperty(value = "归属题库") // Swagger注解,描述字段信息 - private List repoIds; // 题库ID列表,题目可以归属于多个题库 - - /** - * 题目内容 - * 用于进行模糊查询,匹配包含特定内容的题目。 - */ - @ApiModelProperty(value = "题目内容") // Swagger注解,描述字段信息 - private String content; // 题目内容,支持模糊查询 - - /** - * 排除ID列表 - * 用于指定在查询中排除的题目ID列表,这些ID的题目不会出现在查询结果中。 - */ - @ApiModelProperty(value = "排除ID列表") // Swagger注解,描述字段信息 - private List excludes; // 排除的题目ID列表 + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题目类型") + private Integer quType; + + @ApiModelProperty(value = "归属题库") + private List repoIds; + + @ApiModelProperty(value = "题目内容") + private String content; + + @ApiModelProperty(value = "排除ID列表") + private List excludes; + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java index 0628495..3ca148d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/dto/request/QuRepoBatchReqDTO.java @@ -1,47 +1,34 @@ package com.yf.exam.modules.qu.dto.request; -import io.swagger.annotations.ApiModel; // Swagger注解,用于生成API文档 -import io.swagger.annotations.ApiModelProperty; // Swagger注解,用于描述API模型的属性 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; -import java.io.Serializable; // 可序列化接口 -import java.util.List; // 用于表示列表类型的字段 +import java.io.Serializable; +import java.util.List; /** *

-* 试题题库批量操作请求类 +* 问题题目请求类 *

* -* 该类用于封装前端请求批量操作题目和题库关联的参数。 -* 通过该请求类,前端可以执行批量新增或移除题目与题库的关联操作。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 +@Data @ApiModel(value="试题题库批量操作类", description="试题题库批量操作类") public class QuRepoBatchReqDTO implements Serializable { - private static final long serialVersionUID = 1L; // 序列化版本UID - - /** - * 题目ID列表 - * 用于指定要操作的题目ID集合,可以是多个题目。 - */ - @ApiModelProperty(value = "题目ID", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private List quIds; // 要操作的题目ID列表 - - /** - * 题库ID列表 - * 用于指定题目与之关联的题库ID集合,可以是多个题库。 - */ - @ApiModelProperty(value = "题目类型", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private List repoIds; // 题库ID列表 - - /** - * 是否移除标志 - * 如果为 `true`,表示从题库中移除题目;如果为 `false`,表示新增题目到题库中。 - */ - @ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true) // Swagger注解,描述字段信息,标明该字段是必填项 - private Boolean remove; // `true`表示移除,`false`表示新增 + private static final long serialVersionUID = 1L; + + + @ApiModelProperty(value = "题目ID", required=true) + private List quIds; + + @ApiModelProperty(value = "题目类型", required=true) + private List repoIds; + + @ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true) + private Boolean remove; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java index ccb4579..2380cdc 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/Qu.java @@ -1,85 +1,75 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 -import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 -import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 -import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 -import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; -import java.util.Date; // 日期类型 +import java.util.Date; /** *

* 问题题目实体类 *

* -* 该类用于映射问题题目的数据结构,通过MyBatis-Plus框架进行数据库操作。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 -@TableName("el_qu") // MyBatis Plus注解,指定与数据库表的映射关系 +@Data +@TableName("el_qu") public class Qu extends Model { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; /** * 题目ID - * 主键,唯一标识一道题目。 */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID - private String id; // 题目ID + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** * 题目类型 - * 表示该题目是选择题、判断题等类型。 */ - @TableField("qu_type") // MyBatis Plus注解,指定字段名与数据库表字段名映射 - private Integer quType; // 题目类型 + @TableField("qu_type") + private Integer quType; /** - * 题目难度 - * 1表示普通,2表示较难。 + * 1普通,2较难 */ - private Integer level; // 题目难度,1普通,2较难 + private Integer level; /** * 题目图片 - * 题目相关的图片资源,存储图片URL或路径。 */ - private String image; // 题目图片 + private String image; /** * 题目内容 - * 存储题目的实际内容,例如选择题或填空题的文本。 */ - private String content; // 题目内容 + private String content; /** * 创建时间 - * 记录该题目创建的时间戳。 */ - @TableField("create_time") // MyBatis Plus注解,映射数据库中的字段 - private Date createTime; // 创建时间 + @TableField("create_time") + private Date createTime; /** * 更新时间 - * 记录该题目最后更新时间戳。 */ - @TableField("update_time") // MyBatis Plus注解,映射数据库中的字段 - private Date updateTime; // 更新时间 + @TableField("update_time") + private Date updateTime; /** * 题目备注 - * 对题目附加的说明或备注。 */ - private String remark; // 题目备注 + private String remark; /** * 整题解析 - * 对该题目的详细解析,包括答案解析、解题思路等。 */ - private String analysis; // 整题解析 + private String analysis; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java index 6c01005..45e9bf4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuAnswer.java @@ -1,64 +1,58 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 -import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 -import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 -import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 -import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; /** *

* 候选答案实体类 *

* -* 该类用于映射候选答案的数据结构,通过MyBatis-Plus框架进行数据库操作。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 -@TableName("el_qu_answer") // MyBatis Plus注解,指定与数据库表的映射关系 +@Data +@TableName("el_qu_answer") public class QuAnswer extends Model { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; /** * 答案ID - * 主键,唯一标识一个答案。 */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID - private String id; // 答案ID + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** * 问题ID - * 关联的题目ID,表示这个答案是属于哪道题目的。 */ - @TableField("qu_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 - private String quId; // 问题ID + @TableField("qu_id") + private String quId; /** * 是否正确 - * 该答案是否为正确答案,true表示正确,false表示错误。 */ - @TableField("is_right") // MyBatis Plus注解,映射数据库中的字段 - private Boolean isRight; // 是否正确 + @TableField("is_right") + private Boolean isRight; /** * 选项图片 - * 答案相关的图片资源,存储图片URL或路径。 */ - private String image; // 选项图片 + private String image; /** * 答案内容 - * 存储该选项的文本内容。 */ - private String content; // 答案内容 + private String content; + /** * 答案分析 - * 对该答案的详细分析,包括为什么是正确或错误的解析。 */ - private String analysis; // 答案分析 + private String analysis; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java index aa26d34..baade9a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/entity/QuRepo.java @@ -1,59 +1,50 @@ package com.yf.exam.modules.qu.entity; -import com.baomidou.mybatisplus.annotation.IdType; // MyBatis Plus注解,指定ID生成策略 -import com.baomidou.mybatisplus.annotation.TableField; // MyBatis Plus注解,指定字段映射 -import com.baomidou.mybatisplus.annotation.TableId; // MyBatis Plus注解,指定主键字段 -import com.baomidou.mybatisplus.annotation.TableName; // MyBatis Plus注解,指定表名 -import com.baomidou.mybatisplus.extension.activerecord.Model; // MyBatis Plus扩展的活动记录模式类 -import lombok.Data; // Lombok注解,用于自动生成getter、setter等方法 +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.activerecord.Model; +import lombok.Data; /** *

* 试题题库实体类 *

* -* 该类用于映射试题和题库之间的关系,表示一道题目属于某个题库,并可能具有排序。 -* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Data // Lombok注解,自动生成getter、setter等方法 -@TableName("el_qu_repo") // MyBatis Plus注解,指定与数据库表的映射关系 +@Data +@TableName("el_qu_repo") public class QuRepo extends Model { - private static final long serialVersionUID = 1L; // 序列化版本UID + private static final long serialVersionUID = 1L; - /** - * 试题题库关系ID - * 主键,唯一标识一条题目与题库的关联记录。 - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis Plus注解,指定主键生成策略为自定义ID - private String id; // 试题题库关系ID + @TableId(value = "id", type = IdType.ASSIGN_ID) + private String id; /** - * 试题ID - * 关联的题目ID,表示某道题目属于哪个题库。 + * 试题 */ - @TableField("qu_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 - private String quId; // 试题ID + @TableField("qu_id") + private String quId; /** - * 题库ID - * 关联的题库ID,表示该题目属于哪个题库。 + * 归属题库 */ - @TableField("repo_id") // MyBatis Plus注解,指定字段名与数据库表字段名映射 - private String repoId; // 题库ID + @TableField("repo_id") + private String repoId; /** * 题目类型 - * 用于描述该题目所属的类型(例如:选择题、填空题等)。 */ - @TableField("qu_type") // MyBatis Plus注解,映射数据库中的字段 - private Integer quType; // 题目类型 + @TableField("qu_type") + private Integer quType; /** * 排序 - * 用于对题库中的题目进行排序。 */ - private Integer sort; // 排序 + private Integer sort; + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java b/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java index 4e5f342..70e2ee1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/enums/QuType.java @@ -1,10 +1,8 @@ package com.yf.exam.modules.qu.enums; + /** - * 题目类型接口 - * - * 该接口定义了不同类型的题目标识常量,适用于题库系统中对题目类型的区分。 - * + * 题目类型 * @author bool * @date 2019-10-30 13:11 */ @@ -12,19 +10,16 @@ public interface QuType { /** * 单选题 - * 表示一道题目是单选题,用户只能选择一个答案。 */ Integer RADIO = 1; /** * 多选题 - * 表示一道题目是多选题,用户可以选择多个答案。 */ Integer MULTI = 2; /** * 判断题 - * 表示一道题目是判断题,通常是选择“正确”或“错误”两种答案。 */ Integer JUDGE = 3; diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java index 5fb575e..23699ce 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuAnswerMapper.java @@ -4,13 +4,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.yf.exam.modules.qu.entity.QuAnswer; /** - *

- * 候选答案Mapper - *

- * - * @author 聪明笨狗 - * @since 2020-05-25 13:23 - */ +*

+* 候选答案Mapper +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ public interface QuAnswerMapper extends BaseMapper { } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java index 2ab579e..14069a2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuMapper.java @@ -1,15 +1,15 @@ -package com.yf.exam.modules.qu.mapper; // 定义包名,用于存放与问题题目相关的 Mapper 类 +package com.yf.exam.modules.qu.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper,用于提供通用的 CRUD 方法 -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入分页接口 IPage,用于处理分页结果 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入分页插件的 Page 类,用于分页查询 -import com.yf.exam.modules.qu.dto.QuDTO; // 导入 QuDTO 数据传输对象,用于封装题目数据 -import com.yf.exam.modules.qu.dto.export.QuExportDTO; // 导入 QuExportDTO 用于题目导出的数据结构 -import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; // 导入 QuQueryReqDTO 用于封装查询条件 -import com.yf.exam.modules.qu.entity.Qu; // 导入 Qu 实体类,表示题目表的对应数据 -import org.apache.ibatis.annotations.Param; // 导入 MyBatis 的 Param 注解,用于 SQL 查询中的参数传递 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yf.exam.modules.qu.dto.QuDTO; +import com.yf.exam.modules.qu.dto.export.QuExportDTO; +import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import org.apache.ibatis.annotations.Param; -import java.util.List; // 导入 List,用于返回多个对象的集合 +import java.util.List; /** *

@@ -19,34 +19,38 @@ import java.util.List; // 导入 List,用于返回多个对象的集合 * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -public interface QuMapper extends BaseMapper { // QuMapper 继承自 BaseMapper,提供基本的 CRUD 操作 +public interface QuMapper extends BaseMapper { + + /** * 随机抽取题库的数据 - * @param repoId 题库ID - * @param quType 题目类型 - * @param level 题目难度 + * @param repoId + * @param quType + * @param level * @param excludes 要排除的ID列表 - * @param size 抽取题目的数量 - * @return 随机抽取的题目列表 + * @param size + * @return */ - List listByRandom(@Param("repoId") String repoId, // 题库ID - @Param("quType") Integer quType, // 题目类型 - @Param("excludes") List excludes, // 要排除的题目ID列表 - @Param("size") Integer size); // 抽取的题目数量 + List listByRandom(@Param("repoId") String repoId, + @Param("quType") Integer quType, + @Param("excludes") List excludes, + @Param("size") Integer size); /** * 查找导出列表 - * @param query 查询条件对象 - * @return 返回符合条件的题目列表,用于导出 + * @param query + * @return */ - List listForExport(@Param("query") QuQueryReqDTO query); // 根据查询条件查找导出数据 + List listForExport(@Param("query") QuQueryReqDTO query); /** * 分页查找 - * @param page 分页参数,包含当前页和每页大小 - * @param query 查询条件对象 - * @return 返回分页的题目数据 + * @param page + * @param query + * @return */ - IPage paging(Page page, @Param("query") QuQueryReqDTO query); // 分页查询题目数据,返回 QuDTO 类型的数据 + IPage paging(Page page, @Param("query") QuQueryReqDTO query); + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java index 84fa2cb..1015448 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/mapper/QuRepoMapper.java @@ -1,7 +1,7 @@ -package com.yf.exam.modules.qu.mapper; // 定义包名,用于存放与试题题库相关的 Mapper 类 +package com.yf.exam.modules.qu.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper,用于提供通用的 CRUD 方法 -import com.yf.exam.modules.qu.entity.QuRepo; // 导入 QuRepo 实体类,表示试题题库表的数据 +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.yf.exam.modules.qu.entity.QuRepo; /** *

@@ -11,5 +11,6 @@ import com.yf.exam.modules.qu.entity.QuRepo; // 导入 QuRepo 实体类,表示 * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -public interface QuRepoMapper extends BaseMapper { // QuRepoMapper 继承自 BaseMapper,提供基本的 CRUD 操作 +public interface QuRepoMapper extends BaseMapper { + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java index f6329f5..4062e95 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuAnswerService.java @@ -10,7 +10,7 @@ import java.util.List; /** *

-* 候选答案业务类接口,定义了与试题答案相关的业务操作 +* 候选答案业务类 *

* * @author 聪明笨狗 @@ -19,30 +19,30 @@ import java.util.List; public interface QuAnswerService extends IService { /** - * 分页查询答案数据 - * @param reqDTO 请求的分页和查询参数 - * @return 分页的答案数据 + * 分页查询数据 + * @param reqDTO + * @return */ IPage paging(PagingReqDTO reqDTO); /** - * 根据题目ID查询答案,并进行随机排序 - * @param quId 题目ID - * @return 随机排序后的答案列表 + * 根据题目ID查询答案并随机 + * @param quId + * @return */ List listAnswerByRandom(String quId); /** - * 根据题目ID查询所有的答案 - * @param quId 题目ID - * @return 该题目的答案列表 + * 根据问题查找答案 + * @param quId + * @return */ List listByQu(String quId); /** - * 保存所有选项数据 - * @param quId 题目ID - * @param list 题目的所有答案选项 + * 保存试题 + * @param quId + * @param list */ void saveAll(String quId, List list); } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java index a53ebb1..f528759 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuRepoService.java @@ -1,66 +1,59 @@ -// 定义包名,表示该接口属于com.yf.exam.modules.qu.service包下 package com.yf.exam.modules.qu.service; -// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; -// 导入MyBatis Plus框架的服务接口 import com.baomidou.mybatisplus.extension.service.IService; -// 导入项目中定义的分页请求DTO类 import com.yf.exam.core.api.dto.PagingReqDTO; -// 导入项目中定义的题库DTO类 import com.yf.exam.modules.qu.dto.QuRepoDTO; -// 导入项目中定义的批量请求DTO类 import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; -// 导入项目中定义的题库实体类 import com.yf.exam.modules.qu.entity.QuRepo; -// 导入Java.util包下的List接口,用于操作列表 + import java.util.List; /** - *

- * 试题题库业务接口,定义了题库相关的业务操作 - *

- * - * @author 聪明笨狗 - * @since 2020-05-25 13:23 - */ +*

+* 试题题库业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ public interface QuRepoService extends IService { /** - * 分页查询题库数据的方法 - * @param reqDTO 分页请求DTO,包含分页信息和查询条件 - * @return 返回分页响应,包含题库数据和分页信息 - */ + * 分页查询数据 + * @param reqDTO + * @return + */ IPage paging(PagingReqDTO reqDTO); /** - * 保存全部列表的方法,用于保存题目与题库的关系 - * @param quId 题目ID - * @param quType 题目类型 - * @param ids 题库ID列表 + * 保存全部列表 + * @param quId + * @param quType + * @param ids */ void saveAll(String quId, Integer quType, List ids); /** - * 根据题目查找题库的方法 - * @param quId 题目ID - * @return 返回与题目关联的题库ID列表 + * 根据问题查找题库 + * @param quId + * @return */ List listByQu(String quId); /** - * 根据题库查找题目ID列表的方法 - * @param repoId 题库ID - * @param quType 题目类型 - * @param rand 是否随机选择 - * @return 返回题目ID列表 + * 根据题库查找题目ID列表 + * @param repoId + * @param quType + * @param rand + * @return */ List listByRepo(String repoId, Integer quType, boolean rand); /** - * 批量操作的方法,用于执行批量业务操作 - * @param reqDTO 批量请求DTO,包含批量操作信息 + * 批量操作 + * @param reqDTO */ void batchAction(QuRepoBatchReqDTO reqDTO); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java index 51fe835..81f43b0 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/QuService.java @@ -1,55 +1,46 @@ -// 定义包名,表示该接口属于com.yf.exam.modules.qu.service包下 package com.yf.exam.modules.qu.service; -// 导入MyBatis Plus框架的分页功能相关类 import com.baomidou.mybatisplus.core.metadata.IPage; -// 导入MyBatis Plus框架的服务接口 import com.baomidou.mybatisplus.extension.service.IService; -// 导入项目中定义的分页请求DTO类 import com.yf.exam.core.api.dto.PagingReqDTO; -// 导入项目中定义的题目DTO类 import com.yf.exam.modules.qu.dto.QuDTO; -// 导入项目中定义的题目导出DTO类 import com.yf.exam.modules.qu.dto.export.QuExportDTO; -// 导入项目中定义的扩展题目详情DTO类 import com.yf.exam.modules.qu.dto.ext.QuDetailDTO; -// 导入项目中定义的题目查询请求DTO类 import com.yf.exam.modules.qu.dto.request.QuQueryReqDTO; -// 导入项目中定义的题目实体类 import com.yf.exam.modules.qu.entity.Qu; -// 导入Java.util包下的List接口,用于操作列表 + import java.util.List; /** - *

- * 问题题目业务接口,定义了题目相关的业务操作 - *

- * - * @author 聪明笨狗 - * @since 2020-05-25 13:23 - */ +*

+* 问题题目业务类 +*

+* +* @author 聪明笨狗 +* @since 2020-05-25 13:23 +*/ public interface QuService extends IService { /** - * 分页查询题目数据的方法 - * @param reqDTO 分页请求DTO,包含分页信息和查询条件 - * @return 返回分页响应,包含题目数据和分页信息 + * 分页查询数据 + * @param reqDTO + * @return */ IPage paging(PagingReqDTO reqDTO); /** - * 删除题目的方法 - * @param ids 题目ID列表 + * 删除试题 + * @param ids */ void delete(List ids); /** - * 随机抽取题库中的数据的方法 - * @param repoId 题库ID - * @param quType 题目类型 + * 随机抽取题库的数据 + * @param repoId + * @param quType * @param excludes 要排除的ID列表 - * @param size 抽取的数量 - * @return 返回随机抽取的题目列表 + * @param size + * @return */ List listByRandom(String repoId, Integer quType, @@ -57,29 +48,29 @@ public interface QuService extends IService { Integer size); /** - * 查询题目详情的方法 - * @param id 题目ID - * @return 返回题目详情DTO + * 问题详情 + * @param id + * @return */ QuDetailDTO detail(String id); /** - * 保存题目的方法 - * @param reqDTO 题目详情DTO + * 保存试题 + * @param reqDTO */ void save(QuDetailDTO reqDTO); /** - * 查找导出列表的方法 - * @param query 题目查询请求DTO - * @return 返回题目导出列表 + * 查找导出列表 + * @param query + * @return */ List listForExport(QuQueryReqDTO query); /** - * 导入Excel数据的方法 - * @param dtoList 题目导出DTO列表 - * @return 返回导入的结果,影响的行数 + * 导入Excel + * @param dtoList + * @return */ int importExcel(List dtoList); -} \ No newline at end of file +} diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java index 1c31577..2fd66cf 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuAnswerServiceImpl.java @@ -1,24 +1,24 @@ -package com.yf.exam.modules.qu.service.impl; // 定义包名,表示这是实现类部分,专注于处理与试题答案相关的逻辑 - -import com.alibaba.fastjson.JSON; // 导入 fastjson 库,用于 JSON 序列化和反序列化 -import com.alibaba.fastjson.TypeReference; // 导入 fastjson 库的 TypeReference,用于处理泛型类型 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构造查询条件 -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页 Page 类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 基类 -import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象类 -import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象之间的映射 -import com.yf.exam.modules.qu.dto.QuAnswerDTO; // 导入试题答案的 DTO 类 -import com.yf.exam.modules.qu.entity.QuAnswer; // 导入试题答案的实体类 -import com.yf.exam.modules.qu.mapper.QuAnswerMapper; // 导入试题答案的 Mapper 接口 -import com.yf.exam.modules.qu.service.QuAnswerService; // 导入试题答案的服务接口 -import com.yf.exam.modules.qu.utils.ImageCheckUtils; // 导入图片校验工具类 -import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 的注解,自动注入依赖 -import org.springframework.stereotype.Service; // 导入 Spring 的服务注解,标识这是一个服务类 -import org.springframework.util.CollectionUtils; // 导入 Spring 的集合工具类,用于检查集合是否为空 - -import java.util.ArrayList; // 导入 ArrayList,用于动态数组 -import java.util.List; // 导入 List 接口,作为列表类型 +package com.yf.exam.modules.qu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.core.utils.BeanMapper; +import com.yf.exam.modules.qu.dto.QuAnswerDTO; +import com.yf.exam.modules.qu.entity.QuAnswer; +import com.yf.exam.modules.qu.mapper.QuAnswerMapper; +import com.yf.exam.modules.qu.service.QuAnswerService; +import com.yf.exam.modules.qu.utils.ImageCheckUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; /** *

@@ -28,77 +28,65 @@ import java.util.List; // 导入 List 接口,作为列表类型 * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Service // 表示这是一个服务类,Spring 会自动扫描并管理该类 +@Service public class QuAnswerServiceImpl extends ServiceImpl implements QuAnswerService { @Autowired - private ImageCheckUtils imageCheckUtils; // 自动注入图片校验工具类,用于校验图片地址是否合法 + private ImageCheckUtils imageCheckUtils; @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象,传入当前页和每页大小 + + //创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - // 创建查询条件包装器 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - // 执行分页查询,获取分页结果 + //获得数据 IPage page = this.page(query, wrapper); - - // 将查询结果转换为 QuAnswerDTO 类型的分页结果 + //转换结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); return pageData; - } + } @Override public List listAnswerByRandom(String quId) { - // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); - // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); - // 使用 SQL 的随机排序来随机获取答案 wrapper.last(" ORDER BY RAND() "); - // 执行查询并返回结果 return this.list(wrapper); } @Override public List listByQu(String quId) { - // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper<>(); - // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); - // 执行查询,获取答案列表 List list = this.list(wrapper); if(!CollectionUtils.isEmpty(list)){ - // 将 QuAnswer 实体对象列表转换为 QuAnswerDTO 对象列表 return BeanMapper.mapList(list, QuAnswerDTO.class); } - // 如果没有找到记录,返回 null return null; } + /** * 查找已存在的列表 - * @param quId 试题ID - * @return 已存在答案的 ID 列表 + * @param quId + * @return */ public List findExistsList(String quId) { - // 创建空的结果列表 + //返回结果 List ids = new ArrayList<>(); - // 创建查询条件包装器 QueryWrapper wrapper = new QueryWrapper(); - // 设置查询条件,过滤出与 quId 相同的记录 wrapper.lambda().eq(QuAnswer::getQuId, quId); - // 执行查询,获取答案列表 List list = this.list(wrapper); if (!CollectionUtils.isEmpty(list)) { - // 将已有的答案 ID 添加到结果列表 for (QuAnswer item : list) { ids.add(item.getId()); } @@ -108,49 +96,49 @@ public class QuAnswerServiceImpl extends ServiceImpl i @Override public void saveAll(String quId, List list) { - // 创建保存的答案列表 + + //最终要保存的列表 List saveList = new ArrayList<>(); - // 获取已有的答案 ID 列表 + //已存在的标签列表 List ids = this.findExistsList(quId); - // 如果答案列表不为空,则进行处理 if(!CollectionUtils.isEmpty(list)){ for(QuAnswerDTO item: list){ - // 校验选项图片地址是否合法 + // 校验图片地址 imageCheckUtils.checkImage(item.getImage(), "选项图片地址错误!"); - // 获取答案 ID + //标签ID String id = item.getId(); QuAnswer answer = new QuAnswer(); - // 将 DTO 转换为实体类 BeanMapper.copy(item, answer); - answer.setQuId(quId); // 设置试题 ID + answer.setQuId(quId); - // 如果该答案已存在,则从 IDs 列表中移除 + //补全ID避免新增 if(ids.contains(id)){ ids.remove(id); } - // 添加答案到保存列表 saveList.add(answer); } - // 如果有待保存的答案,则批量保存或更新 + //保存标签列表 if(!CollectionUtils.isEmpty(saveList)) { this.saveOrUpdateBatch(saveList); } - // 如果有被移除的答案,则批量删除 + //删除已移除 if(!ids.isEmpty()){ this.removeByIds(ids); } }else{ - // 如果答案列表为空,则删除所有与该试题 ID 相关的答案 + QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuAnswer::getQuId, quId); this.remove(wrapper); } } + + } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java index c0e8f29..b7de030 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuRepoServiceImpl.java @@ -1,182 +1,175 @@ -package com.yf.exam.modules.qu.service.impl; // 定义包名,表示这是服务实现类,负责处理与试题题库相关的业务逻辑 - -import com.alibaba.fastjson.JSON; // 导入 fastjson 库,用于 JSON 序列化和反序列化 -import com.alibaba.fastjson.TypeReference; // 导入 fastjson 库的 TypeReference,用于处理泛型类型 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构造查询条件 -import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页 Page 类 -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 基类 -import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象类 -import com.yf.exam.modules.qu.dto.QuRepoDTO; // 导入试题题库的 DTO 类 -import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; // 导入试题题库批量操作请求类 -import com.yf.exam.modules.qu.entity.Qu; // 导入试题实体类 -import com.yf.exam.modules.qu.entity.QuRepo; // 导入试题题库实体类 -import com.yf.exam.modules.qu.mapper.QuMapper; // 导入试题的 Mapper 接口 -import com.yf.exam.modules.qu.mapper.QuRepoMapper; // 导入试题题库的 Mapper 接口 -import com.yf.exam.modules.qu.service.QuRepoService; // 导入试题题库服务接口 -import com.yf.exam.modules.repo.service.RepoService; // 导入题库服务接口 -import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 的注解,自动注入依赖 -import org.springframework.stereotype.Service; // 导入 Spring 的服务注解,标识这是一个服务类 -import org.springframework.util.CollectionUtils; // 导入 Spring 的集合工具类,用于检查集合是否为空 - -import java.util.ArrayList; // 导入 ArrayList,用于动态数组 -import java.util.List; // 导入 List 接口,作为列表类型 +package com.yf.exam.modules.qu.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yf.exam.core.api.dto.PagingReqDTO; +import com.yf.exam.modules.qu.dto.QuRepoDTO; +import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; +import com.yf.exam.modules.qu.entity.Qu; +import com.yf.exam.modules.qu.entity.QuRepo; +import com.yf.exam.modules.qu.mapper.QuMapper; +import com.yf.exam.modules.qu.mapper.QuRepoMapper; +import com.yf.exam.modules.qu.service.QuRepoService; +import com.yf.exam.modules.repo.service.RepoService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; /** *

-* 试题题库 服务实现类 +* 语言设置 服务实现类 *

* * @author 聪明笨狗 * @since 2020-05-25 13:23 */ -@Service // 表示这是一个 Spring 服务类,Spring 会自动扫描并管理该类 +@Service public class QuRepoServiceImpl extends ServiceImpl implements QuRepoService { + @Autowired - private QuMapper quMapper; // 自动注入试题的 Mapper 接口 + private QuMapper quMapper; @Autowired - private RepoService repoService; // 自动注入题库服务接口 + private RepoService repoService; @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象,传入当前页和每页大小 + + //创建分页对象 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - // 创建查询条件包装器 + //查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - // 执行分页查询,获取分页结果 + //获得数据 IPage page = this.page(query, wrapper); - - // 将查询结果转换为 QuRepoDTO 类型的分页结果 + //转换结果 IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); return pageData; - } + } @Override public void saveAll(String quId, Integer quType, List ids) { - // 先删除已有的试题题库记录 + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getQuId, quId); this.remove(wrapper); - // 如果题库 ID 列表不为空,保存新的记录 + // 保存全部 if(!CollectionUtils.isEmpty(ids)){ List list = new ArrayList<>(); for(String id: ids){ QuRepo ref = new QuRepo(); - ref.setQuId(quId); // 设置试题 ID - ref.setRepoId(id); // 设置题库 ID - ref.setQuType(quType); // 设置题目类型 + ref.setQuId(quId); + ref.setRepoId(id); + ref.setQuType(quType); list.add(ref); } - // 批量保存试题题库记录 this.saveBatch(list); - // 对每个题库进行排序 + for(String id: ids){ this.sortRepo(id); } } + + } @Override public List listByQu(String quId) { - // 根据试题 ID 查找题库记录 + // 先删除 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getQuId, quId); List list = this.list(wrapper); List ids = new ArrayList<>(); if(!CollectionUtils.isEmpty(list)){ - // 提取题库 ID 列表 for(QuRepo item: list){ ids.add(item.getRepoId()); } } - return ids; // 返回题库 ID 列表 + return ids; } @Override public List listByRepo(String repoId, Integer quType, boolean rand) { - // 根据题库 ID 和题目类型查询题库记录 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(QuRepo::getRepoId, repoId); + wrapper.lambda() + .eq(QuRepo::getRepoId, repoId); - // 如果有题目类型,添加过滤条件 - if(quType != null){ + if(quType!=null){ wrapper.lambda().eq(QuRepo::getQuType, quType); } - // 根据是否需要随机排序决定排序方式 if(rand){ - wrapper.orderByAsc(" RAND() "); // 随机排序 + wrapper.orderByAsc(" RAND() "); }else{ - wrapper.lambda().orderByAsc(QuRepo::getSort); // 按照排序字段排序 + wrapper.lambda().orderByAsc(QuRepo::getSort); } - // 执行查询,获取题库记录列表 List list = this.list(wrapper); List ids = new ArrayList<>(); if(!CollectionUtils.isEmpty(list)){ - // 提取试题 ID 列表 for(QuRepo item: list){ ids.add(item.getQuId()); } } - return ids; // 返回试题 ID 列表 + return ids; } @Override public void batchAction(QuRepoBatchReqDTO reqDTO) { - // 如果需要移除记录 - if(reqDTO.getRemove() != null && reqDTO.getRemove()){ - // 删除满足条件的题库记录 + + // 移除的 + if(reqDTO.getRemove()!=null && reqDTO.getRemove()){ QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() .in(QuRepo::getRepoId, reqDTO.getRepoIds()) .in(QuRepo::getQuId, reqDTO.getQuIds()); this.remove(wrapper); }else{ - // 如果是新增记录,处理新增逻辑 + + // 新增的 for(String quId : reqDTO.getQuIds()){ - // 根据试题 ID 查询试题类型 Qu q = quMapper.selectById(quId); - // 保存新的题库记录 this.saveAll(quId, q.getQuType(), reqDTO.getRepoIds()); } } - // 对每个题库进行排序 for(String id: reqDTO.getRepoIds()){ this.sortRepo(id); } + } + /** * 单个题库进行排序 - * @param repoId 题库 ID + * @param repoId */ private void sortRepo(String repoId){ - // 查询题库下的所有试题 + QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(QuRepo::getRepoId, repoId); - List list = this.list(wrapper); - // 如果题库下没有试题,返回 + List list = this.list(wrapper); if(CollectionUtils.isEmpty(list)){ return; } - // 按照顺序设置每个试题的排序值 int sort = 1; for(QuRepo item: list){ item.setSort(sort); sort++; } - - // 批量更新排序值 this.updateBatchById(list); } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java index 3594ff6..f9ae656 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/service/impl/QuServiceImpl.java @@ -1,12 +1,9 @@ package com.yf.exam.modules.qu.service.impl; -// 导入MyBatis Plus相关类 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; - -// 导入其他相关类 import com.yf.exam.ability.upload.config.UploadConfig; import com.yf.exam.core.api.dto.PagingReqDTO; import com.yf.exam.core.exception.ServiceException; @@ -26,7 +23,6 @@ import com.yf.exam.modules.qu.service.QuRepoService; import com.yf.exam.modules.qu.service.QuService; import com.yf.exam.modules.qu.utils.ImageCheckUtils; import com.yf.exam.modules.repo.service.RepoService; - import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -41,7 +37,7 @@ import java.util.Map; /** *

- * 题目管理服务实现类 + * 语言设置 服务实现类 *

* * @author 聪明笨狗 @@ -50,136 +46,125 @@ import java.util.Map; @Service public class QuServiceImpl extends ServiceImpl implements QuService { - // 注入QuAnswerService服务 @Autowired private QuAnswerService quAnswerService; - // 注入QuRepoService服务 @Autowired private QuRepoService quRepoService; - // 注入图片校验工具类 @Autowired private ImageCheckUtils imageCheckUtils; - // 分页查询题目列表 @Override public IPage paging(PagingReqDTO reqDTO) { - // 创建分页对象 + //创建分页对象 Page page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - // 调用baseMapper的分页查询方法,获取分页数据 + //转换结果 IPage pageData = baseMapper.paging(page, reqDTO.getParams()); return pageData; } - // 删除题目、答案和题库绑定 @Transactional(rollbackFor = Exception.class) @Override public void delete(List ids) { - // 删除题目 + // 移除题目 this.removeByIds(ids); - // 删除与题目相关的选项 + // 移除选项 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().in(QuAnswer::getQuId, ids); quAnswerService.remove(wrapper); - // 删除题库与题目的绑定 + // 移除题库绑定 QueryWrapper wrapper1 = new QueryWrapper<>(); wrapper1.lambda().in(QuRepo::getQuId, ids); quRepoService.remove(wrapper1); } - // 随机获取题目 @Override public List listByRandom(String repoId, Integer quType, List excludes, Integer size) { return baseMapper.listByRandom(repoId, quType, excludes, size); } - // 获取题目的详细信息 @Override public QuDetailDTO detail(String id) { QuDetailDTO respDTO = new QuDetailDTO(); - // 获取题目信息 Qu qu = this.getById(id); BeanMapper.copy(qu, respDTO); - // 获取题目的选项信息 List answerList = quAnswerService.listByQu(id); respDTO.setAnswerList(answerList); - // 获取题目所属的题库 List repoIds = quRepoService.listByQu(id); respDTO.setRepoIds(repoIds); return respDTO; } - // 保存题目信息 + @Transactional(rollbackFor = Exception.class) @Override public void save(QuDetailDTO reqDTO) { - // 校验题目信息 + + // 校验数据 this.checkData(reqDTO, ""); Qu qu = new Qu(); - // 将题目详情复制到实体类 BeanMapper.copy(reqDTO, qu); - // 校验图片地址是否正确 + // 校验图片地址 imageCheckUtils.checkImage(qu.getImage(), "题干图片地址错误!"); - // 保存或更新题目信息 + // 更新 this.saveOrUpdate(qu); - // 保存题目的选项 + // 保存全部问题 quAnswerService.saveAll(qu.getId(), reqDTO.getAnswerList()); - // 保存题目与题库的绑定 + // 保存到题库 quRepoService.saveAll(qu.getId(), qu.getQuType(), reqDTO.getRepoIds()); + } - // 获取题目导出的列表 @Override public List listForExport(QuQueryReqDTO query) { return baseMapper.listForExport(query); } - // 导入Excel数据 @Override public int importExcel(List dtoList) { - // 根据题目名称分组 + //根据题目名称分组 Map> anMap = new HashMap<>(16); - // 存储题目信息 + //题目本体信息 Map quMap = new HashMap<>(16); - // 分组数据 + //数据分组 for (QuExportDTO item : dtoList) { - // 如果题目ID为空,跳过 + // 空白的ID if (StringUtils.isEmpty(item.getNo())) { continue; } Integer key; - // 获取题目序号 + //序号 try { key = Integer.parseInt(item.getNo()); } catch (Exception e) { continue; } - // 如果题目已存在,直接处理选项 + //如果已经有题目了,直接处理选项 if (anMap.containsKey(key)) { anMap.get(key).add(item); } else { - // 如果没有,将题目内容和选项一起放入 + //如果没有,将题目内容和选项一起 List subList = new ArrayList<>(); subList.add(item); anMap.put(key, subList); @@ -189,46 +174,49 @@ public class QuServiceImpl extends ServiceImpl implements QuServic int count = 0; try { - // 遍历题目插入 + + //循环题目插入 for (Integer key : quMap.keySet()) { QuExportDTO im = quMap.get(key); - // 处理题目的基本信息 + //题目基本信息 QuDetailDTO qu = new QuDetailDTO(); qu.setContent(im.getQContent()); qu.setAnalysis(im.getQAnalysis()); qu.setQuType(Integer.parseInt(im.getQuType())); qu.setCreateTime(new Date()); - // 设置题目的回答列表 + //设置回答列表 List answerList = this.processAnswerList(anMap.get(key)); + //设置题目 qu.setAnswerList(answerList); - - // 设置题目所属的题库 + //设置引用题库 qu.setRepoIds(im.getRepoList()); - - // 保存题目 + // 保存答案 this.save(qu); count++; } } catch (ServiceException e) { e.printStackTrace(); - // 异常处理,抛出导入失败的异常 throw new ServiceException(1, "导入出现问题,行:" + count + "," + e.getMessage()); } return count; } - // 处理题目的回答列表 + /** + * 处理回答列表 + * + * @param importList + * @return + */ private List processAnswerList(List importList) { List list = new ArrayList<>(16); for (QuExportDTO item : importList) { QuAnswerDTO a = new QuAnswerDTO(); - // 设置选项是否正确 a.setIsRight("1".equals(item.getAIsRight())); a.setContent(item.getAContent()); a.setAnalysis(item.getAAnalysis()); @@ -238,52 +226,58 @@ public class QuServiceImpl extends ServiceImpl implements QuServic return list; } - // 校验题目信息 + /** + * 校验题目信息 + * + * @param qu + * @param no + * @throws Exception + */ public void checkData(QuDetailDTO qu, String no) { - // 校验题目内容不能为空 + if (StringUtils.isEmpty(qu.getContent())) { throw new ServiceException(1, no + "题目内容不能为空!"); } - // 校验至少选择一个题库 + if (CollectionUtils.isEmpty(qu.getRepoIds())) { throw new ServiceException(1, no + "至少要选择一个题库!"); } - // 校验回答选项 List answers = qu.getAnswerList(); - if (CollectionUtils.isEmpty(answers)) { - throw new ServiceException(1, no + "客观题至少要包含一个备选答案!"); - } - int trueCount = 0; - for (QuAnswerDTO a : answers) { - // 校验选项是否定义了正确标志 - if (a.getIsRight() == null) { - throw new ServiceException(1, no + "必须定义选项是否正确项!"); + if (CollectionUtils.isEmpty(answers)) { + throw new ServiceException(1, no + "客观题至少要包含一个备选答案!"); } - // 校验选项内容不能为空 - if (StringUtils.isEmpty(a.getContent())) { - throw new ServiceException(1, no + "选项内容不为空!"); + + int trueCount = 0; + for (QuAnswerDTO a : answers) { + + if (a.getIsRight() == null) { + throw new ServiceException(1, no + "必须定义选项是否正确项!"); + } + + if (StringUtils.isEmpty(a.getContent())) { + throw new ServiceException(1, no + "选项内容不为空!"); + } + + if (a.getIsRight()) { + trueCount += 1; + } } - // 统计正确选项的个数 - if (a.getIsRight()) { - trueCount += 1; + if (trueCount == 0) { + throw new ServiceException(1, no + "至少要包含一个正确项!"); } - } - // 校验至少包含一个正确选项 - if (trueCount == 0) { - throw new ServiceException(1, no + "至少要包含一个正确项!"); - } - // 单选题不能包含多个正确选项 - if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) { - throw new ServiceException(1, no + "单选题不能包含多个正确项!"); - } + //单选题 + if (qu.getQuType().equals(QuType.RADIO) && trueCount > 1) { + throw new ServiceException(1, no + "单选题不能包含多个正确项!"); + } + } } diff --git a/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java b/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java index 902c507..707fbcd 100644 --- a/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java +++ b/src-源文件/main/java/com/yf/exam/modules/qu/utils/ImageCheckUtils.java @@ -1,42 +1,31 @@ -// 定义包名,表示该类属于com.yf.exam.modules.qu.utils包下 package com.yf.exam.modules.qu.utils; -// 导入项目中定义的上传配置类 import com.yf.exam.ability.upload.config.UploadConfig; -// 导入项目中定义的服务异常类 import com.yf.exam.core.exception.ServiceException; -// 导入Apache Commons Lang库中的StringUtils类,用于字符串操作 import org.apache.commons.lang3.StringUtils; -// 导入Spring框架中的注解,用于自动注入依赖 import org.springframework.beans.factory.annotation.Autowired; -// 导入Spring框架中的注解,用于声明组件 import org.springframework.stereotype.Component; -/** - * 图片校验工具类,提供图片地址校验的功能 - */ @Component public class ImageCheckUtils { - // 自动注入上传配置,用于获取图片上传的相关配置 @Autowired private UploadConfig conf; /** - * 进行图片校验的方法 - * @param image 图片地址 - * @param throwMsg 校验失败时抛出的异常信息 + * 进行图片校验! + * @param image + * @param throwMsg */ public void checkImage(String image, String throwMsg) { - // 如果图片地址为空或空白,则直接返回,不进行校验 + if(StringUtils.isBlank(image)){ return; } - // 校验图片地址是否以配置的URL开头,确保图片地址是合法的 + // 校验图片地址 if(!image.startsWith(conf.getUrl())){ - // 如果图片地址不合法,则抛出服务异常 throw new ServiceException(throwMsg); } } -} \ No newline at end of file +} From 22d20a181af4c4a80438c91199db5c271c978606 Mon Sep 17 00:00:00 2001 From: shl <1577537067@qq.com> Date: Wed, 27 Nov 2024 22:47:04 +0800 Subject: [PATCH 4/5] 1 --- .../java/com/yf/exam/modules/Constant.java | 13 +- .../repo/controller/RepoController.java | 182 ++++++------ .../com/yf/exam/modules/repo/dto/RepoDTO.java | 61 ++-- .../modules/repo/dto/request/RepoReqDTO.java | 44 +-- .../repo/dto/response/RepoRespDTO.java | 46 +-- .../com/yf/exam/modules/repo/entity/Repo.java | 60 ++-- .../exam/modules/repo/mapper/RepoMapper.java | 42 +-- .../modules/repo/service/RepoService.java | 50 ++-- .../repo/service/impl/RepoServiceImpl.java | 62 ++-- .../controller/SysConfigController.java | 107 +++---- .../modules/sys/config/dto/SysConfigDTO.java | 67 +++-- .../modules/sys/config/entity/SysConfig.java | 59 ++-- .../sys/config/mapper/SysConfigMapper.java | 24 +- .../sys/config/service/SysConfigService.java | 29 +- .../service/impl/SysConfigServiceImpl.java | 56 ++-- .../controller/SysDepartController.java | 230 +++++++-------- .../modules/sys/depart/dto/SysDepartDTO.java | 59 ++-- .../depart/dto/request/DepartSortReqDTO.java | 41 +-- .../depart/dto/response/SysDepartTreeDTO.java | 41 ++- .../modules/sys/depart/entity/SysDepart.java | 84 +++--- .../sys/depart/mapper/SysDepartMapper.java | 41 +-- .../sys/depart/service/SysDepartService.java | 78 ++--- .../service/impl/SysDepartServiceImpl.java | 275 +++++++++--------- .../sys/system/mapper/SysDictMapper.java | 41 +-- .../sys/system/service/SysDictService.java | 28 +- .../service/impl/SysDictServiceImpl.java | 27 +- .../user/controller/SysRoleController.java | 98 +++---- .../user/controller/SysUserController.java | 227 ++++++++------- .../exam/modules/sys/user/dto/SysRoleDTO.java | 47 ++- .../exam/modules/sys/user/dto/SysUserDTO.java | 77 +++-- .../modules/sys/user/dto/SysUserRoleDTO.java | 53 ++-- .../user/dto/request/SysUserLoginReqDTO.java | 42 +-- .../user/dto/request/SysUserSaveReqDTO.java | 76 ++--- .../user/dto/request/SysUserTokenReqDTO.java | 38 +-- .../user/dto/response/SysUserLoginDTO.java | 78 ++--- .../exam/modules/sys/user/entity/SysRole.java | 60 ++-- .../exam/modules/sys/user/entity/SysUser.java | 84 +++--- .../modules/sys/user/entity/SysUserRole.java | 71 ++--- .../sys/user/mapper/SysRoleMapper.java | 24 +- .../sys/user/mapper/SysUserMapper.java | 23 +- .../sys/user/mapper/SysUserRoleMapper.java | 23 +- .../sys/user/service/SysRoleService.java | 39 +-- .../sys/user/service/SysUserRoleService.java | 73 ++--- .../sys/user/service/SysUserService.java | 79 ++--- .../user/service/impl/SysRoleServiceImpl.java | 64 ++-- .../service/impl/SysUserRoleServiceImpl.java | 124 ++++---- .../user/service/impl/SysUserServiceImpl.java | 226 +++++++------- .../com/yf/exam/modules/user/UserUtils.java | 54 ++-- .../book/controller/UserBookController.java | 109 +++---- .../modules/user/book/dto/UserBookDTO.java | 75 +++-- .../modules/user/book/entity/UserBook.java | 72 ++--- .../user/book/mapper/UserBookMapper.java | 23 +- .../user/book/service/UserBookService.java | 57 ++-- .../service/impl/UserBookServiceImpl.java | 176 ++++++----- .../exam/controller/UserExamController.java | 91 +++--- .../modules/user/exam/dto/UserExamDTO.java | 114 +++++--- .../user/exam/dto/request/UserExamReqDTO.java | 56 ++-- .../exam/dto/response/UserExamRespDTO.java | 49 ++-- .../modules/user/exam/entity/UserExam.java | 117 ++++---- .../user/exam/mapper/UserExamMapper.java | 44 +-- .../user/exam/service/UserExamService.java | 60 ++-- .../service/impl/UserExamServiceImpl.java | 113 ++++--- 62 files changed, 2399 insertions(+), 2284 deletions(-) diff --git a/src-源文件/main/java/com/yf/exam/modules/Constant.java b/src-源文件/main/java/com/yf/exam/modules/Constant.java index 20c5726..7e83ead 100644 --- a/src-源文件/main/java/com/yf/exam/modules/Constant.java +++ b/src-源文件/main/java/com/yf/exam/modules/Constant.java @@ -1,14 +1,15 @@ -package com.yf.exam.modules; - +package com.yf.exam.modules; // 包名:表示该类属于 modules 包 /** - * 通用常量 - * @author bool + * 通用常量类 + * 用于存放项目中使用的常量 + * @作者 bool */ public class Constant { /** - * 会话 + * 会话常量 + * 用于存放 Token 的常量名 */ - public static final String TOKEN = "token"; + public static final String TOKEN = "token"; // 定义一个常量 TOKEN,表示会话中的 Token 名称 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/controller/RepoController.java b/src-源文件/main/java/com/yf/exam/modules/repo/controller/RepoController.java index 6b1764f..29e3998 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/controller/RepoController.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/controller/RepoController.java @@ -1,117 +1,113 @@ -package com.yf.exam.modules.repo.controller; +package com.yf.exam.modules.repo.controller; // 包名:表示该类属于 repo.controller 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdReqDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; -import com.yf.exam.modules.qu.service.QuRepoService; -import com.yf.exam.modules.repo.dto.RepoDTO; -import com.yf.exam.modules.repo.dto.request.RepoReqDTO; -import com.yf.exam.modules.repo.dto.response.RepoRespDTO; -import com.yf.exam.modules.repo.entity.Repo; -import com.yf.exam.modules.repo.service.RepoService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +// 导入所需的类和包 +import com.baomidou.mybatisplus.core.metadata.IPage; // 分页元数据接口 +import com.yf.exam.core.api.ApiRest; // 统一 API 响应类 +import com.yf.exam.core.api.controller.BaseController; // 控制器基类,提供通用控制功能 +import com.yf.exam.core.api.dto.BaseIdReqDTO; // 数据传输对象,用于封装单个 ID 请求 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 数据传输对象,用于封装多个 ID 请求 +import com.yf.exam.core.api.dto.PagingReqDTO; // 数据传输对象,用于分页请求 +import com.yf.exam.modules.qu.dto.request.QuRepoBatchReqDTO; // 数据传输对象,用于题库批量操作请求 +import com.yf.exam.modules.qu.service.QuRepoService; // 服务接口,用于题库的批量操作 +import com.yf.exam.modules.repo.dto.RepoDTO; // 数据传输对象,封装题库信息 +import com.yf.exam.modules.repo.dto.request.RepoReqDTO; // 数据传输对象,用于题库分页查询请求 +import com.yf.exam.modules.repo.dto.response.RepoRespDTO; // 数据传输对象,用于题库分页查询响应 +import com.yf.exam.modules.repo.entity.Repo; // 题库实体类 +import com.yf.exam.modules.repo.service.RepoService; // 服务接口,用于题库操作 +import io.swagger.annotations.Api; // Swagger 注解,用于 API 文档生成 +import io.swagger.annotations.ApiOperation; // Swagger 注解,用于定义接口操作说明 +import org.apache.shiro.authz.annotation.RequiresRoles; // Shiro 注解,用于权限控制 +import org.springframework.beans.BeanUtils; // 工具类,用于对象属性拷贝 +import org.springframework.beans.factory.annotation.Autowired; // Spring 注解,用于依赖注入 +import org.springframework.web.bind.annotation.RequestBody; // 注解,用于绑定请求体 +import org.springframework.web.bind.annotation.RequestMapping; // 注解,用于定义请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 注解,用于指定 HTTP 请求方法 +import org.springframework.web.bind.annotation.RestController; // 注解,标识为 REST 控制器 /** -*

-* 题库控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:25 -*/ -@Api(tags={"题库"}) -@RestController -@RequestMapping("/exam/api/repo") -public class RepoController extends BaseController { + *

+ * 题库控制器 + *

+ * 定义用于操作题库的控制器 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:25 + */ +@Api(tags = {"题库"}) // Swagger 注解:定义 API 文档中该控制器的标签为“题库” +@RestController // Spring 注解:标识该类为 REST 控制器 +@RequestMapping("/exam/api/repo") // 定义请求路径前缀为 /exam/api/repo +public class RepoController extends BaseController { // 题库控制器类,继承基础控制器 - @Autowired + @Autowired // 自动注入题库服务 private RepoService baseService; - @Autowired + @Autowired // 自动注入题库批量操作服务 private QuRepoService quRepoService; /** - * 添加或修改 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = { RequestMethod.POST}) - public ApiRest save(@RequestBody RepoDTO reqDTO) { - baseService.save(reqDTO); - return super.success(); + * 添加或修改题库 + * @param reqDTO 请求数据传输对象,包含题库信息 + * @return 返回操作结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "添加或修改") // Swagger 注解:定义接口操作说明为“添加或修改” + @RequestMapping(value = "/save", method = {RequestMethod.POST}) // 定义请求路径为 /save,请求方法为 POST + public ApiRest save(@RequestBody RepoDTO reqDTO) { // 添加或修改题库的方法 + baseService.save(reqDTO); // 调用服务保存题库信息 + return super.success(); // 返回成功结果 } /** - * 批量删除 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) - public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.removeByIds(reqDTO.getIds()); - return super.success(); + * 批量删除题库 + * @param reqDTO 请求数据传输对象,包含待删除的题库 ID 列表 + * @return 返回操作结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "批量删除") // Swagger 注解:定义接口操作说明为“批量删除” + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) // 定义请求路径为 /delete,请求方法为 POST + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { // 批量删除题库的方法 + baseService.removeByIds(reqDTO.getIds()); // 根据 ID 列表删除题库 + return super.success(); // 返回成功结果 } /** - * 查找详情 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) - public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { - Repo entity = baseService.getById(reqDTO.getId()); - RepoDTO dto = new RepoDTO(); - BeanUtils.copyProperties(entity, dto); - return super.success(dto); + * 查找题库详情 + * @param reqDTO 请求数据传输对象,包含待查找的题库 ID + * @return 返回题库详情 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情” + @RequestMapping(value = "/detail", method = {RequestMethod.POST}) // 定义请求路径为 /detail,请求方法为 POST + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { // 查找题库详情的方法 + Repo entity = baseService.getById(reqDTO.getId()); // 根据 ID 查找题库实体 + RepoDTO dto = new RepoDTO(); // 创建题库数据传输对象 + BeanUtils.copyProperties(entity, dto); // 将实体属性拷贝到 DTO 中 + return super.success(dto); // 返回成功结果,包含题库详情 } /** - * 分页查找 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - - return super.success(page); + * 分页查找题库 + * @param reqDTO 分页请求数据传输对象,包含分页参数和查询条件 + * @return 返回分页结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "分页查找") // Swagger 注解:定义接口操作说明为“分页查找” + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) // 定义请求路径为 /paging,请求方法为 POST + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 分页查找题库的方法 + IPage page = baseService.paging(reqDTO); // 调用服务进行分页查询 + return super.success(page); // 返回成功结果,包含分页数据 } /** - * 批量操作 - * @param reqDTO - * @return + * 批量操作题库 + * @param reqDTO 请求数据传输对象,包含批量操作的参数 + * @return 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "批量操作", notes = "批量加入或从题库移除") - @RequestMapping(value = "/batch-action", method = { RequestMethod.POST}) - public ApiRest batchAction(@RequestBody QuRepoBatchReqDTO reqDTO) { - - //分页查询并转换 - quRepoService.batchAction(reqDTO); - return super.success(); + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "批量操作", notes = "批量加入或从题库移除") // Swagger 注解:定义接口操作说明为“批量操作”,并提供备注 + @RequestMapping(value = "/batch-action", method = {RequestMethod.POST}) // 定义请求路径为 /batch-action,请求方法为 POST + public ApiRest batchAction(@RequestBody QuRepoBatchReqDTO reqDTO) { // 批量操作题库的方法 + quRepoService.batchAction(reqDTO); // 调用服务执行批量操作 + return super.success(); // 返回成功结果 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/dto/RepoDTO.java b/src-源文件/main/java/com/yf/exam/modules/repo/dto/RepoDTO.java index a048c6b..9f5fd48 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/dto/RepoDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/dto/RepoDTO.java @@ -1,43 +1,42 @@ -package com.yf.exam.modules.repo.dto; +package com.yf.exam.modules.repo.dto; // 包名:表示该类属于 repo.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 导入 Serializable 接口,用于支持序列化 +import java.util.Date; // 导入 Date 类,用于处理日期和时间 /** -*

-* 题库请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -@Data -@ApiModel(value="题库", description="题库") -public class RepoDTO implements Serializable { + *

+ * 题库请求类 + *

+ * 定义题库的通用数据传输对象 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "题库", description = "题库") // Swagger 注解,定义该类的 API 模型名称及描述 +public class RepoDTO implements Serializable { // 定义类 RepoDTO,实现 Serializable 接口以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + @ApiModelProperty(value = "题库ID", required = true) // Swagger 注解,描述该属性为“题库 ID” + private String id; // 定义属性:题库的唯一标识符 - @ApiModelProperty(value = "题库ID", required=true) - private String id; + @ApiModelProperty(value = "题库编号", required = true) // Swagger 注解,描述该属性为“题库编号” + private String code; // 定义属性:题库编号 - @ApiModelProperty(value = "题库编号", required=true) - private String code; + @ApiModelProperty(value = "题库名称", required = true) // Swagger 注解,描述该属性为“题库名称” + private String title; // 定义属性:题库名称 - @ApiModelProperty(value = "题库名称", required=true) - private String title; + @ApiModelProperty(value = "题库备注", required = true) // Swagger 注解,描述该属性为“题库备注” + private String remark; // 定义属性:题库备注信息 - @ApiModelProperty(value = "题库备注", required=true) - private String remark; + @ApiModelProperty(value = "创建时间", required = true) // Swagger 注解,描述该属性为“创建时间” + private Date createTime; // 定义属性:题库的创建时间 - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; - - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; - + @ApiModelProperty(value = "更新时间", required = true) // Swagger 注解,描述该属性为“更新时间” + private Date updateTime; // 定义属性:题库的最后更新时间 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/dto/request/RepoReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/repo/dto/request/RepoReqDTO.java index 1e4d803..4129476 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/dto/request/RepoReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/dto/request/RepoReqDTO.java @@ -1,30 +1,30 @@ -package com.yf.exam.modules.repo.dto.request; +package com.yf.exam.modules.repo.dto.request; // 包名:表示该类属于 repo.dto.request 包 -import com.yf.exam.modules.repo.dto.RepoDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.repo.dto.RepoDTO; // 导入 RepoDTO 类,题库数据传输对象 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.util.List; +import java.util.List; // 导入 Java 的 List 接口,用于存储排除的题库 ID 列表 /** -*

-* 题库请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -@Data -@ApiModel(value="题库分页请求类", description="题库分页请求类") -public class RepoReqDTO extends RepoDTO { + *

+ * 题库分页请求类 + *

+ * 定义用于题库分页查询的请求数据传输对象 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "题库分页请求类", description = "题库分页请求类") // Swagger 注解,定义该类的 API 模型名称及描述 +public class RepoReqDTO extends RepoDTO { // 定义类 RepoReqDTO,继承自 RepoDTO - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "排除题库ID", required=true) - private List excludes; - - @ApiModelProperty(value = "单选题数量", required=true) - private String title; + @ApiModelProperty(value = "排除题库ID", required = true) // Swagger 注解,描述该属性为“需要排除的题库 ID 列表” + private List excludes; // 定义属性:排除的题库 ID 列表 + @ApiModelProperty(value = "单选题数量", required = true) // Swagger 注解,描述该属性为“单选题数量” + private String title; // 定义属性:单选题数量(注意:变量名可能存在歧义,建议确认或重命名) } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/dto/response/RepoRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/repo/dto/response/RepoRespDTO.java index feb90aa..c043289 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/dto/response/RepoRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/dto/response/RepoRespDTO.java @@ -1,31 +1,31 @@ -package com.yf.exam.modules.repo.dto.response; +package com.yf.exam.modules.repo.dto.response; // 包名:表示该类属于 repo.dto.response 包 -import com.yf.exam.modules.repo.dto.RepoDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.repo.dto.RepoDTO; // 导入 RepoDTO 类,题库通用数据传输对象 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 /** -*

-* 题库请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -@Data -@ApiModel(value="题库分页响应类", description="题库分页响应类") -public class RepoRespDTO extends RepoDTO { + *

+ * 题库分页响应类 + *

+ * 定义用于分页查询的题库响应数据传输对象 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "题库分页响应类", description = "题库分页响应类") // Swagger 注解,定义该类的 API 模型名称及描述 +public class RepoRespDTO extends RepoDTO { // 定义类 RepoRespDTO,继承自 RepoDTO - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "多选题数量", required=true) - private Integer multiCount; + @ApiModelProperty(value = "多选题数量", required = true) // Swagger 注解,描述该属性为“多选题数量” + private Integer multiCount; // 定义属性:多选题的数量 - @ApiModelProperty(value = "单选题数量", required=true) - private Integer radioCount; - - @ApiModelProperty(value = "判断题数量", required=true) - private Integer judgeCount; + @ApiModelProperty(value = "单选题数量", required = true) // Swagger 注解,描述该属性为“单选题数量” + private Integer radioCount; // 定义属性:单选题的数量 + @ApiModelProperty(value = "判断题数量", required = true) // Swagger 注解,描述该属性为“判断题数量” + private Integer judgeCount; // 定义属性:判断题的数量 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/entity/Repo.java b/src-源文件/main/java/com/yf/exam/modules/repo/entity/Repo.java index 95d3d04..d16452b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/entity/Repo.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/entity/Repo.java @@ -1,59 +1,59 @@ -package com.yf.exam.modules.repo.entity; +package com.yf.exam.modules.repo.entity; // 包名:表示该类属于 repo.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于定义主键类型 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于映射数据库字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于标识主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于映射数据库表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus ActiveRecord 模式基类 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.util.Date; +import java.util.Date; // 导入 Java 的 Date 类,用于表示日期和时间 /** -*

-* 题库实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -@Data -@TableName("el_repo") -public class Repo extends Model { - - private static final long serialVersionUID = 1L; + *

+ * 题库实体类 + *

+ * 定义题库的数据库实体类 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("el_repo") // MyBatis-Plus 注解,指定该实体类映射的数据库表名为 "el_repo" +public class Repo extends Model { // 定义类 Repo,继承 MyBatis-Plus 的 Model 类以支持 ActiveRecord 模式 + + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 /** * 题库ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,标识主键字段,并指定主键生成策略为分配 ID + private String id; // 定义字段:题库的唯一标识符 /** * 题库编号 */ - private String code; + private String code; // 定义字段:题库编号 /** * 题库名称 */ - private String title; + private String title; // 定义字段:题库名称 /** * 题库备注 */ - private String remark; + private String remark; // 定义字段:题库备注信息 /** * 创建时间 */ - @TableField("create_time") - private Date createTime; + @TableField("create_time") // MyBatis-Plus 注解,指定该字段映射数据库中的 "create_time" 列 + private Date createTime; // 定义字段:题库的创建时间 /** * 更新时间 */ - @TableField("update_time") - private Date updateTime; - + @TableField("update_time") // MyBatis-Plus 注解,指定该字段映射数据库中的 "update_time" 列 + private Date updateTime; // 定义字段:题库的最后更新时间 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/mapper/RepoMapper.java b/src-源文件/main/java/com/yf/exam/modules/repo/mapper/RepoMapper.java index af39177..d28d223 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/mapper/RepoMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/mapper/RepoMapper.java @@ -1,29 +1,29 @@ -package com.yf.exam.modules.repo.mapper; +package com.yf.exam.modules.repo.mapper; // 包名:表示该类属于 repo.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.repo.dto.request.RepoReqDTO; -import com.yf.exam.modules.repo.dto.response.RepoRespDTO; -import com.yf.exam.modules.repo.entity.Repo; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,用于基本的数据库操作 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 分页插件中的 Page 类 +import com.yf.exam.modules.repo.dto.request.RepoReqDTO; // 导入用于分页查询的请求数据传输对象 RepoReqDTO +import com.yf.exam.modules.repo.dto.response.RepoRespDTO; // 导入用于分页查询的响应数据传输对象 RepoRespDTO +import com.yf.exam.modules.repo.entity.Repo; // 导入题库实体类 Repo +import org.apache.ibatis.annotations.Param; // 导入 MyBatis 注解,用于标注参数 /** -*

-* 题库Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -public interface RepoMapper extends BaseMapper { + *

+ * 题库Mapper + *

+ * 定义题库的 Mapper 接口,用于执行与题库相关的数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +public interface RepoMapper extends BaseMapper { // RepoMapper 接口,继承自 MyBatis-Plus 的 BaseMapper,提供常见的数据库操作 /** * 分页查询题库 - * @param page - * @param query - * @return + * @param page 分页对象,包含当前页码和每页大小 + * @param query 查询条件,封装了题库分页查询的参数 + * @return 返回分页查询结果,包含多个题库的响应数据 */ - IPage paging(Page page, @Param("query") RepoReqDTO query); - + IPage paging(Page page, @Param("query") RepoReqDTO query); // 自定义分页查询方法,返回题库分页响应数据 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/service/RepoService.java b/src-源文件/main/java/com/yf/exam/modules/repo/service/RepoService.java index 867a283..d4f989a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/service/RepoService.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/service/RepoService.java @@ -1,34 +1,34 @@ -package com.yf.exam.modules.repo.service; +package com.yf.exam.modules.repo.service; // 包名:表示该类属于 repo.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.repo.dto.RepoDTO; -import com.yf.exam.modules.repo.dto.request.RepoReqDTO; -import com.yf.exam.modules.repo.dto.response.RepoRespDTO; -import com.yf.exam.modules.repo.entity.Repo; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 服务接口,提供通用的数据库操作 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.modules.repo.dto.RepoDTO; // 导入 RepoDTO 类,题库数据传输对象 +import com.yf.exam.modules.repo.dto.request.RepoReqDTO; // 导入 RepoReqDTO 类,用于封装分页查询条件 +import com.yf.exam.modules.repo.dto.response.RepoRespDTO; // 导入 RepoRespDTO 类,题库分页响应数据传输对象 +import com.yf.exam.modules.repo.entity.Repo; // 导入 Repo 实体类,表示题库 /** -*

-* 题库业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -public interface RepoService extends IService { + *

+ * 题库业务类 + *

+ * 该接口定义了题库的业务逻辑,继承自 MyBatis-Plus 提供的 IService 接口,简化了数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +public interface RepoService extends IService { // RepoService 接口,继承 MyBatis-Plus 的 IService,提供常见数据库操作 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); - + * 分页查询数据 + * @param reqDTO 请求数据传输对象,包含分页信息和查询条件 + * @return 返回分页查询结果,包含题库响应数据 + */ + IPage paging(PagingReqDTO reqDTO); // 分页查询方法,接收分页请求数据对象,并返回分页结果 /** - * 保存 - * @param reqDTO + * 保存题库 + * @param reqDTO 请求数据传输对象,包含题库信息 */ - void save(RepoDTO reqDTO); + void save(RepoDTO reqDTO); // 保存题库方法,用于保存或更新题库信息 } diff --git a/src-源文件/main/java/com/yf/exam/modules/repo/service/impl/RepoServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/repo/service/impl/RepoServiceImpl.java index df67301..44ca86f 100644 --- a/src-源文件/main/java/com/yf/exam/modules/repo/service/impl/RepoServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/repo/service/impl/RepoServiceImpl.java @@ -1,39 +1,49 @@ -package com.yf.exam.modules.repo.service.impl; +package com.yf.exam.modules.repo.service.impl; // 包名:表示该类属于 repo.service.impl 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.repo.dto.RepoDTO; -import com.yf.exam.modules.repo.dto.request.RepoReqDTO; -import com.yf.exam.modules.repo.dto.response.RepoRespDTO; -import com.yf.exam.modules.repo.entity.Repo; -import com.yf.exam.modules.repo.mapper.RepoMapper; -import com.yf.exam.modules.repo.service.RepoService; -import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 服务实现类,用于提供通用的数据库操作 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.repo.dto.RepoDTO; // 导入 RepoDTO,题库数据传输对象 +import com.yf.exam.modules.repo.dto.request.RepoReqDTO; // 导入 RepoReqDTO,封装分页查询条件的请求数据传输对象 +import com.yf.exam.modules.repo.dto.response.RepoRespDTO; // 导入 RepoRespDTO,题库分页响应数据传输对象 +import com.yf.exam.modules.repo.entity.Repo; // 导入 Repo 实体类,表示题库实体 +import com.yf.exam.modules.repo.mapper.RepoMapper; // 导入 RepoMapper,数据访问层接口 +import com.yf.exam.modules.repo.service.RepoService; // 导入 RepoService,题库服务接口 +import org.springframework.stereotype.Service; // 导入 Spring 的 Service 注解,标识该类为服务层组件 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-25 13:23 -*/ -@Service -public class RepoServiceImpl extends ServiceImpl implements RepoService { + *

+ * 题库服务实现类 + *

+ * 该类实现了 RepoService 接口,处理题库相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-05-25 13:23 + */ +@Service // Spring 注解,标识该类为服务层组件 +public class RepoServiceImpl extends ServiceImpl implements RepoService { // 继承 MyBatis-Plus 提供的 ServiceImpl,简化数据库操作 + /** + * 分页查询题库 + * @param reqDTO 请求数据传输对象,包含分页信息和查询条件 + * @return 返回分页查询结果 + */ @Override public IPage paging(PagingReqDTO reqDTO) { - return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); + return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); // 调用 Mapper 的分页查询方法,传入分页信息和查询条件 } + /** + * 添加或修改题库 + * @param reqDTO 请求数据传输对象,包含题库信息 + */ @Override public void save(RepoDTO reqDTO) { - //复制参数 - Repo entity = new Repo(); - BeanMapper.copy(reqDTO, entity); - this.saveOrUpdate(entity); + // 复制参数,将请求数据传输对象的属性复制到实体类中 + Repo entity = new Repo(); // 创建 Repo 实体对象 + BeanMapper.copy(reqDTO, entity); // 使用 BeanMapper 工具类复制属性 + this.saveOrUpdate(entity); // 调用 MyBatis-Plus 提供的 saveOrUpdate 方法,保存或更新实体 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/controller/SysConfigController.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/controller/SysConfigController.java index b62603b..a812944 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/controller/SysConfigController.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/controller/SysConfigController.java @@ -1,70 +1,71 @@ -package com.yf.exam.modules.sys.config.controller; +package com.yf.exam.modules.sys.config.controller; // 包名:表示该类属于 sys.config.controller 包 -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdRespDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.qu.utils.ImageCheckUtils; -import com.yf.exam.modules.sys.config.dto.SysConfigDTO; -import com.yf.exam.modules.sys.config.entity.SysConfig; -import com.yf.exam.modules.sys.config.service.SysConfigService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import com.yf.exam.core.api.ApiRest; // 导入统一的 API 响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入控制器基类,提供通用的控制器功能 +import com.yf.exam.core.api.dto.BaseIdRespDTO; // 导入基础响应 DTO,用于返回 ID 响应 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.qu.utils.ImageCheckUtils; // 导入图片检查工具类,用于校验图片地址 +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; // 导入 SysConfigDTO 类,用于封装系统配置的数据传输对象 +import com.yf.exam.modules.sys.config.entity.SysConfig; // 导入 SysConfig 实体类,表示系统配置 +import com.yf.exam.modules.sys.config.service.SysConfigService; // 导入 SysConfigService 服务接口 +import io.swagger.annotations.Api; // 导入 Swagger 注解,用于 API 文档生成 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 注解,用于定义接口操作说明 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入 Shiro 权限控制注解,限制角色访问 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 注解,用于依赖注入 +import org.springframework.web.bind.annotation.RequestBody; // 导入注解,用于绑定请求体 +import org.springframework.web.bind.annotation.RequestMapping; // 导入注解,用于定义请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入注解,用于指定请求方法 +import org.springframework.web.bind.annotation.RestController; // 导入注解,标识该类为 REST 控制器 /** -*

-* 通用配置控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -@Api(tags={"通用配置"}) -@RestController -@RequestMapping("/exam/api/sys/config") -public class SysConfigController extends BaseController { + *

+ * 通用配置控制器 + *

+ * 提供与系统配置相关的操作接口,包括添加、修改、查找配置等 + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +@Api(tags = {"通用配置"}) // Swagger 注解:定义该类的 API 文档标签为“通用配置” +@RestController // Spring 注解:标识该类为 REST 控制器 +@RequestMapping("/exam/api/sys/config") // 定义请求路径前缀为 /exam/api/sys/config +public class SysConfigController extends BaseController { // SysConfigController 类,继承自 BaseController,提供通用功能 - @Autowired + @Autowired // 自动注入 SysConfigService 服务 private SysConfigService baseService; - @Autowired + @Autowired // 自动注入 ImageCheckUtils 工具类 private ImageCheckUtils imageCheckUtils; /** - * 添加或修改 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = { RequestMethod.POST}) - public ApiRest save(@RequestBody SysConfigDTO reqDTO) { + * 添加或修改系统配置 + * @param reqDTO 请求数据传输对象,包含系统配置的信息 + * @return 返回包含新增或修改的系统配置 ID 的响应 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "添加或修改") // Swagger 注解:定义接口操作说明为“添加或修改” + @RequestMapping(value = "/save", method = { RequestMethod.POST}) // 定义请求路径为 /save,方法为 POST + public ApiRest save(@RequestBody SysConfigDTO reqDTO) { // 定义保存或修改系统配置的方法 - //复制参数 - SysConfig entity = new SysConfig(); - BeanMapper.copy(reqDTO, entity); + // 复制请求参数到实体对象 + SysConfig entity = new SysConfig(); // 创建 SysConfig 实体对象 + BeanMapper.copy(reqDTO, entity); // 使用 BeanMapper 工具类将 DTO 的属性拷贝到实体对象 - // 校验图片地址 - imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误!"); + // 校验图片地址是否有效 + imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误!"); // 检查系统LOGO地址是否有效 - baseService.saveOrUpdate(entity); - return super.success(new BaseIdRespDTO(entity.getId())); + baseService.saveOrUpdate(entity); // 调用服务的保存或更新方法 + return super.success(new BaseIdRespDTO(entity.getId())); // 返回成功响应,并包含系统配置 ID } /** - * 查找详情 - * @return - */ - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) - public ApiRest find() { - SysConfigDTO dto = baseService.find(); - return super.success(dto); + * 查找系统配置详情 + * @return 返回系统配置详情 + */ + @ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情” + @RequestMapping(value = "/detail", method = { RequestMethod.POST}) // 定义请求路径为 /detail,方法为 POST + public ApiRest find() { // 定义查找系统配置详情的方法 + SysConfigDTO dto = baseService.find(); // 调用服务查找系统配置详情 + return super.success(dto); // 返回成功响应,包含系统配置详情 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/dto/SysConfigDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/dto/SysConfigDTO.java index ef7c179..615c61a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/dto/SysConfigDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/dto/SysConfigDTO.java @@ -1,39 +1,38 @@ -package com.yf.exam.modules.sys.config.dto; +package com.yf.exam.modules.sys.config.dto; // 包名:表示该类属于 sys.config.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于对象序列化 /** -*

-* 通用配置请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -@Data -@ApiModel(value="通用配置", description="通用配置") -public class SysConfigDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "系统名称") - private String siteName; - - @ApiModelProperty(value = "前端LOGO") - private String frontLogo; - - @ApiModelProperty(value = "后台LOGO") - private String backLogo; - - @ApiModelProperty(value = "版权信息") - private String copyRight; - + *

+ * 通用配置请求类 + *

+ * 该类封装了通用配置的数据传输对象,用于在 API 请求中传递系统配置数据 + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "通用配置", description = "通用配置") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysConfigDTO implements Serializable { // 定义 SysConfigDTO 类,实现 Serializable 接口以支持序列化 + + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:系统配置的唯一标识符 + + @ApiModelProperty(value = "系统名称") // Swagger 注解:描述该属性为“系统名称” + private String siteName; // 定义字段:系统名称 + + @ApiModelProperty(value = "前端LOGO") // Swagger 注解:描述该属性为“前端LOGO” + private String frontLogo; // 定义字段:前端展示用的 LOGO 图片地址 + + @ApiModelProperty(value = "后台LOGO") // Swagger 注解:描述该属性为“后台LOGO” + private String backLogo; // 定义字段:后台管理用的 LOGO 图片地址 + + @ApiModelProperty(value = "版权信息") // Swagger 注解:描述该属性为“版权信息” + private String copyRight; // 定义字段:版权信息 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/entity/SysConfig.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/entity/SysConfig.java index 070ab06..16fc25b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/entity/SysConfig.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/entity/SysConfig.java @@ -1,53 +1,54 @@ -package com.yf.exam.modules.sys.config.entity; +package com.yf.exam.modules.sys.config.entity; // 包名:表示该类属于 sys.config.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于定义主键类型 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于映射数据库字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于标识主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于映射数据库表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus ActiveRecord 模式基类 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 /** -*

-* 通用配置实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -@Data -@TableName("sys_config") -public class SysConfig extends Model { - - private static final long serialVersionUID = 1L; + *

+ * 通用配置实体类 + *

+ * 表示系统配置的数据模型,映射数据库表 `sys_config` + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("sys_config") // MyBatis-Plus 注解,指定该实体类映射数据库表名为 `sys_config` +public class SysConfig extends Model { // SysConfig 类继承自 MyBatis-Plus 的 Model 类,启用 ActiveRecord 模式 + + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 /** * ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,标识主键字段,并指定主键生成策略为分配 ID + private String id; // 定义字段:系统配置的唯一标识符 /** * 系统名称 */ - @TableField("site_name") - private String siteName; + @TableField("site_name") // MyBatis-Plus 注解,指定该字段映射数据库中的 "site_name" 列 + private String siteName; // 定义字段:系统名称 /** * 前端LOGO */ - @TableField("front_logo") - private String frontLogo; + @TableField("front_logo") // MyBatis-Plus 注解,指定该字段映射数据库中的 "front_logo" 列 + private String frontLogo; // 定义字段:前端展示的 LOGO 图片地址 /** * 后台LOGO */ - @TableField("back_logo") - private String backLogo; + @TableField("back_logo") // MyBatis-Plus 注解,指定该字段映射数据库中的 "back_logo" 列 + private String backLogo; // 定义字段:后台管理系统的 LOGO 图片地址 /** * 版权信息 */ - @TableField("copy_right") - private String copyRight; + @TableField("copy_right") // MyBatis-Plus 注解,指定该字段映射数据库中的 "copy_right" 列 + private String copyRight; // 定义字段:版权信息 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/mapper/SysConfigMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/mapper/SysConfigMapper.java index 512ae1b..443686a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/mapper/SysConfigMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/mapper/SysConfigMapper.java @@ -1,16 +1,18 @@ -package com.yf.exam.modules.sys.config.mapper; +package com.yf.exam.modules.sys.config.mapper; // 包名:表示该类属于 sys.config.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.sys.config.entity.SysConfig; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,用于基本的数据库操作 +import com.yf.exam.modules.sys.config.entity.SysConfig; // 导入 SysConfig 实体类,表示系统配置 /** -*

-* 通用配置Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -public interface SysConfigMapper extends BaseMapper { + *

+ * 通用配置Mapper + *

+ * 该接口继承自 MyBatis-Plus 的 BaseMapper,提供通用的数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +public interface SysConfigMapper extends BaseMapper { // SysConfigMapper 接口,继承自 MyBatis-Plus 的 BaseMapper + // 该接口继承了 BaseMapper,因此自动具备了 CRUD 方法,无需手动实现 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/service/SysConfigService.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/service/SysConfigService.java index 224b09d..7248a90 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/service/SysConfigService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/service/SysConfigService.java @@ -1,22 +1,23 @@ -package com.yf.exam.modules.sys.config.service; +package com.yf.exam.modules.sys.config.service; // 包名:表示该类属于 sys.config.service 包 -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.sys.config.dto.SysConfigDTO; -import com.yf.exam.modules.sys.config.entity.SysConfig; +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 提供的 IService 接口,提供通用的数据库操作 +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; // 导入 SysConfigDTO 类,封装系统配置的数据传输对象 +import com.yf.exam.modules.sys.config.entity.SysConfig; // 导入 SysConfig 实体类,表示系统配置 /** -*

-* 通用配置业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -public interface SysConfigService extends IService { + *

+ * 通用配置业务类 + *

+ * 该接口定义了与系统配置相关的业务逻辑方法 + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +public interface SysConfigService extends IService { // SysConfigService 接口继承 MyBatis-Plus 的 IService 接口,提供 CRUD 操作 /** * 查找配置信息 - * @return + * @return 返回系统配置的 DTO 对象 */ - SysConfigDTO find(); + SysConfigDTO find(); // 定义查找系统配置信息的方法,返回一个 SysConfigDTO 对象 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/config/service/impl/SysConfigServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/config/service/impl/SysConfigServiceImpl.java index d91880c..071f2e6 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/config/service/impl/SysConfigServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/config/service/impl/SysConfigServiceImpl.java @@ -1,34 +1,44 @@ -package com.yf.exam.modules.sys.config.service.impl; +package com.yf.exam.modules.sys.config.service.impl; // 包名:表示该类属于 sys.config.service.impl 包 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.sys.config.dto.SysConfigDTO; -import com.yf.exam.modules.sys.config.entity.SysConfig; -import com.yf.exam.modules.sys.config.mapper.SysConfigMapper; -import com.yf.exam.modules.sys.config.service.SysConfigService; -import org.springframework.stereotype.Service; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 类,用于提供常见的数据库操作 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.sys.config.dto.SysConfigDTO; // 导入 SysConfigDTO 类,封装系统配置的数据传输对象 +import com.yf.exam.modules.sys.config.entity.SysConfig; // 导入 SysConfig 实体类,表示系统配置 +import com.yf.exam.modules.sys.config.mapper.SysConfigMapper; // 导入 SysConfigMapper,数据访问层接口 +import com.yf.exam.modules.sys.config.service.SysConfigService; // 导入 SysConfigService,系统配置服务接口 +import org.springframework.stereotype.Service; // 导入 Spring 注解,用于标识该类为服务层组件 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-17 09:12 -*/ -@Service -public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService { + *

+ * 语言设置 服务实现类 + *

+ * 该类实现了 SysConfigService 接口,提供与系统配置相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-17 09:12 + */ +@Service // Spring 注解,标识该类为服务层组件 +public class SysConfigServiceImpl extends ServiceImpl implements SysConfigService { // 继承 MyBatis-Plus 的 ServiceImpl 类,简化数据库操作 + /** + * 查找系统配置详情 + * @return 返回系统配置的 DTO 对象 + */ @Override public SysConfigDTO find() { + // 创建 QueryWrapper 对象,用于构建查询条件 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.last(" LIMIT 1"); + wrapper.last(" LIMIT 1"); // 限制查询结果为一条记录 - SysConfig entity = this.getOne(wrapper, false); - SysConfigDTO dto = new SysConfigDTO(); - BeanMapper.copy(entity, dto); - return dto; + // 使用 getOne 方法查询系统配置的第一条记录 + SysConfig entity = this.getOne(wrapper, false); // false 表示不抛出异常,如果没有结果会返回 null + + // 将查询到的实体对象复制到 DTO 对象 + SysConfigDTO dto = new SysConfigDTO(); // 创建 SysConfigDTO 对象 + BeanMapper.copy(entity, dto); // 使用 BeanMapper 工具类将 SysConfig 实体对象的属性复制到 DTO 中 + + return dto; // 返回系统配置 DTO } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/controller/SysDepartController.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/controller/SysDepartController.java index 486fa9a..1565a96 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/controller/SysDepartController.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/controller/SysDepartController.java @@ -1,150 +1,136 @@ -package com.yf.exam.modules.sys.depart.controller; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdReqDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; -import com.yf.exam.modules.sys.depart.dto.request.DepartSortReqDTO; -import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; -import com.yf.exam.modules.sys.depart.entity.SysDepart; -import com.yf.exam.modules.sys.depart.service.SysDepartService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; +package com.yf.exam.modules.sys.depart.controller; // 包名:表示该类属于 sys.depart.controller 包 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.yf.exam.core.api.ApiRest; // 导入统一的 API 响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入控制器基类,提供通用的控制器功能 +import com.yf.exam.core.api.dto.BaseIdReqDTO; // 导入基本请求 DTO,用于单个 ID 请求 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入基本请求 DTO,用于多个 ID 请求 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; // 导入 SysDepartDTO 数据传输对象 +import com.yf.exam.modules.sys.depart.dto.request.DepartSortReqDTO; // 导入部门排序请求 DTO +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; // 导入部门树状结构响应 DTO +import com.yf.exam.modules.sys.depart.entity.SysDepart; // 导入 SysDepart 实体类,表示部门 +import com.yf.exam.modules.sys.depart.service.SysDepartService; // 导入部门服务接口 +import io.swagger.annotations.Api; // 导入 Swagger 注解,用于 API 文档生成 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 注解,用于定义接口操作说明 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入 Shiro 权限控制注解,限制角色访问 +import org.springframework.beans.BeanUtils; // 导入 Spring 的 BeanUtils,用于对象属性拷贝 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 注解,用于依赖注入 +import org.springframework.web.bind.annotation.RequestBody; // 导入注解,用于绑定请求体 +import org.springframework.web.bind.annotation.RequestMapping; // 导入注解,用于定义请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入注解,用于指定请求方法 +import org.springframework.web.bind.annotation.RestController; // 导入注解,标识该类为 REST 控制器 /** -*

-* 部门信息控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -@Api(tags={"部门信息"}) -@RestController -@RequestMapping("/exam/api/sys/depart") -public class SysDepartController extends BaseController { - - @Autowired + *

+ * 部门信息控制器 + *

+ * 提供与部门相关的操作接口,包括添加、修改、删除、查找等 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +@Api(tags = {"部门信息"}) // Swagger 注解:定义该类的 API 文档标签为“部门信息” +@RestController // Spring 注解:标识该类为 REST 控制器 +@RequestMapping("/exam/api/sys/depart") // 定义请求路径前缀为 /exam/api/sys/depart +public class SysDepartController extends BaseController { // SysDepartController 类,继承自 BaseController,提供通用功能 + + @Autowired // 自动注入 SysDepartService 服务 private SysDepartService baseService; /** - * 添加或修改 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "添加或修改") - @RequestMapping(value = "/save", method = { RequestMethod.POST}) - public ApiRest save(@RequestBody SysDepartDTO reqDTO) { - baseService.save(reqDTO); - return super.success(); + * 添加或修改部门 + * @param reqDTO 请求数据传输对象,包含部门信息 + * @return 返回操作结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "添加或修改") // Swagger 注解:定义接口操作说明为“添加或修改” + @RequestMapping(value = "/save", method = {RequestMethod.POST}) // 定义请求路径为 /save,方法为 POST + public ApiRest save(@RequestBody SysDepartDTO reqDTO) { // 添加或修改部门的方法 + baseService.save(reqDTO); // 调用服务保存或更新部门信息 + return super.success(); // 返回成功响应 } /** - * 批量删除 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) - public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.removeByIds(reqDTO.getIds()); - return super.success(); + * 批量删除部门 + * @param reqDTO 请求数据传输对象,包含待删除的部门 ID 列表 + * @return 返回操作结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "批量删除") // Swagger 注解:定义接口操作说明为“批量删除” + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) // 定义请求路径为 /delete,方法为 POST + public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { // 批量删除部门的方法 + baseService.removeByIds(reqDTO.getIds()); // 根据 ID 列表删除部门 + return super.success(); // 返回成功响应 } /** - * 查找详情 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "查找详情") - @RequestMapping(value = "/detail", method = { RequestMethod.POST}) - public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { - SysDepart entity = baseService.getById(reqDTO.getId()); - SysDepartDTO dto = new SysDepartDTO(); - BeanUtils.copyProperties(entity, dto); - return super.success(dto); + * 查找部门详情 + * @param reqDTO 请求数据传输对象,包含部门 ID + * @return 返回部门详情 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情” + @RequestMapping(value = "/detail", method = {RequestMethod.POST}) // 定义请求路径为 /detail,方法为 POST + public ApiRest find(@RequestBody BaseIdReqDTO reqDTO) { // 查找部门详情的方法 + SysDepart entity = baseService.getById(reqDTO.getId()); // 根据 ID 查找部门实体 + SysDepartDTO dto = new SysDepartDTO(); // 创建部门数据传输对象 + BeanUtils.copyProperties(entity, dto); // 将实体对象属性拷贝到 DTO 对象 + return super.success(dto); // 返回成功响应,包含部门详情 } /** - * 分页查找 - * @param reqDTO - * @return - */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - - return super.success(page); + * 分页查找部门 + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return 返回分页查询结果 + */ + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "分页查找") // Swagger 注解:定义接口操作说明为“分页查找” + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) // 定义请求路径为 /paging,方法为 POST + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 分页查找部门的方法 + IPage page = baseService.paging(reqDTO); // 调用服务进行分页查询 + return super.success(page); // 返回成功响应,包含分页数据 } /** - * 查找列表,每次最多返回200条数据 - * @param reqDTO - * @return + * 查找部门列表,每次最多返回200条数据 + * @param reqDTO 请求数据传输对象,包含查询条件 + * @return 返回部门列表 */ - @RequiresRoles("sa") - @ApiOperation(value = "查找列表") - @RequestMapping(value = "/list", method = { RequestMethod.POST}) - public ApiRest> list(@RequestBody SysDepartDTO reqDTO) { - - //分页查询并转换 - QueryWrapper wrapper = new QueryWrapper<>(); - - //转换并返回 - List list = baseService.list(wrapper); - - //转换数据 - List dtoList = BeanMapper.mapList(list, SysDepartDTO.class); - - return super.success(dtoList); + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "查找列表") // Swagger 注解:定义接口操作说明为“查找列表” + @RequestMapping(value = "/list", method = {RequestMethod.POST}) // 定义请求路径为 /list,方法为 POST + public ApiRest> list(@RequestBody SysDepartDTO reqDTO) { // 查找部门列表的方法 + QueryWrapper wrapper = new QueryWrapper<>(); // 创建查询条件 + List list = baseService.list(wrapper); // 获取部门列表 + List dtoList = BeanMapper.mapList(list, SysDepartDTO.class); // 将部门实体列表转换为 DTO 列表 + return super.success(dtoList); // 返回成功响应,包含部门列表 } - /** - * 树列表 - * @return + * 查找部门树状结构 + * @return 返回部门树状结构 */ - @RequiresRoles("sa") - @ApiOperation(value = "树列表") - @RequestMapping(value = "/tree", method = { RequestMethod.POST}) - public ApiRest> tree() { - List dtoList = baseService.findTree(); - return super.success(dtoList); + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "树列表") // Swagger 注解:定义接口操作说明为“树列表” + @RequestMapping(value = "/tree", method = {RequestMethod.POST}) // 定义请求路径为 /tree,方法为 POST + public ApiRest> tree() { // 查找部门树状结构的方法 + List dtoList = baseService.findTree(); // 获取部门树状结构 + return super.success(dtoList); // 返回成功响应,包含部门树状结构 } - /** - * 分类排序 - * @param reqDTO - * @return + * 部门排序 + * @param reqDTO 请求数据传输对象,包含排序信息 + * @return 返回操作结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "分类排序") - @RequestMapping(value = "/sort", method = { RequestMethod.POST}) - public ApiRest sort(@RequestBody DepartSortReqDTO reqDTO) { - baseService.sort(reqDTO.getId(), reqDTO.getSort()); - return super.success(); + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "分类排序") // Swagger 注解:定义接口操作说明为“分类排序” + @RequestMapping(value = "/sort", method = {RequestMethod.POST}) // 定义请求路径为 /sort,方法为 POST + public ApiRest sort(@RequestBody DepartSortReqDTO reqDTO) { // 部门排序的方法 + baseService.sort(reqDTO.getId(), reqDTO.getSort()); // 调用服务进行排序 + return super.success(); // 返回成功响应 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/SysDepartDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/SysDepartDTO.java index ac34b50..0c407b8 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/SysDepartDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/SysDepartDTO.java @@ -1,42 +1,41 @@ -package com.yf.exam.modules.sys.depart.dto; +package com.yf.exam.modules.sys.depart.dto; // 包名:表示该类属于 sys.depart.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象序列化 /** -*

-* 部门信息数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -@Data -@ApiModel(value="部门信息", description="部门信息") -public class SysDepartDTO implements Serializable { + *

+ * 部门信息数据传输类 + *

+ * 用于传递部门相关的数据 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "部门信息", description = "部门信息") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysDepartDTO implements Serializable { // 实现 Serializable 接口以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:部门的唯一标识符 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "1公司2部门", required = true) // Swagger 注解:描述该属性为“1公司2部门”,并标记为必填 + private Integer deptType; // 定义字段:部门类型,1 表示公司,2 表示部门 - @ApiModelProperty(value = "1公司2部门", required=true) - private Integer deptType; + @ApiModelProperty(value = "所属上级", required = true) // Swagger 注解:描述该属性为“所属上级”,并标记为必填 + private String parentId; // 定义字段:上级部门的 ID - @ApiModelProperty(value = "所属上级", required=true) - private String parentId; + @ApiModelProperty(value = "部门名称", required = true) // Swagger 注解:描述该属性为“部门名称”,并标记为必填 + private String deptName; // 定义字段:部门名称 - @ApiModelProperty(value = "部门名称", required=true) - private String deptName; - - @ApiModelProperty(value = "部门编码", required=true) - private String deptCode; - - @ApiModelProperty(value = "排序", required=true) - private Integer sort; + @ApiModelProperty(value = "部门编码", required = true) // Swagger 注解:描述该属性为“部门编码”,并标记为必填 + private String deptCode; // 定义字段:部门的唯一编码,用于标识部门 + @ApiModelProperty(value = "排序", required = true) // Swagger 注解:描述该属性为“排序”,并标记为必填 + private Integer sort; // 定义字段:部门排序序号,用于定义显示顺序 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/request/DepartSortReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/request/DepartSortReqDTO.java index 92d90ab..e2d61e0 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/request/DepartSortReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/request/DepartSortReqDTO.java @@ -1,28 +1,29 @@ -package com.yf.exam.modules.sys.depart.dto.request; +package com.yf.exam.modules.sys.depart.dto.request; // 包名:表示该类属于 sys.depart.dto.request 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于对象序列化 /** -*

-* 部门排序请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-03-14 10:37 -*/ -@Data -@ApiModel(value="部门排序请求类", description="部门排序请求类") -public class DepartSortReqDTO implements Serializable { + *

+ * 部门排序请求类 + *

+ * 封装部门排序请求的数据传输对象 + * + * @作者 聪明笨狗 + * @版本 2020-03-14 10:37 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "部门排序请求类", description = "部门排序请求类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class DepartSortReqDTO implements Serializable { // 实现 Serializable 接口以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "分类ID") - private String id; + @ApiModelProperty(value = "分类ID") // Swagger 注解:描述该属性为“分类ID” + private String id; // 定义字段:分类的唯一标识符 - @ApiModelProperty(value = "排序,0下降,1上升") - private Integer sort; + @ApiModelProperty(value = "排序,0下降,1上升") // Swagger 注解:描述该属性为“排序”,0 表示下降,1 表示上升 + private Integer sort; // 定义字段:排序方式,0 为下降排序,1 为上升排序 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/response/SysDepartTreeDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/response/SysDepartTreeDTO.java index ab6b9d3..4b4cb06 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/response/SysDepartTreeDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/dto/response/SysDepartTreeDTO.java @@ -1,28 +1,27 @@ -package com.yf.exam.modules.sys.depart.dto.response; +package com.yf.exam.modules.sys.depart.dto.response; // 包名:表示该类属于 sys.depart.dto.response 包 -import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; // 导入 SysDepartDTO 类,表示部门的基本信息 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.util.List; +import java.util.List; // 导入 List 接口,用于存储子部门列表 /** -*

-* 部门树结构响应类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -@Data -@ApiModel(value="部门树结构响应类", description="部门树结构响应类") -public class SysDepartTreeDTO extends SysDepartDTO { + *

+ * 部门树结构响应类 + *

+ * 用于返回树形结构的部门数据 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "部门树结构响应类", description = "部门树结构响应类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysDepartTreeDTO extends SysDepartDTO { // 继承 SysDepartDTO,扩展支持树形结构 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "子列表", required=true) - private List children; - - + @ApiModelProperty(value = "子列表", required = true) // Swagger 注解:描述该属性为“子列表”,标记为必填 + private List children; // 定义字段:子部门列表,支持递归嵌套表示树形结构 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/entity/SysDepart.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/entity/SysDepart.java index 71ca156..beeea32 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/entity/SysDepart.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/entity/SysDepart.java @@ -1,59 +1,59 @@ -package com.yf.exam.modules.sys.depart.entity; +package com.yf.exam.modules.sys.depart.entity; // 包名:表示该类属于 sys.depart.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于定义主键类型 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于映射数据库字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于标识主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于映射数据库表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus 的 Model 基类,用于支持 ActiveRecord 模式 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 /** -*

-* 部门信息实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -@Data -@TableName("sys_depart") -public class SysDepart extends Model { + *

+ * 部门信息实体类 + *

+ * 表示数据库中部门信息的实体类,与 `sys_depart` 表对应 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("sys_depart") // MyBatis-Plus 注解,指定该类映射的数据库表名为 `sys_depart` +public class SysDepart extends Model { // 继承 MyBatis-Plus 的 Model 类,支持 ActiveRecord 模式 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,指定主键字段及其生成策略为 ASSIGN_ID + private String id; // 部门的唯一标识符 /** - * 1公司2部门 - */ - @TableField("dept_type") - private Integer deptType; + * 1公司2部门 + */ + @TableField("dept_type") // MyBatis-Plus 注解,指定该字段映射数据库中的 `dept_type` 列 + private Integer deptType; // 部门类型,1 表示公司,2 表示部门 /** - * 所属上级 - */ - @TableField("parent_id") - private String parentId; + * 所属上级 + */ + @TableField("parent_id") // MyBatis-Plus 注解,指定该字段映射数据库中的 `parent_id` 列 + private String parentId; // 上级部门的 ID,用于定义层级关系 /** - * 部门名称 - */ - @TableField("dept_name") - private String deptName; + * 部门名称 + */ + @TableField("dept_name") // MyBatis-Plus 注解,指定该字段映射数据库中的 `dept_name` 列 + private String deptName; // 部门的名称,用于显示和标识部门 /** - * 部门编码 - */ - @TableField("dept_code") - private String deptCode; + * 部门编码 + */ + @TableField("dept_code") // MyBatis-Plus 注解,指定该字段映射数据库中的 `dept_code` 列 + private String deptCode; // 部门的唯一编码,用于标识部门 /** - * 排序 - */ - private Integer sort; - + * 排序 + */ + private Integer sort; // 排序字段,用于定义部门显示的顺序 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/mapper/SysDepartMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/mapper/SysDepartMapper.java index 221ab89..e26b893 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/mapper/SysDepartMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/mapper/SysDepartMapper.java @@ -1,28 +1,29 @@ -package com.yf.exam.modules.sys.depart.mapper; +package com.yf.exam.modules.sys.depart.mapper; // 包名:表示该类属于 sys.depart.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; -import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; -import com.yf.exam.modules.sys.depart.entity.SysDepart; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,用于提供基础的数据库操作 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的分页接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页插件中的 Page 类 +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; // 导入部门数据传输对象,用于封装查询条件 +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; // 导入部门树形结构响应对象 +import com.yf.exam.modules.sys.depart.entity.SysDepart; // 导入部门实体类 +import org.apache.ibatis.annotations.Param; // 导入 MyBatis 注解,用于标注参数 /** -*

-* 部门信息Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -public interface SysDepartMapper extends BaseMapper { + *

+ * 部门信息Mapper + *

+ * 定义部门信息的数据库操作接口 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +public interface SysDepartMapper extends BaseMapper { // SysDepartMapper 接口,继承 MyBatis-Plus 的 BaseMapper /** * 部门树分页 - * @param page - * @param query - * @return + * @param page 分页对象,包含当前页码和每页大小 + * @param query 查询条件,封装了部门查询的参数 + * @return 返回分页结果,包含部门树形结构数据 */ - IPage paging(Page page, @Param("query") SysDepartDTO query); + IPage paging(Page page, @Param("query") SysDepartDTO query); // 自定义分页查询方法,返回部门树形结构的分页数据 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/SysDepartService.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/SysDepartService.java index 1b70e83..9f8aa8c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/SysDepartService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/SysDepartService.java @@ -1,62 +1,62 @@ -package com.yf.exam.modules.sys.depart.service; +package com.yf.exam.modules.sys.depart.service; // 包名:表示该接口属于 sys.depart.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; -import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; -import com.yf.exam.modules.sys.depart.entity.SysDepart; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的分页接口,用于返回分页查询结果 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,用于提供通用的数据库操作 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; // 导入 SysDepartDTO 数据传输对象,用于封装部门数据 +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; // 导入 SysDepartTreeDTO 类,用于表示部门树形结构 +import com.yf.exam.modules.sys.depart.entity.SysDepart; // 导入 SysDepart 实体类,表示部门 -import java.util.List; +import java.util.List; // 导入 List 接口,用于存储部门 ID 或部门列表 /** -*

-* 部门信息业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -public interface SysDepartService extends IService { + *

+ * 部门信息业务类 + *

+ * 该接口定义了与部门相关的业务逻辑操作,如保存、分页查询、排序、查找部门树等 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +public interface SysDepartService extends IService { // SysDepartService 接口继承 MyBatis-Plus 的 IService 接口,提供 CRUD 操作 /** - * 保存 - * @param reqDTO + * 保存部门信息 + * @param reqDTO 部门数据传输对象 */ - void save(SysDepartDTO reqDTO); + void save(SysDepartDTO reqDTO); // 保存部门信息方法,接收部门数据传输对象 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + * 分页查询部门树形结构 + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return 返回分页查询结果,包含部门树形结构数据 + */ + IPage paging(PagingReqDTO reqDTO); // 分页查询部门树的方法 /** - * 查找部门树结构 - * @return + * 查找所有部门的树形结构 + * @return 返回所有部门的树形结构列表 */ - List findTree(); + List findTree(); // 查找所有部门树的方法,返回树形结构数据 /** - * 查找部门树 - * @param ids - * @return + * 查找指定部门ID列表下的部门树 + * @param ids 部门ID列表,用于筛选特定部门的树形结构 + * @return 返回部门树形结构列表 */ - List findTree(List ids); + List findTree(List ids); // 查找指定部门ID列表下的部门树的方法 /** - * 排序 - * @param id - * @param sort + * 排序部门 + * @param id 部门ID + * @param sort 排序方式,0为上升,1为下降 */ - void sort(String id, Integer sort); - + void sort(String id, Integer sort); // 排序部门的方法,支持上升和下降排序 /** * 获取某个部门ID下的所有子部门ID - * @param id - * @return + * @param id 部门ID + * @return 返回该部门下所有子部门的ID列表 */ - List listAllSubIds( String id); + List listAllSubIds(String id); // 获取某个部门下所有子部门ID的方法 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/impl/SysDepartServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/impl/SysDepartServiceImpl.java index 1ba267f..4d36279 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/impl/SysDepartServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/depart/service/impl/SysDepartServiceImpl.java @@ -1,227 +1,233 @@ -package com.yf.exam.modules.sys.depart.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; -import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; -import com.yf.exam.modules.sys.depart.entity.SysDepart; -import com.yf.exam.modules.sys.depart.mapper.SysDepartMapper; -import com.yf.exam.modules.sys.depart.service.SysDepartService; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +package com.yf.exam.modules.sys.depart.service.impl; // 包名:表示该类属于 sys.depart.service.impl 包 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 分页插件中的 Page 类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 类,用于提供通用的数据库操作 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.sys.depart.dto.SysDepartDTO; // 导入 SysDepartDTO 类,封装部门数据传输对象 +import com.yf.exam.modules.sys.depart.dto.response.SysDepartTreeDTO; // 导入 SysDepartTreeDTO 类,用于部门树形结构 +import com.yf.exam.modules.sys.depart.entity.SysDepart; // 导入 SysDepart 实体类,表示部门 +import com.yf.exam.modules.sys.depart.mapper.SysDepartMapper; // 导入部门的 Mapper 接口,用于数据库交互 +import com.yf.exam.modules.sys.depart.service.SysDepartService; // 导入部门服务接口 +import org.apache.commons.lang3.StringUtils; // 导入 Apache Commons Lang3 库中的 StringUtils,用于字符串操作 +import org.springframework.stereotype.Service; // 导入 Spring 注解,用于标识该类为服务层组件 +import org.springframework.util.CollectionUtils; // 导入 Spring 的 CollectionUtils 工具类,用于集合操作 + +import java.util.ArrayList; // 导入 ArrayList 类,用于列表数据存储 +import java.util.HashMap; // 导入 HashMap 类,用于映射键值对 +import java.util.List; // 导入 List 接口,用于存储列表数据 +import java.util.Map; // 导入 Map 接口,用于映射键值对 /** -*

-* 部门信息业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-02 17:25 -*/ -@Service -public class SysDepartServiceImpl extends ServiceImpl implements SysDepartService { - + *

+ * 部门信息业务实现类 + *

+ * 该类实现了 SysDepartService 接口,提供与部门相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-09-02 17:25 + */ +@Service // Spring 注解,标识该类为服务层组件 +public class SysDepartServiceImpl extends ServiceImpl implements SysDepartService { // 继承 MyBatis-Plus 的 ServiceImpl 类,简化数据库操作 /** * 0标识为顶级分类 */ - private static final String ROOT_TAG = "0"; - + private static final String ROOT_TAG = "0"; // 顶级部门标识符 + /** + * 保存或更新部门信息 + * @param reqDTO 部门数据传输对象 + */ @Override public void save(SysDepartDTO reqDTO) { + // 如果部门ID为空,生成部门编码 if(StringUtils.isBlank(reqDTO.getId())) { - this.fillCode(reqDTO); - }else{ - reqDTO.setSort(null); - reqDTO.setDeptCode(null); + this.fillCode(reqDTO); // 填充部门编码 + } else { + reqDTO.setSort(null); // 如果有ID,则清空排序字段 + reqDTO.setDeptCode(null); // 清空部门编码 } - SysDepart entity = new SysDepart(); - BeanMapper.copy(reqDTO, entity); - this.saveOrUpdate(entity); + SysDepart entity = new SysDepart(); // 创建部门实体对象 + BeanMapper.copy(reqDTO, entity); // 将 DTO 数据拷贝到实体对象 + this.saveOrUpdate(entity); // 保存或更新部门信息 } + /** + * 分页查询部门树形结构 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询结果 + */ @Override public IPage paging(PagingReqDTO reqDTO) { // 创建分页对象 Page query = new Page(reqDTO.getCurrent(), reqDTO.getSize()); - // 请求参数 + // 获取查询条件 SysDepartDTO params = reqDTO.getParams(); - //转换结果 + // 执行分页查询 IPage pageData = baseMapper.paging(query, params); - return pageData; - } - + return pageData; // 返回分页结果 + } + /** + * 查找所有部门树 + * @return 返回部门树形结构 + */ @Override public List findTree() { - return this.findTree(null); + return this.findTree(null); // 默认查找所有部门 } + /** + * 查找指定ID的部门树 + * @param ids 部门ID列表 + * @return 返回部门树形结构 + */ @Override public List findTree(List ids) { + QueryWrapper wrapper = new QueryWrapper<>(); // 创建查询条件 + wrapper.lambda().orderByAsc(SysDepart::getSort); // 按照排序字段升序排列 - QueryWrapper wrapper = new QueryWrapper(); - wrapper.lambda().orderByAsc(SysDepart::getSort); - + // 如果传入了部门ID列表,递归获取所有父级部门 if(!CollectionUtils.isEmpty(ids)){ - List fullIds = new ArrayList<>(); + List fullIds = new ArrayList<>(); // 用于存储所有父部门ID for(String id: ids){ - this.cycleAllParent(fullIds, id); + this.cycleAllParent(fullIds, id); // 递归获取所有父部门ID } if(!CollectionUtils.isEmpty(fullIds)){ - wrapper.lambda().in(SysDepart::getId, fullIds); + wrapper.lambda().in(SysDepart::getId, fullIds); // 根据部门ID列表查询 } } - //全部列表 - List list = this.list(wrapper); - List dtoList = BeanMapper.mapList(list, SysDepartTreeDTO.class); - - //子结构的列表 - Map> map = new HashMap<>(16); + // 获取所有部门数据 + List list = this.list(wrapper); + List dtoList = BeanMapper.mapList(list, SysDepartTreeDTO.class); // 将部门实体列表转换为部门树形结构DTO列表 + // 构建子部门的映射关系 + Map> map = new HashMap<>(16); for(SysDepartTreeDTO item: dtoList){ - - //如果存在 + // 如果当前部门已经有子部门,直接添加 if(map.containsKey(item.getParentId())){ map.get(item.getParentId()).add(item); continue; } - //增加新的结构 + // 如果没有子部门,则新建一个子部门列表 List a = new ArrayList<>(); a.add(item); map.put(item.getParentId(), a); } - //注意,第0级为顶级的 + // 获取顶级部门(parentId 为 ROOT_TAG) List topList = map.get(ROOT_TAG); if(!CollectionUtils.isEmpty(topList)){ for(SysDepartTreeDTO item: topList){ - this.fillChildren(map, item); + this.fillChildren(map, item); // 填充子部门 } } - return topList; + return topList; // 返回顶级部门及其子部门树 } + /** + * 排序部门 + * @param id 部门ID + * @param sort 排序方式,0为上升,1为下降 + */ @Override public void sort(String id, Integer sort) { - SysDepart depart = this.getById(id); + SysDepart depart = this.getById(id); // 获取部门实体 SysDepart exchange = null; - QueryWrapper wrapper = new QueryWrapper<>(); - // 同级排序 - wrapper.lambda() - .eq(SysDepart::getParentId, depart.getParentId()); + QueryWrapper wrapper = new QueryWrapper<>(); // 创建查询条件 + // 根据部门的父ID查询同级别的部门 + wrapper.lambda().eq(SysDepart::getParentId, depart.getParentId()); wrapper.last("LIMIT 1"); - // 上升 + // 上升排序 if(sort == 0){ - // 同级排序 - wrapper.lambda() - .lt(SysDepart::getSort, depart.getSort()) - .orderByDesc(SysDepart::getSort); - exchange = this.getOne(wrapper, false); + wrapper.lambda().lt(SysDepart::getSort, depart.getSort()).orderByDesc(SysDepart::getSort); // 查找排序小于当前部门的部门 + exchange = this.getOne(wrapper, false); // 获取交换部门 } - // 下降 + // 下降排序 if(sort == 1){ - // 同级排序 - wrapper.lambda() - .gt(SysDepart::getSort, depart.getSort()) - .orderByAsc(SysDepart::getSort); - exchange = this.getOne(wrapper, false); + wrapper.lambda().gt(SysDepart::getSort, depart.getSort()).orderByAsc(SysDepart::getSort); // 查找排序大于当前部门的部门 + exchange = this.getOne(wrapper, false); // 获取交换部门 } - - if(exchange!=null) { + // 如果找到了交换的部门,进行交换排序 + if(exchange != null) { SysDepart a = new SysDepart(); a.setId(id); a.setSort(exchange.getSort()); SysDepart b = new SysDepart(); b.setId(exchange.getId()); b.setSort(depart.getSort()); - this.updateById(a); - this.updateById(b); + this.updateById(a); // 更新部门a的排序 + this.updateById(b); // 更新部门b的排序 } } /** - * 获取部门编号 - * @param reqDTO - * @return + * 填充部门编码 + * @param reqDTO 部门数据传输对象 */ private void fillCode(SysDepartDTO reqDTO){ - // 前缀 String code = ""; - if(StringUtils.isNotBlank(reqDTO.getParentId()) - && !ROOT_TAG.equals(reqDTO.getParentId())){ + // 获取上级部门编码 + if(StringUtils.isNotBlank(reqDTO.getParentId()) && !ROOT_TAG.equals(reqDTO.getParentId())){ SysDepart parent = this.getById(reqDTO.getParentId()); - code = parent.getDeptCode(); + code = parent.getDeptCode(); // 获取上级部门的编码 } QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.lambda().eq(SysDepart::getParentId, reqDTO.getParentId()).orderByDesc(SysDepart::getSort); // 查询同级部门 - // 同级排序 - wrapper.lambda() - .eq(SysDepart::getParentId, reqDTO.getParentId()) - .orderByDesc(SysDepart::getSort); - wrapper.last("LIMIT 1"); SysDepart depart = this.getOne(wrapper, false); - - if(depart !=null){ - code += this.formatCode(depart.getSort()+1); - reqDTO.setSort(depart.getSort()+1); - }else{ - code += this.formatCode(1); - reqDTO.setSort(1); + if(depart != null){ + code += this.formatCode(depart.getSort() + 1); // 根据排序生成部门编码 + reqDTO.setSort(depart.getSort() + 1); // 设置部门的排序 + } else { + code += this.formatCode(1); // 如果没有同级部门,则从1开始 + reqDTO.setSort(1); // 设置部门的排序为1 } - reqDTO.setDeptCode(code); + reqDTO.setDeptCode(code); // 设置部门编码 } /** - * 根式化加0 - * @param sort - * @return + * 格式化部门编码 + * @param sort 排序值 + * @return 返回格式化后的部门编码 */ private String formatCode(Integer sort){ if(sort < 10){ - return "A0"+sort; + return "A0" + sort; // 排序小于10时,返回带前导零的编码 } - return "A"+sort; + return "A" + sort; // 排序大于或等于10时,返回正常编码 } /** - * 递归去做填充数据 - * @param map - * @param item + * 填充子部门列表 + * @param map 部门映射关系 + * @param item 当前部门对象 */ - private void fillChildren(Map> map, SysDepartTreeDTO item){ + private void fillChildren(Map> map, SysDepartTreeDTO item){ //设置子类 if(map.containsKey(item.getId())){ @@ -229,60 +235,61 @@ public class SysDepartServiceImpl extends ServiceImpl children = map.get(item.getId()); if(!CollectionUtils.isEmpty(children)){ for(SysDepartTreeDTO sub: children){ - this.fillChildren(map, sub); + this.fillChildren(map, sub); // 递归填充子部门 } } - item.setChildren(children); + item.setChildren(children); // 设置子部门列表 } } - + /** + * 获取所有子部门的ID列表 + * @param id 部门ID + * @return 返回所有子部门的ID列表 + */ @Override - public List listAllSubIds( String id){ + public List listAllSubIds(String id){ List ids = new ArrayList<>(); - this.cycleAllSubs(ids, id); + this.cycleAllSubs(ids, id); // 递归获取所有子部门的ID return ids; } - /** - * 递归所有子级别ID - * @param list - * @param id + * 递归获取所有子部门的ID + * @param list 用于存储子部门ID的列表 + * @param id 当前部门ID */ private void cycleAllSubs(List list, String id){ - // 添加ID + // 添加当前部门ID list.add(id); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() .eq(SysDepart::getParentId, id) - .orderByDesc(SysDepart::getSort); + .orderByDesc(SysDepart::getSort); // 查询当前部门的所有子部门 List subList = this.list(wrapper); if(!CollectionUtils.isEmpty(subList)){ for(SysDepart item: subList){ - this.cycleAllSubs(list, item.getId()); + this.cycleAllSubs(list, item.getId()); // 递归查询子部门 } } } /** - * 递归所有子级别ID - * @param list - * @param id + * 递归获取所有父部门的ID + * @param list 用于存储父部门ID的列表 + * @param id 当前部门ID */ private void cycleAllParent(List list, String id){ - // 往上递归获得父类 + // 往上递归获取父部门 list.add(id); SysDepart depart = this.getById(id); - if(StringUtils.isNotBlank(depart.getParentId()) - && !ROOT_TAG.equals(depart.getParentId())){ - this.cycleAllParent(list, depart.getParentId()); + if(StringUtils.isNotBlank(depart.getParentId()) && !ROOT_TAG.equals(depart.getParentId())){ + this.cycleAllParent(list, depart.getParentId()); // 递归查询父部门 } - } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/system/mapper/SysDictMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/system/mapper/SysDictMapper.java index 7910881..85494ef 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/system/mapper/SysDictMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/system/mapper/SysDictMapper.java @@ -1,29 +1,30 @@ -package com.yf.exam.modules.sys.system.mapper; +package com.yf.exam.modules.sys.system.mapper; // 包名:表示该接口属于 sys.system.mapper 包 -import org.apache.ibatis.annotations.Mapper; -import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Mapper; // 导入 MyBatis 的 @Mapper 注解,表示这是一个 Mapper 接口 +import org.apache.ibatis.annotations.Param; // 导入 MyBatis 的 @Param 注解,用于指定参数名称 /** -*

-* 机主信息Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-08-22 13:46 -*/ -@Mapper + *

+ * 机主信息Mapper + *

+ * 该接口用于操作数据字典,提供查找数据字典的方法 + * + * @作者 聪明笨狗 + * @版本 2020-08-22 13:46 + */ +@Mapper // MyBatis 注解,表示该接口为 Mapper 接口,MyBatis 会自动生成相应的实现 public interface SysDictMapper { /** * 查找数据字典 - * @param table - * @param text - * @param key - * @param value - * @return + * @param table 数据表名称 + * @param text 字段文本 + * @param key 字段键值 + * @param value 字段值 + * @return 返回字典数据的对应值 */ - String findDict(@Param("table") String table, - @Param("text") String text, - @Param("key") String key, - @Param("value") String value); + String findDict(@Param("table") String table, // 使用 @Param 注解绑定 SQL 参数名 + @Param("text") String text, // 绑定 SQL 参数 text + @Param("key") String key, // 绑定 SQL 参数 key + @Param("value") String value); // 绑定 SQL 参数 value } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/system/service/SysDictService.java b/src-源文件/main/java/com/yf/exam/modules/sys/system/service/SysDictService.java index ab8abd2..6e933ec 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/system/service/SysDictService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/system/service/SysDictService.java @@ -1,21 +1,25 @@ -package com.yf.exam.modules.sys.system.service; +package com.yf.exam.modules.sys.system.service; // 包名:表示该接口属于 sys.system.service 包 /** * 数据字典工具类 - * @author bool + * 提供与数据字典相关的业务方法 + * + * @作者 bool */ -public interface SysDictService { +public interface SysDictService { // 定义 SysDictService 接口,提供数据字典的服务 /** * 查找数据字典 - * @param table - * @param text - * @param key - * @param value - * @return + * 根据给定的表、字段文本、键和值查找数据字典中的对应数据 + * + * @param table 数据表名称 + * @param text 字段文本,用于描述字段内容 + * @param key 字段键值,用于匹配字典数据 + * @param value 字段值,用于匹配字典数据 + * @return 返回数据字典中的对应值 */ - String findDict(String table, - String text, - String key, - String value); + String findDict(String table, // 表示字典数据的表名 + String text, // 字段文本,用于描述字段 + String key, // 字段的键 + String value); // 字段的值,查询条件之一 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/system/service/impl/SysDictServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/system/service/impl/SysDictServiceImpl.java index 033ed67..623ce4b 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/system/service/impl/SysDictServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/system/service/impl/SysDictServiceImpl.java @@ -1,21 +1,30 @@ -package com.yf.exam.modules.sys.system.service.impl; +package com.yf.exam.modules.sys.system.service.impl; // 包名:表示该类属于 sys.system.service.impl 包 -import com.yf.exam.modules.sys.system.mapper.SysDictMapper; -import com.yf.exam.modules.sys.system.service.SysDictService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; +import com.yf.exam.modules.sys.system.mapper.SysDictMapper; // 导入 SysDictMapper 接口,用于操作数据字典 +import com.yf.exam.modules.sys.system.service.SysDictService; // 导入 SysDictService 接口,定义数据字典的业务逻辑 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 的 @Autowired 注解,用于自动注入依赖 +import org.springframework.stereotype.Service; // 导入 Spring 的 @Service 注解,用于标识该类为服务层组件 /** + * SysDictServiceImpl 类提供了数据字典的业务逻辑实现 * @author bool */ -@Service -public class SysDictServiceImpl implements SysDictService { +@Service // Spring 注解,标识该类为服务层组件 +public class SysDictServiceImpl implements SysDictService { // 实现 SysDictService 接口 - @Autowired + @Autowired // 自动注入 SysDictMapper private SysDictMapper sysDictMapper; + /** + * 查找数据字典 + * @param table 数据表名称 + * @param text 字段文本 + * @param key 字段键值 + * @param value 字段值 + * @return 返回字典数据的对应值 + */ @Override public String findDict(String table, String text, String key, String value) { - return sysDictMapper.findDict(table, text, key, value); + return sysDictMapper.findDict(table, text, key, value); // 调用 Mapper 层的方法查找字典数据 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysRoleController.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysRoleController.java index dab2bc2..de3402e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysRoleController.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysRoleController.java @@ -1,77 +1,75 @@ -package com.yf.exam.modules.sys.user.controller; +package com.yf.exam.modules.sys.user.controller; // 包名:表示该类属于 sys.user.controller 包 -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.modules.sys.user.dto.SysRoleDTO; -import com.yf.exam.modules.sys.user.entity.SysRole; -import com.yf.exam.modules.sys.user.service.SysRoleService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.yf.exam.core.api.ApiRest; // 导入统一的 API 响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入基类控制器,提供通用功能 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象属性拷贝 +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; // 导入 SysRoleDTO 数据传输对象 +import com.yf.exam.modules.sys.user.entity.SysRole; // 导入 SysRole 实体类,表示角色 +import com.yf.exam.modules.sys.user.service.SysRoleService; // 导入 SysRoleService 服务接口 +import io.swagger.annotations.Api; // 导入 Swagger 注解,用于定义 API 文档 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 注解,用于描述接口操作 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入 Shiro 注解,用于权限控制,限制访问角色 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 注解,用于自动注入依赖 +import org.springframework.web.bind.annotation.RequestBody; // 导入注解,用于绑定请求体 +import org.springframework.web.bind.annotation.RequestMapping; // 导入注解,用于定义请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入注解,用于指定请求方法 +import org.springframework.web.bind.annotation.RestController; // 导入注解,标识该类为 REST 控制器 -import java.util.List; +import java.util.List; // 导入 List 接口,用于存储角色列表 /** *

* 管理用户控制器 *

- * - * @author 聪明笨狗 - * @since 2020-04-13 16:57 + * 该类用于处理角色管理相关的请求 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 */ -@Api(tags = {"管理用户"}) -@RestController -@RequestMapping("/exam/api/sys/role") -public class SysRoleController extends BaseController { +@Api(tags = {"管理用户"}) // Swagger 注解:定义该类的 API 文档标签为“管理用户” +@RestController // Spring 注解:标识该类为 REST 控制器,处理 HTTP 请求 +@RequestMapping("/exam/api/sys/role") // 定义请求路径前缀为 /exam/api/sys/role +public class SysRoleController extends BaseController { // SysRoleController 继承自 BaseController,提供通用功能 - @Autowired + @Autowired // 自动注入 SysRoleService 服务 private SysRoleService baseService; - - - /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找角色信息 + * @param reqDTO 分页请求数据传输对象,包含分页信息和查询条件 + * @return 返回分页查询结果,包含角色数据 */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "分页查找") // Swagger 注解:描述接口操作为“分页查找” + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // 请求路径为 /paging,方法为 POST public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - //分页查询并转换 - IPage page = baseService.paging(reqDTO); - return super.success(page); + // 调用服务层进行分页查询,并返回角色数据 + IPage page = baseService.paging(reqDTO); + return super.success(page); // 返回成功响应,包含分页数据 } /** - * 查找列表,每次最多返回200条数据 - * @return + * 查找所有角色列表,每次最多返回200条数据 + * @return 返回角色列表 */ - @RequiresRoles("sa") - @ApiOperation(value = "查找列表") - @RequestMapping(value = "/list", method = { RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "查找列表") // Swagger 注解:描述接口操作为“查找列表” + @RequestMapping(value = "/list", method = { RequestMethod.POST}) // 请求路径为 /list,方法为 POST public ApiRest> list() { - //分页查询并转换 - QueryWrapper wrapper = new QueryWrapper<>(); + // 创建查询条件 + QueryWrapper wrapper = new QueryWrapper<>(); - //转换并返回 - List list = baseService.list(wrapper); + // 获取所有角色数据 + List list = baseService.list(wrapper); - //转换数据 + // 将角色实体数据转换为角色数据传输对象 List dtoList = BeanMapper.mapList(list, SysRoleDTO.class); - return super.success(dtoList); + return super.success(dtoList); // 返回成功响应,包含角色列表 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysUserController.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysUserController.java index 757c5e3..3c6aef1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysUserController.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/controller/SysUserController.java @@ -1,182 +1,185 @@ -package com.yf.exam.modules.sys.user.controller; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.BaseStateReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.sys.user.dto.SysUserDTO; -import com.yf.exam.modules.sys.user.dto.request.SysUserLoginReqDTO; -import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import com.yf.exam.modules.sys.user.entity.SysUser; -import com.yf.exam.modules.sys.user.service.SysUserService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.apache.shiro.authz.annotation.RequiresRoles; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import javax.servlet.http.HttpServletRequest; +package com.yf.exam.modules.sys.user.controller; // 包名:表示该类属于 sys.user.controller 包 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.yf.exam.core.api.ApiRest; // 导入统一的 API 响应类 +import com.yf.exam.core.api.controller.BaseController; // 导入基类控制器,提供通用功能 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入基本请求 DTO,用于处理多个 ID 请求 +import com.yf.exam.core.api.dto.BaseStateReqDTO; // 导入基本状态请求 DTO,用于更新状态 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO +import com.yf.exam.modules.sys.user.dto.SysUserDTO; // 导入 SysUserDTO 数据传输对象 +import com.yf.exam.modules.sys.user.dto.request.SysUserLoginReqDTO; // 导入 SysUserLoginReqDTO 登录请求 DTO +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; // 导入 SysUserSaveReqDTO 保存请求 DTO +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 导入 SysUserLoginDTO 登录响应 DTO +import com.yf.exam.modules.sys.user.entity.SysUser; // 导入 SysUser 实体类,表示系统用户 +import com.yf.exam.modules.sys.user.service.SysUserService; // 导入 SysUserService 服务接口 +import io.swagger.annotations.Api; // 导入 Swagger 注解,用于定义 API 文档 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 注解,用于描述接口操作 +import org.apache.shiro.authz.annotation.RequiresRoles; // 导入 Shiro 注解,用于角色权限控制 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Spring 注解,用于自动注入依赖 +import org.springframework.web.bind.annotation.CrossOrigin; // 导入 Spring 注解,用于启用跨域请求 +import org.springframework.web.bind.annotation.RequestBody; // 导入 Spring 注解,用于请求体绑定 +import org.springframework.web.bind.annotation.RequestMapping; // 导入 Spring 注解,用于指定请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入 Spring 注解,用于指定请求方法 +import org.springframework.web.bind.annotation.RequestParam; // 导入 Spring 注解,用于请求参数绑定 +import org.springframework.web.bind.annotation.RestController; // 导入 Spring 注解,标识该类为 REST 控制器 + +import javax.servlet.http.HttpServletRequest; // 导入 HttpServletRequest 类,用于获取 HTTP 请求 /** *

* 管理用户控制器 *

- * - * @author 聪明笨狗 - * @since 2020-04-13 16:57 + * 该类用于处理用户相关的请求,包括登录、注册、修改用户资料等 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 */ -@Api(tags = {"管理用户"}) -@RestController -@RequestMapping("/exam/api/sys/user") -public class SysUserController extends BaseController { +@Api(tags = {"管理用户"}) // Swagger 注解:定义该类的 API 文档标签为“管理用户” +@RestController // Spring 注解:标识该类为 REST 控制器,处理 HTTP 请求 +@RequestMapping("/exam/api/sys/user") // 定义请求路径前缀为 /exam/api/sys/user +public class SysUserController extends BaseController { // SysUserController 类继承 BaseController,提供通用功能 - @Autowired + @Autowired // 自动注入 SysUserService 服务 private SysUserService baseService; /** * 用户登录 - * @return + * @param reqDTO 登录请求 DTO,包含用户名和密码 + * @return 返回用户登录信息 */ - @CrossOrigin - @ApiOperation(value = "用户登录") - @RequestMapping(value = "/login", method = {RequestMethod.POST}) + @CrossOrigin // 允许跨域请求 + @ApiOperation(value = "用户登录") // Swagger 注解:描述接口操作为“用户登录” + @RequestMapping(value = "/login", method = {RequestMethod.POST}) // 请求路径为 /login,方法为 POST public ApiRest login(@RequestBody SysUserLoginReqDTO reqDTO) { - SysUserLoginDTO respDTO = baseService.login(reqDTO.getUsername(), reqDTO.getPassword()); - return super.success(respDTO); + SysUserLoginDTO respDTO = baseService.login(reqDTO.getUsername(), reqDTO.getPassword()); // 调用服务层的登录方法 + return super.success(respDTO); // 返回成功响应,包含用户登录信息 } /** - * 用户登录 - * @return + * 用户登出 + * @param request HTTP 请求对象,用于获取请求头中的 token + * @return 返回成功响应 */ - @CrossOrigin - @ApiOperation(value = "用户登录") - @RequestMapping(value = "/logout", method = {RequestMethod.POST}) + @CrossOrigin // 允许跨域请求 + @ApiOperation(value = "用户登出") // Swagger 注解:描述接口操作为“用户登出” + @RequestMapping(value = "/logout", method = {RequestMethod.POST}) // 请求路径为 /logout,方法为 POST public ApiRest logout(HttpServletRequest request) { - String token = request.getHeader("token"); - System.out.println("+++++当前会话为:"+token); - baseService.logout(token); - return super.success(); + String token = request.getHeader("token"); // 获取请求头中的 token + System.out.println("+++++当前会话为:" + token); // 打印当前会话的 token + baseService.logout(token); // 调用服务层的登出方法 + return super.success(); // 返回成功响应 } /** - * 获取会话 - * @return + * 获取当前会话信息 + * @param token 会话 token + * @return 返回当前会话信息 */ - @ApiOperation(value = "获取会话") - @RequestMapping(value = "/info", method = {RequestMethod.POST}) + @ApiOperation(value = "获取会话") // Swagger 注解:描述接口操作为“获取会话” + @RequestMapping(value = "/info", method = {RequestMethod.POST}) // 请求路径为 /info,方法为 POST public ApiRest info(@RequestParam("token") String token) { - SysUserLoginDTO respDTO = baseService.token(token); - return success(respDTO); + SysUserLoginDTO respDTO = baseService.token(token); // 根据 token 获取当前会话信息 + return success(respDTO); // 返回会话信息 } /** * 修改用户资料 - * @return + * @param reqDTO 用户资料 DTO,包含修改后的用户信息 + * @return 返回成功响应 */ - @ApiOperation(value = "修改用户资料") - @RequestMapping(value = "/update", method = {RequestMethod.POST}) + @ApiOperation(value = "修改用户资料") // Swagger 注解:描述接口操作为“修改用户资料” + @RequestMapping(value = "/update", method = {RequestMethod.POST}) // 请求路径为 /update,方法为 POST public ApiRest update(@RequestBody SysUserDTO reqDTO) { - baseService.update(reqDTO); - return success(); + baseService.update(reqDTO); // 调用服务层的更新方法 + return success(); // 返回成功响应 } - /** * 保存或修改系统用户 - * @return + * @param reqDTO 用户保存或修改请求 DTO + * @return 返回成功响应 */ - @RequiresRoles("sa") - @ApiOperation(value = "保存或修改") - @RequestMapping(value = "/save", method = {RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "保存或修改") // Swagger 注解:描述接口操作为“保存或修改” + @RequestMapping(value = "/save", method = {RequestMethod.POST}) // 请求路径为 /save,方法为 POST public ApiRest save(@RequestBody SysUserSaveReqDTO reqDTO) { - baseService.save(reqDTO); - return success(); + baseService.save(reqDTO); // 调用服务层的保存方法 + return success(); // 返回成功响应 } - /** - * 批量删除 - * @param reqDTO - * @return + * 批量删除用户 + * @param reqDTO 批量删除请求 DTO,包含待删除用户的 ID 列表 + * @return 返回成功响应 */ - @RequiresRoles("sa") - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "批量删除") // Swagger 注解:描述接口操作为“批量删除” + @RequestMapping(value = "/delete", method = {RequestMethod.POST}) // 请求路径为 /delete,方法为 POST public ApiRest edit(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 - baseService.removeByIds(reqDTO.getIds()); - return super.success(); + baseService.removeByIds(reqDTO.getIds()); // 根据 ID 列表删除用户 + return super.success(); // 返回成功响应 } /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找用户 + * @param reqDTO 分页请求 DTO,包含分页信息和查询条件 + * @return 返回分页查询结果 */ - @RequiresRoles("sa") - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "分页查找") // Swagger 注解:描述接口操作为“分页查找” + @RequestMapping(value = "/paging", method = {RequestMethod.POST}) // 请求路径为 /paging,方法为 POST public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { - //分页查询并转换 + // 调用服务层的分页查询方法 IPage page = baseService.paging(reqDTO); - return super.success(page); + return super.success(page); // 返回成功响应,包含分页数据 } /** - * 修改状态 - * @param reqDTO - * @return + * 修改用户状态 + * @param reqDTO 状态请求 DTO,包含用户 ID 列表和状态 + * @return 返回成功响应 */ - @RequiresRoles("sa") - @ApiOperation(value = "修改状态") - @RequestMapping(value = "/state", method = { RequestMethod.POST}) + @RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色 + @ApiOperation(value = "修改状态") // Swagger 注解:描述接口操作为“修改状态” + @RequestMapping(value = "/state", method = {RequestMethod.POST}) // 请求路径为 /state,方法为 POST public ApiRest state(@RequestBody BaseStateReqDTO reqDTO) { - // 条件 + // 构建查询条件:排除 admin 用户 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .in(SysUser::getId, reqDTO.getIds()) - .ne(SysUser::getUserName, "admin"); - + .in(SysUser::getId, reqDTO.getIds()) // 根据 ID 列表查询 + .ne(SysUser::getUserName, "admin"); // 排除用户名为 admin 的用户 SysUser record = new SysUser(); - record.setState(reqDTO.getState()); - baseService.update(record, wrapper); + record.setState(reqDTO.getState()); // 设置用户状态 + baseService.update(record, wrapper); // 更新状态 - return super.success(); + return super.success(); // 返回成功响应 } - /** - * 保存或修改系统用户 - * @return + * 用户注册 + * @param reqDTO 用户注册请求 DTO,包含用户注册信息 + * @return 返回用户登录信息 */ - @ApiOperation(value = "学员注册") - @RequestMapping(value = "/reg", method = {RequestMethod.POST}) + @ApiOperation(value = "学员注册") // Swagger 注解:描述接口操作为“学员注册” + @RequestMapping(value = "/reg", method = {RequestMethod.POST}) // 请求路径为 /reg,方法为 POST public ApiRest reg(@RequestBody SysUserDTO reqDTO) { - SysUserLoginDTO respDTO = baseService.reg(reqDTO); - return success(respDTO); + SysUserLoginDTO respDTO = baseService.reg(reqDTO); // 调用服务层的注册方法 + return success(respDTO); // 返回注册后的用户登录信息 } /** - * 快速注册,如果手机号存在则登录,不存在就注册 - * @return + * 快速注册 + * @param reqDTO 用户注册请求 DTO,包含用户信息 + * @return 返回用户登录信息 */ - @ApiOperation(value = "快速注册") - @RequestMapping(value = "/quick-reg", method = {RequestMethod.POST}) + @ApiOperation(value = "快速注册") // Swagger 注解:描述接口操作为“快速注册” + @RequestMapping(value = "/quick-reg", method = {RequestMethod.POST}) // 请求路径为 /quick-reg,方法为 POST public ApiRest quick(@RequestBody SysUserDTO reqDTO) { - SysUserLoginDTO respDTO = baseService.quickReg(reqDTO); - return success(respDTO); + SysUserLoginDTO respDTO = baseService.quickReg(reqDTO); // 调用服务层的快速注册方法 + return success(respDTO); // 返回快速注册后的用户登录信息 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysRoleDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysRoleDTO.java index d138569..8532147 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysRoleDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysRoleDTO.java @@ -1,30 +1,29 @@ -package com.yf.exam.modules.sys.user.dto; +package com.yf.exam.modules.sys.user.dto; // 包名:表示该类属于 sys.user.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 /** -*

-* 角色请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="角色", description="角色") -public class SysRoleDTO implements Serializable { + *

+ * 角色请求类 + *

+ * 用于封装角色请求的数据,包括角色的ID和名称 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "角色", description = "角色") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysRoleDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "角色ID", required=true) - private String id; - - @ApiModelProperty(value = "角色名称", required=true) - private String roleName; - + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + + @ApiModelProperty(value = "角色ID", required = true) // Swagger 注解:描述该属性为“角色ID”,并标记为必填 + private String id; // 定义字段:角色的唯一标识符 + + @ApiModelProperty(value = "角色名称", required = true) // Swagger 注解:描述该属性为“角色名称”,并标记为必填 + private String roleName; // 定义字段:角色的名称 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserDTO.java index e8831b3..d74db93 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserDTO.java @@ -1,55 +1,54 @@ -package com.yf.exam.modules.sys.user.dto; +package com.yf.exam.modules.sys.user.dto; // 包名:表示该类属于 sys.user.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 +import java.util.Date; // 导入 Date 类,用于表示日期和时间 /** -*

-* 管理用户请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="管理用户", description="管理用户") -public class SysUserDTO implements Serializable { + *

+ * 管理用户请求类 + *

+ * 用于封装管理员用户的相关数据,包括用户的基本信息 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "管理用户", description = "管理用户") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:用户的唯一标识符 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "用户名", required = true) // Swagger 注解:描述该属性为“用户名”,并标记为必填 + private String userName; // 定义字段:管理员的用户名,用于登录和身份验证 - @ApiModelProperty(value = "用户名", required=true) - private String userName; + @ApiModelProperty(value = "真实姓名", required = true) // Swagger 注解:描述该属性为“真实姓名”,并标记为必填 + private String realName; // 定义字段:管理员的真实姓名 - @ApiModelProperty(value = "真实姓名", required=true) - private String realName; + @ApiModelProperty(value = "密码", required = true) // Swagger 注解:描述该属性为“密码”,并标记为必填 + private String password; // 定义字段:管理员的密码 - @ApiModelProperty(value = "密码", required=true) - private String password; + @ApiModelProperty(value = "密码盐", required = true) // Swagger 注解:描述该属性为“密码盐”,并标记为必填 + private String salt; // 定义字段:用于加密密码的盐值 - @ApiModelProperty(value = "密码盐", required=true) - private String salt; + @ApiModelProperty(value = "角色列表", required = true) // Swagger 注解:描述该属性为“角色列表”,并标记为必填 + private String roleIds; // 定义字段:用户的角色ID列表,用于权限控制 - @ApiModelProperty(value = "角色列表", required=true) - private String roleIds; + @ApiModelProperty(value = "部门ID", required = true) // Swagger 注解:描述该属性为“部门ID”,并标记为必填 + private String departId; // 定义字段:用户所属的部门ID - @ApiModelProperty(value = "部门ID", required=true) - private String departId; + @ApiModelProperty(value = "创建时间", required = true) // Swagger 注解:描述该属性为“创建时间”,并标记为必填 + private Date createTime; // 定义字段:管理员账号的创建时间 - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; + @ApiModelProperty(value = "更新时间", required = true) // Swagger 注解:描述该属性为“更新时间”,并标记为必填 + private Date updateTime; // 定义字段:管理员账号的最后更新时间 - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; - - @ApiModelProperty(value = "状态", required=true) - private Integer state; - + @ApiModelProperty(value = "状态", required = true) // Swagger 注解:描述该属性为“状态”,并标记为必填 + private Integer state; // 定义字段:管理员账号的状态,如启用或禁用 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserRoleDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserRoleDTO.java index 0973302..d18eca4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserRoleDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/SysUserRoleDTO.java @@ -1,33 +1,32 @@ -package com.yf.exam.modules.sys.user.dto; +package com.yf.exam.modules.sys.user.dto; // 包名:表示该类属于 sys.user.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 /** -*

-* 用户角色请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="用户角色", description="用户角色") -public class SysUserRoleDTO implements Serializable { + *

+ * 用户角色请求类 + *

+ * 用于封装用户角色信息的请求数据,包括用户与角色的映射关系 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "用户角色", description = "用户角色") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserRoleDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "用户ID", required=true) - private String userId; - - @ApiModelProperty(value = "角色ID", required=true) - private String roleId; - + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 + + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:用户角色关系的唯一标识符 + + @ApiModelProperty(value = "用户ID", required = true) // Swagger 注解:描述该属性为“用户ID”,并标记为必填 + private String userId; // 定义字段:用户的唯一标识符,关联到特定的用户 + + @ApiModelProperty(value = "角色ID", required = true) // Swagger 注解:描述该属性为“角色ID”,并标记为必填 + private String roleId; // 定义字段:角色的唯一标识符,关联到特定的角色 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserLoginReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserLoginReqDTO.java index 35f00a7..c7275a9 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserLoginReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserLoginReqDTO.java @@ -1,29 +1,29 @@ -package com.yf.exam.modules.sys.user.dto.request; +package com.yf.exam.modules.sys.user.dto.request; // 包名:表示该类属于 sys.user.dto.request 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 /** -*

-* 管理员登录请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="管理员登录请求类", description="管理员登录请求类") -public class SysUserLoginReqDTO implements Serializable { + *

+ * 管理员登录请求类 + *

+ * 用于封装管理员登录请求的数据,包括用户名和密码 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "管理员登录请求类", description = "管理员登录请求类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserLoginReqDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "用户名", required=true) - private String username; + @ApiModelProperty(value = "用户名", required = true) // Swagger 注解:描述该属性为“用户名”,并标记为必填 + private String username; // 定义字段:用户名,登录时使用 - @ApiModelProperty(value = "密码", required=true) - private String password; - + @ApiModelProperty(value = "密码", required = true) // Swagger 注解:描述该属性为“密码”,并标记为必填 + private String password; // 定义字段:密码,登录时使用 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserSaveReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserSaveReqDTO.java index e3fb9f4..280a545 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserSaveReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserSaveReqDTO.java @@ -1,43 +1,43 @@ -package com.yf.exam.modules.sys.user.dto.request; +package com.yf.exam.modules.sys.user.dto.request; // 包名:表示该类属于 sys.user.dto.request 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; -import java.util.List; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 +import java.util.List; // 导入 List 接口,用于存储角色列表 /** -*

-* 管理员登录请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="管理员保存请求类", description="管理员保存请求类") -public class SysUserSaveReqDTO implements Serializable { - - @ApiModelProperty(value = "ID", required=true) - private String id; - - @ApiModelProperty(value = "用户名", required=true) - private String userName; - - @ApiModelProperty(value = "头像", required=true) - private String avatar; - - @ApiModelProperty(value = "真实姓名", required=true) - private String realName; - - @ApiModelProperty(value = "密码", required=true) - private String password; - - @ApiModelProperty(value = "部门", required=true) - private String departId; - - @ApiModelProperty(value = "角色列表", required=true) - private List roles; - + *

+ * 管理员保存请求类 + *

+ * 用于封装保存管理员信息的请求数据 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "管理员保存请求类", description = "管理员保存请求类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserSaveReqDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 + + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:管理员的唯一标识符,通常用于更新操作 + + @ApiModelProperty(value = "用户名", required = true) // Swagger 注解:描述该属性为“用户名”,并标记为必填 + private String userName; // 定义字段:管理员的用户名,用于登录 + + @ApiModelProperty(value = "头像", required = true) // Swagger 注解:描述该属性为“头像”,并标记为必填 + private String avatar; // 定义字段:管理员的头像 URL + + @ApiModelProperty(value = "真实姓名", required = true) // Swagger 注解:描述该属性为“真实姓名”,并标记为必填 + private String realName; // 定义字段:管理员的真实姓名 + + @ApiModelProperty(value = "密码", required = true) // Swagger 注解:描述该属性为“密码”,并标记为必填 + private String password; // 定义字段:管理员的登录密码 + + @ApiModelProperty(value = "部门", required = true) // Swagger 注解:描述该属性为“部门”,并标记为必填 + private String departId; // 定义字段:管理员所属的部门ID + + @ApiModelProperty(value = "角色列表", required = true) // Swagger 注解:描述该属性为“角色列表”,并标记为必填 + private List roles; // 定义字段:管理员的角色列表,每个角色的 ID 组成的列表 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserTokenReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserTokenReqDTO.java index 5e830a9..c309dc1 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserTokenReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/request/SysUserTokenReqDTO.java @@ -1,26 +1,26 @@ -package com.yf.exam.modules.sys.user.dto.request; +package com.yf.exam.modules.sys.user.dto.request; // 包名:表示该类属于 sys.user.dto.request 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 /** -*

-* 会话检查请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="会话检查请求类", description="会话检查请求类") -public class SysUserTokenReqDTO implements Serializable { + *

+ * 会话检查请求类 + *

+ * 用于封装会话检查请求的数据,包含会话的 token 信息 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "会话检查请求类", description = "会话检查请求类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserTokenReqDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "用户名", required=true) - private String token; - + @ApiModelProperty(value = "用户名", required = true) // Swagger 注解:描述该属性为“用户名”,并标记为必填 + private String token; // 定义字段:会话的 token,用于标识当前会话 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/response/SysUserLoginDTO.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/response/SysUserLoginDTO.java index 17362b5..80b375f 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/response/SysUserLoginDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/dto/response/SysUserLoginDTO.java @@ -1,55 +1,55 @@ -package com.yf.exam.modules.sys.user.dto.response; +package com.yf.exam.modules.sys.user.dto.response; // 包名:表示该类属于 sys.user.dto.response 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.io.Serializable; -import java.util.Date; -import java.util.List; +import java.io.Serializable; // 导入 Serializable 接口,用于支持对象的序列化 +import java.util.Date; // 导入 Date 类,用于表示日期和时间 +import java.util.List; // 导入 List 接口,用于存储角色列表 /** -*

-* 管理用户请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@ApiModel(value="管理用户登录响应类", description="管理用户登录响应类") -public class SysUserLoginDTO implements Serializable { + *

+ * 管理用户登录响应类 + *

+ * 用于封装管理员登录后的响应数据,包括用户信息和登录令牌 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@ApiModel(value = "管理用户登录响应类", description = "管理用户登录响应类") // Swagger 注解:定义该类的 API 模型名称和描述 +public class SysUserLoginDTO implements Serializable { // 实现 Serializable 接口,以支持序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "ID", required = true) // Swagger 注解:描述该属性为“ID”,并标记为必填 + private String id; // 定义字段:管理员的唯一标识符 - @ApiModelProperty(value = "用户名", required=true) - private String userName; + @ApiModelProperty(value = "用户名", required = true) // Swagger 注解:描述该属性为“用户名”,并标记为必填 + private String userName; // 定义字段:管理员的用户名 - @ApiModelProperty(value = "真实姓名", required=true) - private String realName; + @ApiModelProperty(value = "真实姓名", required = true) // Swagger 注解:描述该属性为“真实姓名”,并标记为必填 + private String realName; // 定义字段:管理员的真实姓名 - @ApiModelProperty(value = "角色列表", required=true) - private String roleIds; + @ApiModelProperty(value = "角色列表", required = true) // Swagger 注解:描述该属性为“角色列表”,并标记为必填 + private String roleIds; // 定义字段:管理员的角色ID列表,用于权限控制 - @ApiModelProperty(value = "部门ID", required=true) - private String departId; + @ApiModelProperty(value = "部门ID", required = true) // Swagger 注解:描述该属性为“部门ID”,并标记为必填 + private String departId; // 定义字段:管理员所属部门的ID - @ApiModelProperty(value = "创建时间", required=true) - private Date createTime; + @ApiModelProperty(value = "创建时间", required = true) // Swagger 注解:描述该属性为“创建时间”,并标记为必填 + private Date createTime; // 定义字段:管理员账号的创建时间 - @ApiModelProperty(value = "更新时间", required=true) - private Date updateTime; + @ApiModelProperty(value = "更新时间", required = true) // Swagger 注解:描述该属性为“更新时间”,并标记为必填 + private Date updateTime; // 定义字段:管理员账号的最后更新时间 - @ApiModelProperty(value = "状态", required=true) - private Integer state; + @ApiModelProperty(value = "状态", required = true) // Swagger 注解:描述该属性为“状态”,并标记为必填 + private Integer state; // 定义字段:管理员账号的状态,如启用或禁用 - @ApiModelProperty(value = "角色列表", required=true) - private List roles; + @ApiModelProperty(value = "角色列表", required = true) // Swagger 注解:描述该属性为“角色列表”,并标记为必填 + private List roles; // 定义字段:管理员角色的列表,每个角色的名称或ID - @ApiModelProperty(value = "登录令牌", required=true) - private String token; - + @ApiModelProperty(value = "登录令牌", required = true) // Swagger 注解:描述该属性为“登录令牌”,并标记为必填 + private String token; // 定义字段:管理员登录后的令牌,用于身份验证 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysRole.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysRole.java index b5d328f..ff90c1f 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysRole.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysRole.java @@ -1,36 +1,38 @@ -package com.yf.exam.modules.sys.user.entity; +package com.yf.exam.modules.sys.user.entity; // 包名:表示该类属于 sys.user.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于指定主键生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于指定表字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于指定表主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus 扩展的 Model 类,支持 ActiveRecord 模式 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 /** -*

-* 角色实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@TableName("sys_role") -public class SysRole extends Model { + *

+ * 角色实体类 + *

+ * 该类用于封装角色实体的数据,与数据库中的 `sys_role` 表对应 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("sys_role") // MyBatis-Plus 注解,指定该实体类对应数据库表名为 "sys_role" +public class SysRole extends Model { // SysRole 类继承自 Model 类,支持 ActiveRecord 模式 + + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - private static final long serialVersionUID = 1L; - /** - * 角色ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; - + * 角色ID + * 主键,使用 MyBatis-Plus 的自增策略 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,指定主键字段及生成策略 + private String id; // 定义字段:角色的唯一标识符 + /** - * 角色名称 - */ - @TableField("role_name") - private String roleName; - + * 角色名称 + * 对应数据库中的 "role_name" 字段 + */ + @TableField("role_name") // MyBatis-Plus 注解,指定该字段对应数据库中的 "role_name" 字段 + private String roleName; // 定义字段:角色的名称 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUser.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUser.java index 7651f68..ec5f429 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUser.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUser.java @@ -1,83 +1,93 @@ -package com.yf.exam.modules.sys.user.entity; +package com.yf.exam.modules.sys.user.entity; // 包名:表示该类属于 sys.user.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于指定主键生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于指定表字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于指定表主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus 扩展的 Model 类,支持 ActiveRecord 模式 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 -import java.util.Date; +import java.util.Date; // 导入 Date 类,用于表示日期和时间 /** -*

-* 管理用户实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@TableName("sys_user") -public class SysUser extends Model { + *

+ * 管理用户实体类 + *

+ * 该类用于封装管理员用户的数据,与数据库中的 `sys_user` 表对应 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("sys_user") // MyBatis-Plus 注解,指定该实体类对应数据库表名为 "sys_user" +public class SysUser extends Model { // SysUser 类继承自 Model 类,支持 ActiveRecord 模式 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 /** * ID + * 主键,使用 MyBatis-Plus 的自增策略 */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,指定主键字段及生成策略 + private String id; // 定义字段:用户的唯一标识符 /** * 用户名 + * 对应数据库中的 "user_name" 字段 */ - @TableField("user_name") - private String userName; + @TableField("user_name") // MyBatis-Plus 注解,指定该字段对应数据库中的 "user_name" 字段 + private String userName; // 定义字段:管理员的用户名,用于登录和身份验证 /** * 真实姓名 + * 对应数据库中的 "real_name" 字段 */ - @TableField("real_name") - private String realName; + @TableField("real_name") // MyBatis-Plus 注解,指定该字段对应数据库中的 "real_name" 字段 + private String realName; // 定义字段:管理员的真实姓名 /** * 密码 + * 存储管理员的密码 */ - private String password; + private String password; // 定义字段:管理员的登录密码 /** * 密码盐 + * 用于加密密码的盐值 */ - private String salt; + private String salt; // 定义字段:用于加密密码的盐值 /** * 角色列表 + * 对应数据库中的 "role_ids" 字段,存储角色的ID列表 */ - @TableField("role_ids") - private String roleIds; + @TableField("role_ids") // MyBatis-Plus 注解,指定该字段对应数据库中的 "role_ids" 字段 + private String roleIds; // 定义字段:用户的角色ID列表,用于权限控制 /** * 部门ID + * 对应数据库中的 "depart_id" 字段 */ - @TableField("depart_id") - private String departId; + @TableField("depart_id") // MyBatis-Plus 注解,指定该字段对应数据库中的 "depart_id" 字段 + private String departId; // 定义字段:管理员所属的部门ID /** * 创建时间 + * 对应数据库中的 "create_time" 字段 */ - @TableField("create_time") - private Date createTime; + @TableField("create_time") // MyBatis-Plus 注解,指定该字段对应数据库中的 "create_time" 字段 + private Date createTime; // 定义字段:管理员账号的创建时间 /** * 更新时间 + * 对应数据库中的 "update_time" 字段 */ - @TableField("update_time") - private Date updateTime; + @TableField("update_time") // MyBatis-Plus 注解,指定该字段对应数据库中的 "update_time" 字段 + private Date updateTime; // 定义字段:管理员账号的最后更新时间 /** * 状态 + * 表示管理员账号的状态,如启用或禁用 */ - private Integer state; - + private Integer state; // 定义字段:管理员账号的状态(如启用或禁用) } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUserRole.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUserRole.java index 1006e0f..ecea83c 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUserRole.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/entity/SysUserRole.java @@ -1,42 +1,45 @@ -package com.yf.exam.modules.sys.user.entity; +package com.yf.exam.modules.sys.user.entity; // 包名:表示该类属于 sys.user.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于指定主键生成策略 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于指定表字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于指定表主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于指定表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus 扩展的 Model 类,支持 ActiveRecord 模式 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法 /** -*

-* 用户角色实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Data -@TableName("sys_user_role") -public class SysUserRole extends Model { + *

+ * 用户角色实体类 + *

+ * 该类用于封装用户角色的关系数据,与数据库中的 `sys_user_role` 表对应 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法 +@TableName("sys_user_role") // MyBatis-Plus 注解,指定该实体类对应数据库表名为 "sys_user_role" +public class SysUserRole extends Model { // SysUserRole 类继承自 Model 类,支持 ActiveRecord 模式 + + private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查 - private static final long serialVersionUID = 1L; - /** - * ID - */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; - + * ID + * 主键,使用 MyBatis-Plus 的自增策略 + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,指定主键字段及生成策略 + private String id; // 定义字段:用户角色关系的唯一标识符 + /** - * 用户ID - */ - @TableField("user_id") - private String userId; - + * 用户ID + * 对应数据库中的 "user_id" 字段 + */ + @TableField("user_id") // MyBatis-Plus 注解,指定该字段对应数据库中的 "user_id" 字段 + private String userId; // 定义字段:用户的唯一标识符,关联到特定的用户 + /** - * 角色ID - */ - @TableField("role_id") - private String roleId; - + * 角色ID + * 对应数据库中的 "role_id" 字段 + */ + @TableField("role_id") // MyBatis-Plus 注解,指定该字段对应数据库中的 "role_id" 字段 + private String roleId; // 定义字段:角色的唯一标识符,关联到特定的角色 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysRoleMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysRoleMapper.java index 05763a3..71dad7e 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysRoleMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysRoleMapper.java @@ -1,15 +1,17 @@ -package com.yf.exam.modules.sys.user.mapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.sys.user.entity.SysRole; +package com.yf.exam.modules.sys.user.mapper; // 包名:表示该类属于 sys.user.mapper 包 + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,提供基本的数据库操作方法 +import com.yf.exam.modules.sys.user.entity.SysRole; // 导入 SysRole 实体类,表示角色实体 /** -*

-* 角色Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysRoleMapper extends BaseMapper { + *

+ * 角色Mapper + *

+ * 该接口继承自 MyBatis-Plus 的 BaseMapper,用于提供对 `SysRole` 实体的数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysRoleMapper extends BaseMapper { // 继承 MyBatis-Plus 的 BaseMapper,自动提供对 SysRole 实体的 CRUD 操作 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserMapper.java index de7ae4f..4200719 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserMapper.java @@ -1,16 +1,17 @@ -package com.yf.exam.modules.sys.user.mapper; +package com.yf.exam.modules.sys.user.mapper; // 包名:表示该类属于 sys.user.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.sys.user.entity.SysUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,提供基本的数据库操作方法 +import com.yf.exam.modules.sys.user.entity.SysUser; // 导入 SysUser 实体类,表示管理员用户实体 /** -*

-* 管理用户Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysUserMapper extends BaseMapper { + *

+ * 管理用户Mapper + *

+ * 该接口继承自 MyBatis-Plus 的 BaseMapper,用于提供对 `SysUser` 实体的数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysUserMapper extends BaseMapper { // 继承 MyBatis-Plus 的 BaseMapper,自动提供对 SysUser 实体的 CRUD 操作 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserRoleMapper.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserRoleMapper.java index 3055949..e8ec341 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserRoleMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/mapper/SysUserRoleMapper.java @@ -1,16 +1,17 @@ -package com.yf.exam.modules.sys.user.mapper; +package com.yf.exam.modules.sys.user.mapper; // 包名:表示该类属于 sys.user.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.sys.user.entity.SysUserRole; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,提供基本的数据库操作方法 +import com.yf.exam.modules.sys.user.entity.SysUserRole; // 导入 SysUserRole 实体类,表示用户角色实体 /** -*

-* 用户角色Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysUserRoleMapper extends BaseMapper { + *

+ * 用户角色Mapper + *

+ * 该接口继承自 MyBatis-Plus 的 BaseMapper,用于提供对 `SysUserRole` 实体的数据库操作 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysUserRoleMapper extends BaseMapper { // 继承 MyBatis-Plus 的 BaseMapper,自动提供对 SysUserRole 实体的 CRUD 操作 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysRoleService.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysRoleService.java index b0a87f9..f6b50d2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysRoleService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysRoleService.java @@ -1,25 +1,26 @@ -package com.yf.exam.modules.sys.user.service; +package com.yf.exam.modules.sys.user.service; // 包名:表示该类属于 sys.user.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.sys.user.dto.SysRoleDTO; -import com.yf.exam.modules.sys.user.entity.SysRole; -import com.yf.exam.core.api.dto.PagingReqDTO; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,提供基本的服务方法 +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; // 导入 SysRoleDTO 数据传输对象,用于封装角色数据 +import com.yf.exam.modules.sys.user.entity.SysRole; // 导入 SysRole 实体类,表示角色 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO,用于封装分页请求参数 /** -*

-* 角色业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysRoleService extends IService { + *

+ * 角色业务类 + *

+ * 该接口定义了与角色相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysRoleService extends IService { // 继承 MyBatis-Plus 的 IService 接口,提供基本的 CRUD 操作 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + * 分页查询数据 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询的结果 + */ + IPage paging(PagingReqDTO reqDTO); // 定义分页查询方法,返回角色的分页数据 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserRoleService.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserRoleService.java index 76fb6f2..2f637f7 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserRoleService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserRoleService.java @@ -1,61 +1,64 @@ -package com.yf.exam.modules.sys.user.service; +package com.yf.exam.modules.sys.user.service; // 包名:表示该类属于 sys.user.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; -import com.yf.exam.modules.sys.user.entity.SysUserRole; -import com.yf.exam.core.api.dto.PagingReqDTO; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,提供基本的服务方法 +import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; // 导入 SysUserRoleDTO 数据传输对象,用于封装用户角色数据 +import com.yf.exam.modules.sys.user.entity.SysUserRole; // 导入 SysUserRole 实体类,表示用户角色 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO,用于封装分页请求参数 -import java.util.List; +import java.util.List; // 导入 List 接口,用于存储多个角色ID /** -*

-* 用户角色业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysUserRoleService extends IService { + *

+ * 用户角色业务类 + *

+ * 该接口定义了与用户角色相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysUserRoleService extends IService { // 继承 MyBatis-Plus 的 IService 接口,提供基本的 CRUD 操作 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + * 分页查询数据 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询的结果 + */ + IPage paging(PagingReqDTO reqDTO); // 定义分页查询用户角色数据的方法,返回角色的分页数据 /** * 查找用户角色列表 - * @param userId - * @return + * @param userId 用户ID + * @return 返回该用户的角色ID列表 */ - List listRoles(String userId); + List listRoles(String userId); // 根据用户ID查找该用户的角色ID列表 /** * 保存全部角色 - * @param userId - * @param ids - * @return + * @param userId 用户ID + * @param ids 角色ID列表 + * @return 返回角色ID的拼接字符串 */ - String saveRoles(String userId, List ids); + String saveRoles(String userId, List ids); // 保存指定用户的角色 /** * 是否学生 - * @param userId - * @return + * @param userId 用户ID + * @return 返回用户是否为学生,true表示是学生,false表示不是学生 */ - boolean isStudent(String userId); + boolean isStudent(String userId); // 判断指定用户是否为学生 /** * 是否老师 + * @param userId 用户ID + * @return 返回用户是否为老师,true表示是老师,false表示不是老师 */ - boolean isTeacher(String userId); + boolean isTeacher(String userId); // 判断指定用户是否为老师 /** - * 是否管理 - * @param userId - * @return + * 是否管理员 + * @param userId 用户ID + * @return 返回用户是否为管理员,true表示是管理员,false表示不是管理员 */ - boolean isAdmin(String userId); + boolean isAdmin(String userId); // 判断指定用户是否为管理员 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserService.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserService.java index 52a1818..f562771 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserService.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/SysUserService.java @@ -1,72 +1,75 @@ -package com.yf.exam.modules.sys.user.service; +package com.yf.exam.modules.sys.user.service; // 包名:表示该类属于 sys.user.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.modules.sys.user.dto.SysUserDTO; -import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import com.yf.exam.modules.sys.user.entity.SysUser; -import com.yf.exam.core.api.dto.PagingReqDTO; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,提供基本的服务方法 +import com.yf.exam.modules.sys.user.dto.SysUserDTO; // 导入 SysUserDTO 数据传输对象,用于封装用户数据 +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; // 导入 SysUserSaveReqDTO 请求 DTO,用于保存用户信息 +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 导入 SysUserLoginDTO 响应 DTO,用于返回登录信息 +import com.yf.exam.modules.sys.user.entity.SysUser; // 导入 SysUser 实体类,表示管理员用户 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO,用于封装分页请求参数 /** -*

-* 管理用户业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -public interface SysUserService extends IService { + *

+ * 管理用户业务类 + *

+ * 该接口定义了与管理用户相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +public interface SysUserService extends IService { // 继承 MyBatis-Plus 的 IService 接口,提供基本的 CRUD 操作 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + * 分页查询数据 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询的结果 + */ + IPage paging(PagingReqDTO reqDTO); // 定义分页查询用户数据的方法,返回用户的分页数据 /** * 登录 - * @param userName - * @param password - * @return + * @param userName 用户名 + * @param password 密码 + * @return 返回登录信息,包括 token 等数据 */ - SysUserLoginDTO login(String userName, String password); + SysUserLoginDTO login(String userName, String password); // 实现用户登录,验证用户名和密码 /** * 获取管理会话 - * @param token - * @return + * @param token 用户的 JWT token + * @return 返回用户的登录信息和角色信息 */ - SysUserLoginDTO token(String token); + SysUserLoginDTO token(String token); // 根据 token 获取用户的会话信息并验证 /** * 退出登录 - * @param token + * @param token 用户的 JWT token */ - void logout(String token); + void logout(String token); // 退出登录,销毁当前会话 /** * 修改用户资料 - * @param reqDTO + * @param reqDTO 用户资料数据传输对象 */ - void update(SysUserDTO reqDTO); + void update(SysUserDTO reqDTO); // 修改用户资料,包括密码等信息 /** * 保存添加系统用户 - * @param reqDTO + * @param reqDTO 保存用户信息的请求数据传输对象 */ - void save(SysUserSaveReqDTO reqDTO); + void save(SysUserSaveReqDTO reqDTO); // 保存或更新系统用户 /** * 用户注册 - * @param reqDTO + * @param reqDTO 注册用户的数据传输对象 + * @return 返回用户登录信息和 token */ - SysUserLoginDTO reg(SysUserDTO reqDTO); + SysUserLoginDTO reg(SysUserDTO reqDTO); // 用户注册,保存用户信息并返回登录数据 /** * 快速注册 - * @param reqDTO + * @param reqDTO 快速注册用户的数据传输对象 + * @return 返回用户登录信息和 token */ - SysUserLoginDTO quickReg(SysUserDTO reqDTO); + SysUserLoginDTO quickReg(SysUserDTO reqDTO); // 快速注册,如果用户已存在则直接登录,否则进行注册 } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysRoleServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysRoleServiceImpl.java index 8593f55..f2cd262 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysRoleServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysRoleServiceImpl.java @@ -1,42 +1,46 @@ -package com.yf.exam.modules.sys.user.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.modules.sys.user.dto.SysRoleDTO; -import com.yf.exam.modules.sys.user.entity.SysRole; -import com.yf.exam.modules.sys.user.mapper.SysRoleMapper; -import com.yf.exam.modules.sys.user.service.SysRoleService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import org.springframework.stereotype.Service; +package com.yf.exam.modules.sys.user.service.impl; // 包名:表示该类属于 sys.user.service.impl 包 + +import com.alibaba.fastjson.JSON; // 导入 Fastjson 库,用于 JSON 处理 +import com.alibaba.fastjson.TypeReference; // 导入 Fastjson 的 TypeReference,用于泛型类型的转换 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 分页类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl,实现基本的服务层操作 +import com.yf.exam.modules.sys.user.dto.SysRoleDTO; // 导入 SysRoleDTO 数据传输对象,用于封装角色数据 +import com.yf.exam.modules.sys.user.entity.SysRole; // 导入 SysRole 实体类,表示角色 +import com.yf.exam.modules.sys.user.mapper.SysRoleMapper; // 导入 SysRoleMapper,用于数据库操作 +import com.yf.exam.modules.sys.user.service.SysRoleService; // 导入 SysRoleService 服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO +import org.springframework.stereotype.Service; // 导入 Spring 的 Service 注解,标识该类为服务层组件 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Service -public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { + *

+ * 语言设置 服务实现类 + *

+ * 该类实现了 SysRoleService 接口,提供了角色相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Service // 标识该类为服务层组件 +public class SysRoleServiceImpl extends ServiceImpl implements SysRoleService { // 继承 MyBatis-Plus 的 ServiceImpl,自动提供基础的 CRUD 操作 @Override - public IPage paging(PagingReqDTO reqDTO) { + public IPage paging(PagingReqDTO reqDTO) { // 重写分页查询方法 - //创建分页对象 + // 创建分页对象,设置当前页和每页显示的条数 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 创建查询条件对象(此处没有具体条件,查询所有数据) QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 查询数据,获取分页结果 IPage page = this.page(query, wrapper); - //转换结果 - IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + + // 将查询结果转换为 SysRoleDTO 类型的分页结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>() {}); + + // 返回分页数据 return pageData; - } + } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserRoleServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserRoleServiceImpl.java index 794457b..6d3d34a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserRoleServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserRoleServiceImpl.java @@ -1,128 +1,144 @@ -package com.yf.exam.modules.sys.user.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; -import com.yf.exam.modules.sys.user.entity.SysUserRole; -import com.yf.exam.modules.sys.user.mapper.SysUserRoleMapper; -import com.yf.exam.modules.sys.user.service.SysUserRoleService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; -import org.springframework.util.StringUtils; - -import java.util.ArrayList; -import java.util.List; +package com.yf.exam.modules.sys.user.service.impl; // 包名:表示该类属于 sys.user.service.impl 包 + +import com.alibaba.fastjson.JSON; // 导入 Fastjson 库,用于 JSON 处理 +import com.alibaba.fastjson.TypeReference; // 导入 Fastjson 的 TypeReference,用于泛型类型的转换 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 分页类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 类,提供基础的数据库操作 +import com.yf.exam.modules.sys.user.dto.SysUserRoleDTO; // 导入 SysUserRoleDTO 数据传输对象,用于封装用户角色数据 +import com.yf.exam.modules.sys.user.entity.SysUserRole; // 导入 SysUserRole 实体类,表示用户角色 +import com.yf.exam.modules.sys.user.mapper.SysUserRoleMapper; // 导入 SysUserRoleMapper,用于数据库操作 +import com.yf.exam.modules.sys.user.service.SysUserRoleService; // 导入 SysUserRoleService 服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO +import org.springframework.stereotype.Service; // 导入 Spring 的 Service 注解,标识该类为服务层组件 +import org.springframework.util.CollectionUtils; // 导入 Spring 的 CollectionUtils 工具类,用于判断集合是否为空 +import org.springframework.util.StringUtils; // 导入 Spring 的 StringUtils 工具类,用于判断字符串是否为空 + +import java.util.ArrayList; // 导入 ArrayList 类,用于创建列表 +import java.util.List; // 导入 List 接口,用于存储角色列表 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Service -public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { + *

+ * 用户角色服务实现类 + *

+ * 该类实现了 SysUserRoleService 接口,提供了用户角色相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Service // 标识该类为服务层组件 +public class SysUserRoleServiceImpl extends ServiceImpl implements SysUserRoleService { // 继承 MyBatis-Plus 的 ServiceImpl,自动提供基础的 CRUD 操作 @Override - public IPage paging(PagingReqDTO reqDTO) { + public IPage paging(PagingReqDTO reqDTO) { // 实现分页查询方法 - //创建分页对象 + // 创建分页对象,设置当前页和每页显示的条数 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 创建查询条件对象 QueryWrapper wrapper = new QueryWrapper<>(); - //获得数据 + // 查询数据,获取分页结果 IPage page = this.page(query, wrapper); - //转换结果 - IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + + // 将查询结果转换为 SysUserRoleDTO 类型的分页结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>() {}); + + // 返回分页数据 return pageData; - } + } @Override - public List listRoles(String userId) { + public List listRoles(String userId) { // 根据用户ID获取该用户的角色列表 + // 创建查询条件对象,筛选出指定用户的角色 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUserRole::getUserId, userId); + // 查询角色列表 List list = this.list(wrapper); List roles = new ArrayList<>(); - if(!CollectionUtils.isEmpty(list)){ - for(SysUserRole item: list){ + + // 如果查询结果不为空,将角色ID添加到列表中 + if (!CollectionUtils.isEmpty(list)) { + for (SysUserRole item : list) { roles.add(item.getRoleId()); } } + // 返回角色ID列表 return roles; } @Override - public String saveRoles(String userId, List ids) { + public String saveRoles(String userId, List ids) { // 保存用户角色方法 - // 删除全部角色 + // 删除该用户所有角色 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUserRole::getUserId, userId); this.remove(wrapper); - - if(!CollectionUtils.isEmpty(ids)){ + // 如果角色列表不为空,保存新的角色 + if (!CollectionUtils.isEmpty(ids)) { List list = new ArrayList<>(); String roleIds = null; - for(String item: ids){ + // 将角色ID列表转为 SysUserRole 实体对象列表 + for (String item : ids) { SysUserRole role = new SysUserRole(); role.setRoleId(item); role.setUserId(userId); list.add(role); - if(StringUtils.isEmpty(roleIds)){ + if (StringUtils.isEmpty(roleIds)) { roleIds = item; - }else{ - roleIds+=","+item; + } else { + roleIds += "," + item; // 将角色ID拼接成字符串 } } + // 批量保存角色数据 this.saveBatch(list); - return roleIds; + return roleIds; // 返回拼接后的角色ID字符串 } - return ""; + return ""; // 如果角色列表为空,返回空字符串 } @Override - public boolean isStudent(String userId) { + public boolean isStudent(String userId) { // 检查用户是否为学生 - // 学生角色 + // 查询用户是否拥有学生角色 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUserRole::getUserId, userId) .eq(SysUserRole::getRoleId, "student"); + // 如果查询结果数量大于0,则表示该用户是学生 return this.count(wrapper) > 0; } @Override - public boolean isTeacher(String userId) { - // 学生角色 + public boolean isTeacher(String userId) { // 检查用户是否为教师 + + // 查询用户是否拥有教师角色 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUserRole::getUserId, userId) .eq(SysUserRole::getRoleId, "teacher"); + // 如果查询结果数量大于0,则表示该用户是教师 return this.count(wrapper) > 0; } @Override - public boolean isAdmin(String userId) { - // 学生角色 + public boolean isAdmin(String userId) { // 检查用户是否为管理员 + + // 查询用户是否拥有管理员角色(角色ID为 "sa") QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUserRole::getUserId, userId) .eq(SysUserRole::getRoleId, "sa"); + // 如果查询结果数量大于0,则表示该用户是管理员 return this.count(wrapper) > 0; } } diff --git a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserServiceImpl.java index 4370e56..0fdba23 100644 --- a/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/sys/user/service/impl/SysUserServiceImpl.java @@ -1,176 +1,185 @@ -package com.yf.exam.modules.sys.user.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.core.toolkit.IdWorker; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.ApiError; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.core.enums.CommonState; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.core.utils.BeanMapper; -import com.yf.exam.core.utils.passwd.PassHandler; -import com.yf.exam.core.utils.passwd.PassInfo; -import com.yf.exam.ability.shiro.jwt.JwtUtils; -import com.yf.exam.modules.sys.user.dto.SysUserDTO; -import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import com.yf.exam.modules.sys.user.entity.SysUser; -import com.yf.exam.modules.sys.user.mapper.SysUserMapper; -import com.yf.exam.modules.sys.user.service.SysUserRoleService; -import com.yf.exam.modules.sys.user.service.SysUserService; -import com.yf.exam.modules.user.UserUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.shiro.SecurityUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; - -import java.util.ArrayList; -import java.util.List; +package com.yf.exam.modules.sys.user.service.impl; // 包名:表示该类属于 sys.user.service.impl 包 + +import com.alibaba.fastjson.JSON; // 导入 Fastjson 库,用于 JSON 处理 +import com.alibaba.fastjson.TypeReference; // 导入 Fastjson 的 TypeReference,用于泛型类型的转换 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.baomidou.mybatisplus.core.toolkit.IdWorker; // 导入 MyBatis-Plus 的 IdWorker,用于生成唯一ID +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 分页类 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 类,提供基础的数据库操作 +import com.yf.exam.core.api.ApiError; // 导入 ApiError 用于错误码定义 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO +import com.yf.exam.core.enums.CommonState; // 导入公共状态枚举,定义正常与异常状态 +import com.yf.exam.core.exception.ServiceException; // 导入 ServiceException,用于抛出自定义异常 +import com.yf.exam.core.utils.BeanMapper; // 导入 BeanMapper 工具类,用于对象之间的属性拷贝 +import com.yf.exam.core.utils.passwd.PassHandler; // 导入 PassHandler 用于密码处理 +import com.yf.exam.core.utils.passwd.PassInfo; // 导入 PassInfo 用于存储密码和盐 +import com.yf.exam.ability.shiro.jwt.JwtUtils; // 导入 JwtUtils 用于生成和验证 JWT +import com.yf.exam.modules.sys.user.dto.SysUserDTO; // 导入 SysUserDTO 数据传输对象,用于封装用户数据 +import com.yf.exam.modules.sys.user.dto.request.SysUserSaveReqDTO; // 导入 SysUserSaveReqDTO 请求 DTO,用于保存用户信息 +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 导入 SysUserLoginDTO 响应 DTO,用于返回登录信息 +import com.yf.exam.modules.sys.user.entity.SysUser; // 导入 SysUser 实体类,表示管理员用户 +import com.yf.exam.modules.sys.user.mapper.SysUserMapper; // 导入 SysUserMapper,用于数据库操作 +import com.yf.exam.modules.sys.user.service.SysUserRoleService; // 导入 SysUserRoleService 服务接口,用于角色操作 +import com.yf.exam.modules.sys.user.service.SysUserService; // 导入 SysUserService 服务接口,用于用户操作 +import com.yf.exam.modules.user.UserUtils; // 导入 UserUtils 工具类,用于获取当前用户信息 +import org.apache.commons.lang3.StringUtils; // 导入 StringUtils 工具类,用于判断字符串是否为空 +import org.apache.shiro.SecurityUtils; // 导入 Shiro 的 SecurityUtils,用于获取和处理用户会话 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 注解,用于自动注入依赖 +import org.springframework.stereotype.Service; // 导入 Spring 的 Service 注解,标识该类为服务层组件 +import org.springframework.transaction.annotation.Transactional; // 导入 Spring 的事务注解,支持事务管理 +import org.springframework.util.CollectionUtils; // 导入 Spring 的 CollectionUtils 工具类,用于判断集合是否为空 + +import java.util.ArrayList; // 导入 ArrayList 类,用于创建列表 +import java.util.List; // 导入 List 接口,用于存储角色列表 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-04-13 16:57 -*/ -@Service -public class SysUserServiceImpl extends ServiceImpl implements SysUserService { + *

+ * 用户服务实现类 + *

+ * 该类实现了 SysUserService 接口,提供了与用户相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-04-13 16:57 + */ +@Service // 标识该类为服务层组件 +public class SysUserServiceImpl extends ServiceImpl implements SysUserService { // 继承 MyBatis-Plus 的 ServiceImpl,自动提供基础的 CRUD 操作 @Autowired - private SysUserRoleService sysUserRoleService; - + private SysUserRoleService sysUserRoleService; // 注入 SysUserRoleService,用于用户角色管理 @Override - public IPage paging(PagingReqDTO reqDTO) { + public IPage paging(PagingReqDTO reqDTO) { // 实现分页查询方法 - //创建分页对象 + // 创建分页对象,设置当前页和每页显示的条数 IPage query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 创建查询条件对象 QueryWrapper wrapper = new QueryWrapper<>(); SysUserDTO params = reqDTO.getParams(); - if(params!=null){ - if(!StringUtils.isBlank(params.getUserName())){ + // 根据传入的参数设置查询条件 + if (params != null) { + if (!StringUtils.isBlank(params.getUserName())) { wrapper.lambda().like(SysUser::getUserName, params.getUserName()); } - if(!StringUtils.isBlank(params.getRealName())){ + if (!StringUtils.isBlank(params.getRealName())) { wrapper.lambda().like(SysUser::getRealName, params.getRealName()); } } - //获得数据 + // 查询数据,获取分页结果 IPage page = this.page(query, wrapper); - //转换结果 - IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + + // 将查询结果转换为 SysUserDTO 类型的分页结果 + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>() {}); + + // 返回分页数据 return pageData; - } + } @Override - public SysUserLoginDTO login(String userName, String password) { + public SysUserLoginDTO login(String userName, String password) { // 用户登录方法 + // 查询用户是否存在 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUser::getUserName, userName); SysUser user = this.getOne(wrapper, false); - if(user == null){ - throw new ServiceException(ApiError.ERROR_90010002); + if (user == null) { + throw new ServiceException(ApiError.ERROR_90010002); // 用户不存在,抛出异常 } - // 被禁用 - if(user.getState().equals(CommonState.ABNORMAL)){ - throw new ServiceException(ApiError.ERROR_90010005); + // 检查用户是否被禁用 + if (user.getState().equals(CommonState.ABNORMAL)) { + throw new ServiceException(ApiError.ERROR_90010005); // 用户被禁用,抛出异常 } - boolean check = PassHandler.checkPass(password,user.getSalt(), user.getPassword()); - if(!check){ - throw new ServiceException(ApiError.ERROR_90010002); + // 校验密码 + boolean check = PassHandler.checkPass(password, user.getSalt(), user.getPassword()); + if (!check) { + throw new ServiceException(ApiError.ERROR_90010002); // 密码不正确,抛出异常 } + // 设置 JWT token 并返回登录信息 return this.setToken(user); } @Override - public SysUserLoginDTO token(String token) { + public SysUserLoginDTO token(String token) { // 根据 token 获取用户会话信息 - // 获得会话 + // 获取 token 中的用户名 String username = JwtUtils.getUsername(token); - // 校验结果 + // 校验 token 是否有效 boolean check = JwtUtils.verify(token, username); - if(!check){ - throw new ServiceException(ApiError.ERROR_90010002); + if (!check) { + throw new ServiceException(ApiError.ERROR_90010002); // token 无效,抛出异常 } + // 查询用户信息 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUser::getUserName, username); SysUser user = this.getOne(wrapper, false); - if(user == null){ - throw new ServiceException(ApiError.ERROR_10010002); + if (user == null) { + throw new ServiceException(ApiError.ERROR_10010002); // 用户不存在,抛出异常 } - // 被禁用 - if(user.getState().equals(CommonState.ABNORMAL)){ - throw new ServiceException(ApiError.ERROR_90010005); + // 检查用户是否被禁用 + if (user.getState().equals(CommonState.ABNORMAL)) { + throw new ServiceException(ApiError.ERROR_90010005); // 用户被禁用,抛出异常 } + // 设置 JWT token 并返回登录信息 return this.setToken(user); } @Override - public void logout(String token) { + public void logout(String token) { // 用户登出方法 - // 仅退出当前会话 + // 退出当前会话 SecurityUtils.getSubject().logout(); } @Override - public void update(SysUserDTO reqDTO) { - - - String pass = reqDTO.getPassword(); - if(!StringUtils.isBlank(pass)){ - PassInfo passInfo = PassHandler.buildPassword(pass); - SysUser user = this.getById(UserUtils.getUserId()); - user.setPassword(passInfo.getPassword()); - user.setSalt(passInfo.getSalt()); - this.updateById(user); - } + public void update(SysUserDTO reqDTO) { // 更新用户信息 + + String pass = reqDTO.getPassword(); + if (!StringUtils.isBlank(pass)) { + // 如果提供了新密码,则更新密码 + PassInfo passInfo = PassHandler.buildPassword(pass); + SysUser user = this.getById(UserUtils.getUserId()); + user.setPassword(passInfo.getPassword()); + user.setSalt(passInfo.getSalt()); + this.updateById(user); // 更新用户数据 + } } - @Transactional(rollbackFor = Exception.class) + @Transactional(rollbackFor = Exception.class) // 启用事务管理,保证数据一致性 @Override - public void save(SysUserSaveReqDTO reqDTO) { + public void save(SysUserSaveReqDTO reqDTO) { // 保存或修改用户信息 List roles = reqDTO.getRoles(); - if(CollectionUtils.isEmpty(roles)){ - throw new ServiceException(ApiError.ERROR_90010003); + if (CollectionUtils.isEmpty(roles)) { + throw new ServiceException(ApiError.ERROR_90010003); // 角色列表不能为空,抛出异常 } // 保存基本信息 SysUser user = new SysUser(); BeanMapper.copy(reqDTO, user); - // 添加模式 - if(StringUtils.isBlank(user.getId())){ + // 添加模式,生成新的 ID + if (StringUtils.isBlank(user.getId())) { user.setId(IdWorker.getIdStr()); } - // 修改密码 - if(!StringUtils.isBlank(reqDTO.getPassword())){ + // 如果提供了密码,则加密并保存 + if (!StringUtils.isBlank(reqDTO.getPassword())) { PassInfo pass = PassHandler.buildPassword(reqDTO.getPassword()); user.setPassword(pass.getPassword()); user.setSalt(pass.getSalt()); @@ -179,23 +188,23 @@ public class SysUserServiceImpl extends ServiceImpl impl // 保存角色信息 String roleIds = sysUserRoleService.saveRoles(user.getId(), roles); user.setRoleIds(roleIds); - this.saveOrUpdate(user); + + this.saveOrUpdate(user); // 保存或更新用户信息 } - @Transactional(rollbackFor = Exception.class) + @Transactional(rollbackFor = Exception.class) // 启用事务管理 @Override - public SysUserLoginDTO reg(SysUserDTO reqDTO) { + public SysUserLoginDTO reg(SysUserDTO reqDTO) { // 用户注册方法 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName()); int count = this.count(wrapper); - if(count > 0){ - throw new ServiceException(1, "用户名已存在,换一个吧!"); + if (count > 0) { + throw new ServiceException(1, "用户名已存在,换一个吧!"); // 用户名已存在,抛出异常 } - // 保存用户 SysUser user = new SysUser(); user.setId(IdWorker.getIdStr()); @@ -212,21 +221,22 @@ public class SysUserServiceImpl extends ServiceImpl impl user.setRoleIds(roleIds); this.save(user); + // 返回生成的 token return this.setToken(user); } @Override - public SysUserLoginDTO quickReg(SysUserDTO reqDTO) { + public SysUserLoginDTO quickReg(SysUserDTO reqDTO) { // 快速注册方法 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda().eq(SysUser::getUserName, reqDTO.getUserName()); wrapper.last(" LIMIT 1 "); SysUser user = this.getOne(wrapper); - if(user!=null){ - return this.setToken(user); + if (user != null) { + return this.setToken(user); // 如果用户已存在,直接返回登录信息 } - return this.reg(reqDTO); + return this.reg(reqDTO); // 如果用户不存在,进行注册 } @@ -235,16 +245,16 @@ public class SysUserServiceImpl extends ServiceImpl impl * @param user * @return */ - private SysUserLoginDTO setToken(SysUser user){ + private SysUserLoginDTO setToken(SysUser user) { // 生成并设置用户的 JWT token SysUserLoginDTO respDTO = new SysUserLoginDTO(); BeanMapper.copy(user, respDTO); - // 生成Token + // 生成 JWT token String token = JwtUtils.sign(user.getUserName()); respDTO.setToken(token); - // 填充角色 + // 填充角色信息 List roles = sysUserRoleService.listRoles(user.getId()); respDTO.setRoles(roles); diff --git a/src-源文件/main/java/com/yf/exam/modules/user/UserUtils.java b/src-源文件/main/java/com/yf/exam/modules/user/UserUtils.java index 4477ecb..cb8d96d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/UserUtils.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/UserUtils.java @@ -1,56 +1,56 @@ -package com.yf.exam.modules.user; +package com.yf.exam.modules.user; // 包名:表示该类属于 user 包 -import com.yf.exam.core.api.ApiError; -import com.yf.exam.core.exception.ServiceException; -import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; -import org.apache.shiro.SecurityUtils; +import com.yf.exam.core.api.ApiError; // 导入 ApiError 类,定义 API 错误码 +import com.yf.exam.core.exception.ServiceException; // 导入 ServiceException 类,定义自定义服务异常 +import com.yf.exam.modules.sys.user.dto.response.SysUserLoginDTO; // 导入用户登录响应 DTO 类 +import org.apache.shiro.SecurityUtils; // 导入 Shiro 的 SecurityUtils 类,用于获取当前登录用户的信息 /** * 用户静态工具类 - * @author bool + * 提供当前登录用户的相关工具方法 + * @作者 bool */ public class UserUtils { - /** * 获取当前登录用户的ID - * @param throwable - * @return + * @param throwable 如果发生异常,是否抛出异常 + * @return 当前登录用户的ID */ - public static String getUserId(boolean throwable){ + public static String getUserId(boolean throwable) { // 获取当前登录用户 ID 的方法 try { + // 使用 Shiro 获取当前用户的主体对象,然后从中提取用户 ID return ((SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal()).getId(); - }catch (Exception e){ - if(throwable){ - throw new ServiceException(ApiError.ERROR_10010002); + } catch (Exception e) { // 捕获异常 + if (throwable) { // 如果 throwable 为 true,则抛出自定义服务异常 + throw new ServiceException(ApiError.ERROR_10010002); // 异常码:10010002 } - return null; + return null; // 如果发生异常且 throwable 为 false,则返回 null } } /** * 获取当前登录用户的ID - * @param throwable - * @return + * @param throwable 如果发生异常,是否抛出异常 + * @return 当前登录用户的ID */ - public static boolean isAdmin(boolean throwable){ + public static boolean isAdmin(boolean throwable) { // 判断当前用户是否为管理员的方法 try { - SysUserLoginDTO dto = ((SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal()); - return dto.getRoles().contains("sa"); - }catch (Exception e){ - if(throwable){ - throw new ServiceException(ApiError.ERROR_10010002); + SysUserLoginDTO dto = ((SysUserLoginDTO) SecurityUtils.getSubject().getPrincipal()); // 获取当前用户的登录信息 + return dto.getRoles().contains("sa"); // 判断用户角色中是否包含管理员角色 "sa" + } catch (Exception e) { // 捕获异常 + if (throwable) { // 如果 throwable 为 true,则抛出自定义服务异常 + throw new ServiceException(ApiError.ERROR_10010002); // 异常码:10010002 } } - - return false; + return false; // 如果发生异常且 throwable 为 false,则返回 false } /** * 获取当前登录用户的ID,默认是会抛异常的 - * @return + * @return 当前登录用户的ID */ - public static String getUserId(){ - return getUserId(true); + public static String getUserId() { // 默认抛出异常的获取用户 ID 方法 + return getUserId(true); // 调用带有 throwable 参数的方法,默认抛出异常 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/controller/UserBookController.java b/src-源文件/main/java/com/yf/exam/modules/user/book/controller/UserBookController.java index 9300493..6ece464 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/controller/UserBookController.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/controller/UserBookController.java @@ -1,76 +1,79 @@ -package com.yf.exam.modules.user.book.controller; +package com.yf.exam.modules.user.book.controller; // 包名:表示该类属于 user.book.controller 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.BaseIdRespDTO; -import com.yf.exam.core.api.dto.BaseIdsReqDTO; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.user.book.dto.UserBookDTO; -import com.yf.exam.modules.user.book.service.UserBookService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 分页接口 +import com.yf.exam.core.api.ApiRest; // 导入 ApiRest 类,定义接口返回的统一格式 +import com.yf.exam.core.api.controller.BaseController; // 导入 BaseController 基础控制器类,提供一些基础功能 +import com.yf.exam.core.api.dto.BaseIdRespDTO; // 导入 BaseIdRespDTO 数据传输对象,用于返回 ID 响应 +import com.yf.exam.core.api.dto.BaseIdsReqDTO; // 导入 BaseIdsReqDTO 数据传输对象,用于接收 ID 列表请求 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入 PagingReqDTO 数据传输对象,用于分页请求 +import com.yf.exam.modules.user.book.dto.UserBookDTO; // 导入 UserBookDTO 数据传输对象,用于封装错题本数据 +import com.yf.exam.modules.user.book.service.UserBookService; // 导入 UserBookService 服务接口,用于处理业务逻辑 +import io.swagger.annotations.Api; // 导入 Swagger 的 Api 注解,用于生成 API 文档 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 的 ApiOperation 注解,用于描述 API 操作 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 注解,用于自动注入依赖 +import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 注解,用于接收请求体数据 +import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 注解,用于映射请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入 RequestMethod 枚举,表示请求方法类型 +import org.springframework.web.bind.annotation.RestController; // 导入 RestController 注解,表示这是一个控制器类 /** -*

-* 错题本控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -@Api(tags={"错题本"}) -@RestController -@RequestMapping("/exam/api/user/wrong-book") -public class UserBookController extends BaseController { + *

+ * 错题本控制器 + *

+ * 该控制器处理与错题本相关的 API 请求 + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +@Api(tags={"错题本"}) // 为这个控制器定义一个标签,用于生成 API 文档 +@RestController // 标识该类为 Spring 的控制器类,自动注入到 Spring 上下文 +@RequestMapping("/exam/api/user/wrong-book") // 设置该类的请求路径前缀 +public class UserBookController extends BaseController { // 继承自 BaseController,享受基础功能 @Autowired - private UserBookService baseService; + private UserBookService baseService; // 注入 UserBookService,用于处理错题本的相关逻辑 /** - * 批量删除 - * @param reqDTO - * @return - */ - @ApiOperation(value = "批量删除") - @RequestMapping(value = "/delete", method = { RequestMethod.POST}) - public ApiRest delete(@RequestBody BaseIdsReqDTO reqDTO) { - //根据ID删除 + * 批量删除 + * @param reqDTO 请求数据传输对象,包含多个 ID + * @return 返回成功的响应 + */ + @ApiOperation(value = "批量删除") // 为该方法生成 Swagger 的文档描述 + @RequestMapping(value = "/delete", method = { RequestMethod.POST }) // 映射 POST 请求路径 "/delete" + public ApiRest delete(@RequestBody BaseIdsReqDTO reqDTO) { // 接收请求体中的 ID 列表 + + // 根据 ID 删除错题本数据 baseService.removeByIds(reqDTO.getIds()); - return super.success(); + return super.success(); // 返回成功的响应 } /** - * 分页查找 - * @param reqDTO - * @return - */ - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + * 分页查找 + * @param reqDTO 请求数据传输对象,包含分页参数和查询条件 + * @return 返回分页查询的结果 + */ + @ApiOperation(value = "分页查找") // 为该方法生成 Swagger 的文档描述 + @RequestMapping(value = "/paging", method = { RequestMethod.POST }) // 映射 POST 请求路径 "/paging" + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 接收分页请求数据 - //分页查询并转换 + // 调用服务层的分页查询方法 IPage page = baseService.paging(reqDTO); - return super.success(page); + return super.success(page); // 返回分页查询的结果 } /** * 查找列表,每次最多返回200条数据 - * @param reqDTO - * @return + * @param reqDTO 请求数据传输对象,包含考试 ID 和题目 ID + * @return 返回下一题的 ID */ - @ApiOperation(value = "查找列表") - @RequestMapping(value = "/next", method = { RequestMethod.POST}) - public ApiRest nextQu(@RequestBody UserBookDTO reqDTO) { - //转换并返回 + @ApiOperation(value = "查找列表") // 为该方法生成 Swagger 的文档描述 + @RequestMapping(value = "/next", method = { RequestMethod.POST }) // 映射 POST 请求路径 "/next" + public ApiRest nextQu(@RequestBody UserBookDTO reqDTO) { // 接收包含考试 ID 和题目 ID 的请求数据 + + // 调用服务层的 findNext 方法查找下一题 String quId = baseService.findNext(reqDTO.getExamId(), reqDTO.getQuId()); - return super.success(new BaseIdRespDTO(quId)); + return super.success(new BaseIdRespDTO(quId)); // 返回下一题的 ID } } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/dto/UserBookDTO.java b/src-源文件/main/java/com/yf/exam/modules/user/book/dto/UserBookDTO.java index 582b415..0a6668a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/dto/UserBookDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/dto/UserBookDTO.java @@ -1,52 +1,51 @@ -package com.yf.exam.modules.user.book.dto; +package com.yf.exam.modules.user.book.dto; // 包名:表示该类属于 user.book.dto 包 -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import io.swagger.annotations.ApiModel; // 导入 Swagger 的 ApiModel 注解,用于生成 API 文档中的模型描述 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 的 ApiModelProperty 注解,用于描述模型的属性 +import lombok.Data; // 导入 Lombok 的 Data 注解,自动生成 getters、setters、toString 等方法 -import java.io.Serializable; -import java.util.Date; +import java.io.Serializable; // 导入 Serializable 接口,用于对象序列化 +import java.util.Date; // 导入 Date 类,用于处理日期数据 /** -*

-* 错题本请求类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -@Data -@ApiModel(value="错题本", description="错题本") -public class UserBookDTO implements Serializable { + *

+ * 错题本请求类 + *

+ * 用于封装错题本相关的数据请求 + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +@Data // Lombok 注解,自动生成常用的 getter、setter、toString、equals 和 hashCode 方法 +@ApiModel(value="错题本", description="错题本") // Swagger 注解,定义该类用于描述错题本 +public class UserBookDTO implements Serializable { // 实现 Serializable 接口,支持对象序列化 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 定义序列化版本 UID + @ApiModelProperty(value = "ID", required=true) // Swagger 注解,描述属性的含义和是否必填 + private String id; // 错题本 ID - @ApiModelProperty(value = "ID", required=true) - private String id; + @ApiModelProperty(value = "考试ID", required=true) // Swagger 注解,描述考试 ID + private String examId; // 关联的考试 ID - @ApiModelProperty(value = "考试ID", required=true) - private String examId; + @ApiModelProperty(value = "用户ID", required=true) // Swagger 注解,描述用户 ID + private String userId; // 关联的用户 ID - @ApiModelProperty(value = "用户ID", required=true) - private String userId; + @ApiModelProperty(value = "题目ID", required=true) // Swagger 注解,描述题目 ID + private String quId; // 关联的题目 ID - @ApiModelProperty(value = "题目ID", required=true) - private String quId; + @ApiModelProperty(value = "加入时间", required=true) // Swagger 注解,描述错题本的加入时间 + private Date createTime; // 错题本加入时间 - @ApiModelProperty(value = "加入时间", required=true) - private Date createTime; + @ApiModelProperty(value = "最近错误时间", required=true) // Swagger 注解,描述最近一次错误的时间 + private Date updateTime; // 最近一次错题的时间 - @ApiModelProperty(value = "最近错误时间", required=true) - private Date updateTime; + @ApiModelProperty(value = "错误次数", required=true) // Swagger 注解,描述错题的错误次数 + private Integer wrongCount; // 错题的错误次数 - @ApiModelProperty(value = "错误时间", required=true) - private Integer wrongCount; + @ApiModelProperty(value = "题目标题", required=true) // Swagger 注解,描述题目标题 + private String title; // 题目的标题 - @ApiModelProperty(value = "题目标题", required=true) - private String title; - - @ApiModelProperty(value = "错题序号", required=true) - private Integer sort; - -} \ No newline at end of file + @ApiModelProperty(value = "错题序号", required=true) // Swagger 注解,描述错题的序号 + private Integer sort; // 错题的序号,用于排序 +} diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/entity/UserBook.java b/src-源文件/main/java/com/yf/exam/modules/user/book/entity/UserBook.java index f163425..d339083 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/entity/UserBook.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/entity/UserBook.java @@ -1,78 +1,78 @@ -package com.yf.exam.modules.user.book.entity; +package com.yf.exam.modules.user.book.entity; // 包名:表示该类属于 user.book.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 的 IdType,用于设置 ID 类型 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 TableField 注解,用于标识表字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 TableId 注解,用于标识表的主键 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 TableName 注解,用于标识表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 Model 类,用于支持 Active Record 模式 +import lombok.Data; // 导入 Lombok 的 Data 注解,自动生成 getter、setter、toString 等方法 -import java.util.Date; +import java.util.Date; // 导入 Date 类,用于处理日期类型数据 /** -*

-* 错题本实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -@Data -@TableName("el_user_book") -public class UserBook extends Model { + *

+ * 错题本实体类 + *

+ * 该类表示错题本数据表中的记录 + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +@Data // Lombok 注解,自动为类生成 getter、setter、toString、equals 和 hashCode 方法 +@TableName("el_user_book") // 表示该类对应数据库中的 el_user_book 表 +public class UserBook extends Model { // 继承自 MyBatis-Plus 的 Model 类,支持 Active Record 模式 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本 UID /** * ID */ - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; + @TableId(value = "id", type = IdType.ASSIGN_ID) // 设置表的主键 ID 类型为 ASSIGN_ID,表示数据库自增长 + private String id; // 错题本记录的 ID /** * 考试ID */ - @TableField("exam_id") - private String examId; + @TableField("exam_id") // 映射数据库表的 exam_id 字段 + private String examId; // 关联的考试 ID /** * 用户ID */ - @TableField("user_id") - private String userId; + @TableField("user_id") // 映射数据库表的 user_id 字段 + private String userId; // 关联的用户 ID /** * 题目ID */ - @TableField("qu_id") - private String quId; + @TableField("qu_id") // 映射数据库表的 qu_id 字段 + private String quId; // 关联的题目 ID /** * 加入时间 */ - @TableField("create_time") - private Date createTime; + @TableField("create_time") // 映射数据库表的 create_time 字段 + private Date createTime; // 错题加入时间 /** * 最近错误时间 */ - @TableField("update_time") - private Date updateTime; + @TableField("update_time") // 映射数据库表的 update_time 字段 + private Date updateTime; // 最近一次错误的时间 /** * 错误时间 */ - @TableField("wrong_count") - private Integer wrongCount; + @TableField("wrong_count") // 映射数据库表的 wrong_count 字段 + private Integer wrongCount; // 错误的次数 /** * 题目标题 */ - private String title; + private String title; // 题目的标题 /** * 错题序号 */ - private Integer sort; - + private Integer sort; // 错题的序号,用于排序 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/mapper/UserBookMapper.java b/src-源文件/main/java/com/yf/exam/modules/user/book/mapper/UserBookMapper.java index 67c3cca..ad403de 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/mapper/UserBookMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/mapper/UserBookMapper.java @@ -1,16 +1,17 @@ -package com.yf.exam.modules.user.book.mapper; +package com.yf.exam.modules.user.book.mapper; // 包名:表示该接口属于 user.book.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yf.exam.modules.user.book.entity.UserBook; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,提供基本的 CRUD 操作 +import com.yf.exam.modules.user.book.entity.UserBook; // 导入 UserBook 实体类,表示错题本数据 /** -*

-* 错题本Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -public interface UserBookMapper extends BaseMapper { + *

+ * 错题本Mapper + *

+ * 该接口用于操作错题本相关的数据,继承 MyBatis-Plus 提供的 BaseMapper + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +public interface UserBookMapper extends BaseMapper { // 继承 MyBatis-Plus 的 BaseMapper 接口,自动具备对 UserBook 实体的基本 CRUD 操作 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/service/UserBookService.java b/src-源文件/main/java/com/yf/exam/modules/user/book/service/UserBookService.java index 726a070..0755c7f 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/service/UserBookService.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/service/UserBookService.java @@ -1,40 +1,41 @@ -package com.yf.exam.modules.user.book.service; +package com.yf.exam.modules.user.book.service; // 包名:表示该接口属于 user.book.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.user.book.dto.UserBookDTO; -import com.yf.exam.modules.user.book.entity.UserBook; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,提供常用的 CRUD 操作 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求数据传输对象 +import com.yf.exam.modules.user.book.dto.UserBookDTO; // 导入错题本 DTO 类,用于封装错题本的数据 +import com.yf.exam.modules.user.book.entity.UserBook; // 导入错题本实体类,映射数据库中的错题本表 /** -*

-* 错题本业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -public interface UserBookService extends IService { + *

+ * 错题本业务类 + *

+ * 提供与错题本相关的业务逻辑方法 + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +public interface UserBookService extends IService { // 继承 MyBatis-Plus 的 IService 接口,提供基本的 CRUD 操作 /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + * 分页查询错题本数据 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询结果 + */ + IPage paging(PagingReqDTO reqDTO); // 分页查询错题本数据 /** - * 加入错题本 - * @param quId - * @param examId + * 将错题添加到错题本 + * @param examId 考试 ID + * @param quId 题目 ID */ - void addBook(String examId, String quId); + void addBook(String examId, String quId); // 将指定的错题添加到错题本 /** - * 查找第一个错题 - * @param quId - * @param examId - * @return + * 查找下一个错题 + * @param quId 当前题目 ID + * @param examId 当前考试 ID + * @return 返回下一个错题的 ID */ - String findNext(String examId, String quId); + String findNext(String examId, String quId); // 查找下一个错题 ID } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/book/service/impl/UserBookServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/user/book/service/impl/UserBookServiceImpl.java index e1f7de6..a02f0a4 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/book/service/impl/UserBookServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/book/service/impl/UserBookServiceImpl.java @@ -1,155 +1,153 @@ -package com.yf.exam.modules.user.book.service.impl; - -import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.TypeReference; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.qu.entity.Qu; -import com.yf.exam.modules.qu.service.QuService; -import com.yf.exam.modules.user.UserUtils; -import com.yf.exam.modules.user.book.dto.UserBookDTO; -import com.yf.exam.modules.user.book.entity.UserBook; -import com.yf.exam.modules.user.book.mapper.UserBookMapper; -import com.yf.exam.modules.user.book.service.UserBookService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.StringUtils; +package com.yf.exam.modules.user.book.service.impl; // 包名:表示该类属于 user.book.service.impl 包 + +import com.alibaba.fastjson.JSON; // 导入 fastjson,用于将对象转换为 JSON 字符串 +import com.alibaba.fastjson.TypeReference; // 导入 TypeReference 用于反序列化复杂类型 +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper 类,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的分页插件 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 的 ServiceImpl 基类 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求的 DTO 类 +import com.yf.exam.modules.qu.entity.Qu; // 导入题目实体类 +import com.yf.exam.modules.qu.service.QuService; // 导入题目服务接口 +import com.yf.exam.modules.user.UserUtils; // 导入用户工具类,用于获取当前用户信息 +import com.yf.exam.modules.user.book.dto.UserBookDTO; // 导入错题本 DTO +import com.yf.exam.modules.user.book.entity.UserBook; // 导入错题本实体类 +import com.yf.exam.modules.user.book.mapper.UserBookMapper; // 导入错题本 Mapper 类 +import com.yf.exam.modules.user.book.service.UserBookService; // 导入错题本服务接口 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 注解,用于自动注入依赖 +import org.springframework.stereotype.Service; // 导入 Service 注解,标识该类为 Spring 服务层组件 +import org.springframework.util.StringUtils; // 导入 StringUtils 工具类,用于字符串操作 /** -*

-* 语言设置 服务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-05-27 17:56 -*/ -@Service -public class UserBookServiceImpl extends ServiceImpl implements UserBookService { + *

+ * 错题本服务实现类 + *

+ * 实现了错题本相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-05-27 17:56 + */ +@Service // 标识该类为 Spring 的服务类 +public class UserBookServiceImpl extends ServiceImpl implements UserBookService { // 继承 MyBatis-Plus 的 ServiceImpl,实现 UserBookService 接口 @Autowired - private QuService quService; + private QuService quService; // 注入题目服务,用于获取题目内容 @Override - public IPage paging(PagingReqDTO reqDTO) { + public IPage paging(PagingReqDTO reqDTO) { // 分页查询错题本数据 - //创建分页对象 + // 创建分页对象 Page query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize()); - //查询条件 + // 查询条件 QueryWrapper wrapper = new QueryWrapper<>(); // 查找用户的错题 wrapper.lambda().eq(UserBook::getUserId, UserUtils.getUserId(true)); UserBookDTO params = reqDTO.getParams(); - if(params!=null){ - if(!StringUtils.isEmpty(params.getTitle())){ + if(params != null) { + // 根据题目标题查询 + if(!StringUtils.isEmpty(params.getTitle())) { wrapper.lambda().like(UserBook::getTitle, params.getTitle()); } - if(!StringUtils.isEmpty(params.getExamId())){ + // 根据考试 ID 查询 + if(!StringUtils.isEmpty(params.getExamId())) { wrapper.lambda().eq(UserBook::getExamId, params.getExamId()); } } - //获得数据 + // 执行分页查询 IPage page = this.page(query, wrapper); - //转换结果 - IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>(){}); + // 转换结果为 DTO + IPage pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference>() {}); return pageData; - } - - + } @Override - public void addBook(String examId, String quId) { + public void addBook(String examId, String quId) { // 添加错题到错题本 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .eq(UserBook::getUserId, UserUtils.getUserId()) - .eq(UserBook::getExamId, examId) - .eq(UserBook::getQuId, quId); + .eq(UserBook::getUserId, UserUtils.getUserId()) // 查找当前用户的错题 + .eq(UserBook::getExamId, examId) // 查找特定考试的错题 + .eq(UserBook::getQuId, quId); // 查找特定题目的错题 - //查找已有的错题信息 + // 查找已有的错题信息 UserBook book = this.getOne(wrapper, false); - - // 问题 + // 获取题目信息 Qu qu = quService.getById(quId); - if (book == null) { + if (book == null) { // 如果错题本中没有该题目,则添加 book = new UserBook(); book.setExamId(examId); - book.setUserId(UserUtils.getUserId()); - book.setTitle(qu.getContent()); + book.setUserId(UserUtils.getUserId()); // 设置当前用户的 ID + book.setTitle(qu.getContent()); // 设置题目内容 book.setQuId(quId); - book.setWrongCount(1); - Integer maxSort = this.findMaxSort(examId, UserUtils.getUserId()); - book.setSort(maxSort+1); - - this.save(book); - } else { - book.setWrongCount(book.getWrongCount()+1); - this.updateById(book); + book.setWrongCount(1); // 错误次数初始化为 1 + Integer maxSort = this.findMaxSort(examId, UserUtils.getUserId()); // 查找当前用户的最大排序号 + book.setSort(maxSort + 1); // 设置错题的排序号 + + this.save(book); // 保存错题记录 + } else { // 如果错题本中已有该题目,则更新错误次数 + book.setWrongCount(book.getWrongCount() + 1); // 错误次数加 1 + this.updateById(book); // 更新错题记录 } } @Override - public String findNext(String examId, String quId) { - + public String findNext(String examId, String quId) { // 查找下一个错题 Integer sort = 999999; - if(!StringUtils.isEmpty(quId)){ + if(!StringUtils.isEmpty(quId)) { QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .eq(UserBook::getUserId, UserUtils.getUserId()) - .eq(UserBook::getExamId, examId) - .eq(UserBook::getQuId, quId); - wrapper.last(" ORDER BY `sort` DESC"); + .eq(UserBook::getUserId, UserUtils.getUserId()) // 查找当前用户的错题 + .eq(UserBook::getExamId, examId) // 查找特定考试的错题 + .eq(UserBook::getQuId, quId); // 查找特定题目的错题 + wrapper.last(" ORDER BY `sort` DESC"); // 按照排序降序排列 UserBook last = this.getOne(wrapper, false); - if(last!=null){ - sort = last.getSort(); + if(last != null) { + sort = last.getSort(); // 获取当前错题的排序号 } } QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .eq(UserBook::getUserId, UserUtils.getUserId()) - .eq(UserBook::getExamId, examId) - .lt(UserBook::getSort, sort); - wrapper.last(" ORDER BY `sort` DESC"); - - UserBook next = this.getOne(wrapper, false); - if(next != null){ - return next.getQuId(); + .eq(UserBook::getUserId, UserUtils.getUserId()) // 查找当前用户的错题 + .eq(UserBook::getExamId, examId) // 查找特定考试的错题 + .lt(UserBook::getSort, sort); // 查找排序号小于当前错题的错题 + wrapper.last(" ORDER BY `sort` DESC"); // 按照排序降序排列 + + UserBook next = this.getOne(wrapper, false); // 查找下一个错题 + if(next != null) { + return next.getQuId(); // 返回下一个错题的 ID } - return null; + return null; // 如果没有下一个错题,返回 null } /** * 查找最大的排序 - * @param userId - * @return + * @param examId 考试 ID + * @param userId 用户 ID + * @return 返回最大的排序号 */ - private Integer findMaxSort(String examId, String userId){ + private Integer findMaxSort(String examId, String userId) { // 查找当前用户在某个考试中的最大排序号 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.lambda() - .eq(UserBook::getExamId, examId) - .eq(UserBook::getUserId, userId); - wrapper.last(" ORDER BY `sort` DESC"); + .eq(UserBook::getExamId, examId) // 查找特定考试的错题 + .eq(UserBook::getUserId, userId); // 查找当前用户的错题 + wrapper.last(" ORDER BY `sort` DESC"); // 按照排序号降序排列 - UserBook book = this.getOne(wrapper, false); - if(book == null){ - return 0; + UserBook book = this.getOne(wrapper, false); // 获取最大排序号的错题 + if(book == null) { + return 0; // 如果没有错题,返回 0 } - return book.getSort(); + return book.getSort(); // 返回最大排序号 } - - } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/controller/UserExamController.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/controller/UserExamController.java index 65cf11c..f848356 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/controller/UserExamController.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/controller/UserExamController.java @@ -1,65 +1,64 @@ -package com.yf.exam.modules.user.exam.controller; +package com.yf.exam.modules.user.exam.controller; // 包名:表示该类属于 user.exam.controller 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.api.controller.BaseController; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; -import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; -import com.yf.exam.modules.user.exam.service.UserExamService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.yf.exam.core.api.ApiRest; // 导入 API 响应封装类,用于统一返回格式 +import com.yf.exam.core.api.controller.BaseController; // 导入基础控制器类,提供通用的接口方法 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO 类,用于封装分页参数 +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; // 导入用户考试请求 DTO 类,用于封装考试查询参数 +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; // 导入用户考试响应 DTO 类,用于封装查询结果 +import com.yf.exam.modules.user.exam.service.UserExamService; // 导入用户考试服务接口,用于处理考试相关的业务逻辑 +import io.swagger.annotations.Api; // 导入 Swagger 注解,用于生成 API 文档中的标签 +import io.swagger.annotations.ApiOperation; // 导入 Swagger 注解,用于描述接口方法 +import org.springframework.beans.factory.annotation.Autowired; // 导入 Autowired 注解,用于自动注入依赖 +import org.springframework.web.bind.annotation.RequestBody; // 导入 RequestBody 注解,用于绑定请求体参数 +import org.springframework.web.bind.annotation.RequestMapping; // 导入 RequestMapping 注解,用于映射请求路径 +import org.springframework.web.bind.annotation.RequestMethod; // 导入 RequestMethod 枚举,用于指定请求方法类型 +import org.springframework.web.bind.annotation.RestController; // 导入 RestController 注解,标识该类为 RESTful 风格的控制器 /** -*

-* 考试记录控制器 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Api(tags={"考试记录"}) -@RestController -@RequestMapping("/exam/api/user/exam") -public class UserExamController extends BaseController { + *

+ * 考试记录控制器 + *

+ * 用于处理用户的考试记录相关请求 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Api(tags={"考试记录"}) // Swagger 注解,定义该类在 API 文档中的标签 +@RestController // 标识该类为 RESTful 风格的控制器 +@RequestMapping("/exam/api/user/exam") // 映射请求路径,所有接口都以 "/exam/api/user/exam" 开头 +public class UserExamController extends BaseController { // 继承 BaseController,提供基础的响应方法 @Autowired - private UserExamService baseService; - + private UserExamService baseService; // 自动注入 UserExamService 服务,处理考试记录相关业务 /** - * 分页查找 - * @param reqDTO - * @return + * 分页查找考试记录 + * @param reqDTO 分页请求数据传输对象 + * @return 返回分页查询的考试记录结果 */ - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/paging", method = { RequestMethod.POST}) - public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { + @ApiOperation(value = "分页查找") // Swagger 注解,描述接口方法的作用 + @RequestMapping(value = "/paging", method = { RequestMethod.POST}) // 映射 POST 请求路径 "/exam/api/user/exam/paging" + public ApiRest> paging(@RequestBody PagingReqDTO reqDTO) { // 接收分页请求,返回分页结果 - //分页查询并转换 + // 调用服务层方法进行分页查询,并将结果转换为响应 DTO IPage page = baseService.paging(reqDTO); - return super.success(page); + return super.success(page); // 调用父类的 success 方法返回查询结果 } - /** - * 分页查找 - * @param reqDTO - * @return - */ - @ApiOperation(value = "分页查找") - @RequestMapping(value = "/my-paging", method = { RequestMethod.POST}) - public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { + * 分页查找用户自己的考试记录 + * @param reqDTO 分页请求数据传输对象 + * @return 返回用户的分页考试记录 + */ + @ApiOperation(value = "分页查找") // Swagger 注解,描述接口方法的作用 + @RequestMapping(value = "/my-paging", method = { RequestMethod.POST}) // 映射 POST 请求路径 "/exam/api/user/exam/my-paging" + public ApiRest> myPaging(@RequestBody PagingReqDTO reqDTO) { // 接收分页请求,返回用户的分页考试记录 - //分页查询并转换 + // 调用服务层方法进行分页查询,并将结果转换为响应 DTO IPage page = baseService.myPaging(reqDTO); - return super.success(page); + return super.success(page); // 调用父类的 success 方法返回查询结果 } } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/UserExamDTO.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/UserExamDTO.java index 61a0c23..b10110d 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/UserExamDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/UserExamDTO.java @@ -1,50 +1,72 @@ -package com.yf.exam.modules.user.exam.dto; +package com.yf.exam.modules.user.exam.dto; // 包名:表示该类属于 user.exam.dto 包 -import com.yf.exam.core.annon.Dict; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import java.util.Date; - -import java.io.Serializable; +import com.yf.exam.core.annon.Dict; // 导入 Dict 注解,用于字段的字典数据转换 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于生成 API 文档中的描述 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述类字段 +import lombok.Data; // 导入 Lombok 的 Data 注解,用于自动生成 getter、setter 等方法 +import java.util.Date; // 导入 Date 类,用于处理时间 +import java.io.Serializable; // 导入 Serializable 接口,确保该类可以序列化 /** -*

-* 考试记录数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Data -@ApiModel(value="考试记录", description="考试记录") -public class UserExamDTO implements Serializable { - - private static final long serialVersionUID = 1L; - - - private String id; - - @ApiModelProperty(value = "用户ID", required=true) - private String userId; - - @Dict(dictTable = "el_exam", dicText = "title", dicCode = "id") - @ApiModelProperty(value = "考试ID", required=true) - private String examId; - - @ApiModelProperty(value = "考试次数", required=true) - private Integer tryCount; - - @ApiModelProperty(value = "最高分数", required=true) - private Integer maxScore; - - @ApiModelProperty(value = "是否通过", required=true) - private Boolean passed; - - @ApiModelProperty(value = "创建时间") - private Date createTime; - - @ApiModelProperty(value = "更新时间") - private Date updateTime; - + *

+ * 考试记录数据传输类 + *

+ * 用于封装考试记录相关数据 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Data // Lombok 注解,自动为类生成 getter、setter、toString 等方法 +@ApiModel(value="考试记录", description="考试记录") // Swagger 注解,描述该类的作用,生成 API 文档时使用 +public class UserExamDTO implements Serializable { // 实现 Serializable 接口,使该类可以序列化 + + private static final long serialVersionUID = 1L; // 序列化版本 UID + + /** + * 用户ID + */ + private String id; // 用户ID字段 + + /** + * 用户ID + */ + @ApiModelProperty(value = "用户ID", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String userId; // 用户ID字段 + + /** + * 考试ID + */ + @Dict(dictTable = "el_exam", dicText = "title", dicCode = "id") // 使用 Dict 注解,指定字典表及映射字段 + @ApiModelProperty(value = "考试ID", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String examId; // 考试ID字段 + + /** + * 考试次数 + */ + @ApiModelProperty(value = "考试次数", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private Integer tryCount; // 考试次数字段 + + /** + * 最高分数 + */ + @ApiModelProperty(value = "最高分数", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private Integer maxScore; // 最高分数字段 + + /** + * 是否通过 + */ + @ApiModelProperty(value = "是否通过", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private Boolean passed; // 是否通过字段 + + /** + * 创建时间 + */ + @ApiModelProperty(value = "创建时间") // Swagger 注解,描述字段的作用 + private Date createTime; // 创建时间字段 + + /** + * 更新时间 + */ + @ApiModelProperty(value = "更新时间") // Swagger 注解,描述字段的作用 + private Date updateTime; // 更新时间字段 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/request/UserExamReqDTO.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/request/UserExamReqDTO.java index e554837..d792bc2 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/request/UserExamReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/request/UserExamReqDTO.java @@ -1,30 +1,34 @@ -package com.yf.exam.modules.user.exam.dto.request; +package com.yf.exam.modules.user.exam.dto.request; // 包名:表示该类属于 user.exam.dto.request 包 -import com.yf.exam.modules.user.exam.dto.UserExamDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.user.exam.dto.UserExamDTO; // 导入 UserExamDTO 类,作为父类,包含通用的考试记录信息 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于生成 API 文档中的描述 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述类字段 +import lombok.Data; // 导入 Lombok 的 Data 注解,用于自动生成 getter、setter 等方法 /** -*

-* 考试记录数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Data -@ApiModel(value="考试记录", description="考试记录") -public class UserExamReqDTO extends UserExamDTO { - - private static final long serialVersionUID = 1L; - - - @ApiModelProperty(value = "考试名称", required=true) - private String title; - - @ApiModelProperty(value = "人员名称", required=true) - private String realName; - - + *

+ * 考试记录数据传输类 + *

+ * 用于封装请求中的考试记录数据 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Data // Lombok 注解,自动为类生成 getter、setter、toString 等方法 +@ApiModel(value="考试记录", description="考试记录") // Swagger 注解,描述该类的作用,生成 API 文档时使用 +public class UserExamReqDTO extends UserExamDTO { // 继承 UserExamDTO 类,扩展额外的请求字段 + + private static final long serialVersionUID = 1L; // 序列化版本 UID + + /** + * 考试名称 + */ + @ApiModelProperty(value = "考试名称", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String title; // 考试名称字段 + + /** + * 人员名称 + */ + @ApiModelProperty(value = "人员名称", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String realName; // 人员名称字段 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/response/UserExamRespDTO.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/response/UserExamRespDTO.java index 0ad1d39..13a11c5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/response/UserExamRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/dto/response/UserExamRespDTO.java @@ -1,29 +1,34 @@ -package com.yf.exam.modules.user.exam.dto.response; +package com.yf.exam.modules.user.exam.dto.response; // 包名:表示该类属于 user.exam.dto.response 包 -import com.yf.exam.modules.user.exam.dto.UserExamDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.modules.user.exam.dto.UserExamDTO; // 导入 UserExamDTO 类,作为父类,包含通用的考试记录信息 +import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于生成 API 文档中的描述 +import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述类字段 +import lombok.Data; // 导入 Lombok 的 Data 注解,用于自动生成 getter、setter 等方法 /** -*

-* 考试记录数据传输类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Data -@ApiModel(value="考试记录", description="考试记录") -public class UserExamRespDTO extends UserExamDTO { + *

+ * 考试记录数据传输类 + *

+ * 用于封装响应中的考试记录数据 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Data // Lombok 注解,自动为类生成 getter、setter、toString 等方法 +@ApiModel(value="考试记录", description="考试记录") // Swagger 注解,描述该类的作用,生成 API 文档时使用 +public class UserExamRespDTO extends UserExamDTO { // 继承 UserExamDTO 类,扩展额外的响应字段 - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; // 序列化版本 UID + /** + * 考试名称 + */ + @ApiModelProperty(value = "考试名称", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String title; // 考试名称字段 - @ApiModelProperty(value = "考试名称", required=true) - private String title; - - @ApiModelProperty(value = "人员名称", required=true) - private String realName; - + /** + * 人员名称 + */ + @ApiModelProperty(value = "人员名称", required=true) // Swagger 注解,描述字段的作用,设置为必填项 + private String realName; // 人员名称字段 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/entity/UserExam.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/entity/UserExam.java index 7721d40..499ce37 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/entity/UserExam.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/entity/UserExam.java @@ -1,69 +1,72 @@ -package com.yf.exam.modules.user.exam.entity; +package com.yf.exam.modules.user.exam.entity; // 包名:表示该类属于 user.exam.entity 包 -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.activerecord.Model; -import lombok.Data; -import java.util.Date; +import com.baomidou.mybatisplus.annotation.IdType; // 导入 MyBatis-Plus 注解,用于指定主键策略 +import com.baomidou.mybatisplus.annotation.TableField; // 导入 MyBatis-Plus 注解,用于指定数据库表字段 +import com.baomidou.mybatisplus.annotation.TableId; // 导入 MyBatis-Plus 注解,用于指定主键字段 +import com.baomidou.mybatisplus.annotation.TableName; // 导入 MyBatis-Plus 注解,用于指定数据库表名 +import com.baomidou.mybatisplus.extension.activerecord.Model; // 导入 MyBatis-Plus 提供的 Model 类,用于增强实体类 +import lombok.Data; // 导入 Lombok 注解,用于自动生成 getter、setter 等方法 +import java.util.Date; // 导入 Date 类,用于处理时间 /** -*

-* 考试记录实体类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Data -@TableName("el_user_exam") -public class UserExam extends Model { + *

+ * 考试记录实体类 + *

+ * 用于映射数据库中的考试记录表 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Data // Lombok 注解,自动为类生成 getter、setter、toString 等方法 +@TableName("el_user_exam") // MyBatis-Plus 注解,指定该实体类对应的数据库表名为 "el_user_exam" +public class UserExam extends Model { // 继承 Model 类,提供额外的 MyBatis-Plus 功能 + + private static final long serialVersionUID = 1L; // 序列化版本 UID - private static final long serialVersionUID = 1L; - - @TableId(value = "id", type = IdType.ASSIGN_ID) - private String id; - /** - * 用户ID - */ - @TableField("user_id") - private String userId; - + * ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,指定主键字段为 "id",主键类型为 "ASSIGN_ID" + private String id; // ID字段 + /** - * 考试ID - */ - @TableField("exam_id") - private String examId; - + * 用户ID + */ + @TableField("user_id") // MyBatis-Plus 注解,指定数据库字段 "user_id" 对应实体类的 "userId" 字段 + private String userId; // 用户ID字段 + /** - * 考试次数 - */ - @TableField("try_count") - private Integer tryCount; - + * 考试ID + */ + @TableField("exam_id") // MyBatis-Plus 注解,指定数据库字段 "exam_id" 对应实体类的 "examId" 字段 + private String examId; // 考试ID字段 + /** - * 最高分数 - */ - @TableField("max_score") - private Integer maxScore; - + * 考试次数 + */ + @TableField("try_count") // MyBatis-Plus 注解,指定数据库字段 "try_count" 对应实体类的 "tryCount" 字段 + private Integer tryCount; // 考试次数字段 + /** - * 是否通过 - */ - private Boolean passed; - + * 最高分数 + */ + @TableField("max_score") // MyBatis-Plus 注解,指定数据库字段 "max_score" 对应实体类的 "maxScore" 字段 + private Integer maxScore; // 最高分数字段 + + /** + * 是否通过 + */ + private Boolean passed; // 是否通过字段 + /** - * 创建时间 - */ - @TableField("create_time") - private Date createTime; - + * 创建时间 + */ + @TableField("create_time") // MyBatis-Plus 注解,指定数据库字段 "create_time" 对应实体类的 "createTime" 字段 + private Date createTime; // 创建时间字段 + /** - * 更新时间 - */ - @TableField("update_time") - private Date updateTime; - + * 更新时间 + */ + @TableField("update_time") // MyBatis-Plus 注解,指定数据库字段 "update_time" 对应实体类的 "updateTime" 字段 + private Date updateTime; // 更新时间字段 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/mapper/UserExamMapper.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/mapper/UserExamMapper.java index c28ce6f..c5cd0b5 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/mapper/UserExamMapper.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/mapper/UserExamMapper.java @@ -1,29 +1,29 @@ -package com.yf.exam.modules.user.exam.mapper; +package com.yf.exam.modules.user.exam.mapper; // 包名:表示该类属于 user.exam.mapper 包 -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; -import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; -import com.yf.exam.modules.user.exam.entity.UserExam; -import org.apache.ibatis.annotations.Param; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,提供基本的数据库操作 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入 MyBatis-Plus 的 Page 类,用于分页查询 +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; // 导入用户考试请求 DTO 类,用于封装分页查询请求 +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; // 导入用户考试响应 DTO 类,用于封装分页查询结果 +import com.yf.exam.modules.user.exam.entity.UserExam; // 导入用户考试实体类,用于映射数据库表 +import org.apache.ibatis.annotations.Param; // 导入 MyBatis 的 Param 注解,用于标注方法参数 /** -*

-* 考试记录Mapper -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -public interface UserExamMapper extends BaseMapper { + *

+ * 考试记录Mapper + *

+ * 用于处理考试记录的数据访问层操作 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +public interface UserExamMapper extends BaseMapper { // 继承 BaseMapper 提供基础的增删改查功能 /** - * 我的考试分页 - * @param page - * @param query - * @return + * 我的考试分页查询 + * @param page 分页对象,用于控制查询的页数和每页的数据量 + * @param query 查询参数,封装了分页和查询条件 + * @return 返回分页查询的结果 */ - IPage paging(Page page, @Param("query") UserExamReqDTO query); - + IPage paging(Page page, @Param("query") UserExamReqDTO query); // 自定义分页查询方法,返回分页结果 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/service/UserExamService.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/service/UserExamService.java index d1fbf72..4e3eb92 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/service/UserExamService.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/service/UserExamService.java @@ -1,43 +1,43 @@ -package com.yf.exam.modules.user.exam.service; +package com.yf.exam.modules.user.exam.service; // 包名:表示该类属于 user.exam.service 包 -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; -import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; -import com.yf.exam.modules.user.exam.entity.UserExam; +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.IService; // 导入 MyBatis-Plus 的 IService 接口,提供基础服务接口 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO 类,用于封装分页查询请求 +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; // 导入用户考试请求 DTO 类 +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; // 导入用户考试响应 DTO 类 +import com.yf.exam.modules.user.exam.entity.UserExam; // 导入用户考试实体类,用于映射数据库表 /** -*

-* 考试记录业务类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -public interface UserExamService extends IService { - - /** - * 分页查询数据 - * @param reqDTO - * @return - */ - IPage paging(PagingReqDTO reqDTO); + *

+ * 考试记录业务类 + *

+ * 提供用户考试记录相关的业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +public interface UserExamService extends IService { // 继承 IService 接口,提供对 UserExam 实体的增删改查功能 /** * 分页查询数据 - * @param reqDTO - * @return + * @param reqDTO 分页请求 DTO,封装了分页查询参数 + * @return 返回分页查询的结果 */ - IPage myPaging(PagingReqDTO reqDTO); + IPage paging(PagingReqDTO reqDTO); // 用于分页查询考试记录 + /** + * 分页查询数据,针对当前用户 + * @param reqDTO 分页请求 DTO,封装了分页查询参数 + * @return 返回分页查询的结果 + */ + IPage myPaging(PagingReqDTO reqDTO); // 用于分页查询当前用户的考试记录 /** * 考试完成后加入成绩 - * @param userId - * @param examId - * @param score - * @param passed + * @param userId 用户ID + * @param examId 考试ID + * @param score 用户得分 + * @param passed 用户是否通过考试 */ - void joinResult(String userId, String examId, Integer score, boolean passed); + void joinResult(String userId, String examId, Integer score, boolean passed); // 记录用户考试结果 } diff --git a/src-源文件/main/java/com/yf/exam/modules/user/exam/service/impl/UserExamServiceImpl.java b/src-源文件/main/java/com/yf/exam/modules/user/exam/service/impl/UserExamServiceImpl.java index 226eb84..c08fc2a 100644 --- a/src-源文件/main/java/com/yf/exam/modules/user/exam/service/impl/UserExamServiceImpl.java +++ b/src-源文件/main/java/com/yf/exam/modules/user/exam/service/impl/UserExamServiceImpl.java @@ -1,88 +1,87 @@ -package com.yf.exam.modules.user.exam.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yf.exam.core.api.dto.PagingReqDTO; -import com.yf.exam.modules.user.UserUtils; -import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; -import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; -import com.yf.exam.modules.user.exam.entity.UserExam; -import com.yf.exam.modules.user.exam.mapper.UserExamMapper; -import com.yf.exam.modules.user.exam.service.UserExamService; -import org.springframework.stereotype.Service; - -import java.util.Date; +package com.yf.exam.modules.user.exam.service.impl; // 包名:表示该类属于 user.exam.service.impl 包 + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; // 导入 MyBatis-Plus 的 QueryWrapper,用于构建查询条件 +import com.baomidou.mybatisplus.core.metadata.IPage; // 导入 MyBatis-Plus 的 IPage 接口,用于分页查询 +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; // 导入 MyBatis-Plus 提供的 ServiceImpl 类,提供基础的服务层实现 +import com.yf.exam.core.api.dto.PagingReqDTO; // 导入分页请求 DTO 类,用于封装分页查询请求 +import com.yf.exam.modules.user.UserUtils; // 导入 UserUtils 工具类,用于获取当前用户的 ID +import com.yf.exam.modules.user.exam.dto.request.UserExamReqDTO; // 导入用户考试请求 DTO 类 +import com.yf.exam.modules.user.exam.dto.response.UserExamRespDTO; // 导入用户考试响应 DTO 类 +import com.yf.exam.modules.user.exam.entity.UserExam; // 导入用户考试实体类,用于映射数据库表 +import com.yf.exam.modules.user.exam.mapper.UserExamMapper; // 导入用户考试 Mapper 类,提供数据库操作 +import com.yf.exam.modules.user.exam.service.UserExamService; // 导入用户考试服务接口 +import org.springframework.stereotype.Service; // 导入 Service 注解,标识该类为服务层组件 + +import java.util.Date; // 导入 Date 类,用于处理时间 /** -*

-* 考试记录业务实现类 -*

-* -* @author 聪明笨狗 -* @since 2020-09-21 15:13 -*/ -@Service -public class UserExamServiceImpl extends ServiceImpl implements UserExamService { + *

+ * 考试记录业务实现类 + *

+ * 实现了 UserExamService 接口,提供考试记录相关业务逻辑 + * + * @作者 聪明笨狗 + * @版本 2020-09-21 15:13 + */ +@Service // 标识该类为 Spring 服务层组件 +public class UserExamServiceImpl extends ServiceImpl implements UserExamService { // 继承 ServiceImpl 类,提供基础的增删改查功能,并实现 UserExamService 接口 @Override - public IPage paging(PagingReqDTO reqDTO) { + public IPage paging(PagingReqDTO reqDTO) { // 分页查询方法 - //转换结果 + // 使用 MyBatis-Plus 提供的 paging 方法进行分页查询,并转换为响应 DTO 类型 IPage pageData = baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); - return pageData; + return pageData; // 返回分页查询结果 } @Override - public IPage myPaging(PagingReqDTO reqDTO) { + public IPage myPaging(PagingReqDTO reqDTO) { // 我的考试分页查询方法 - UserExamReqDTO params = reqDTO.getParams(); + UserExamReqDTO params = reqDTO.getParams(); // 获取请求参数 - - if(params==null){ + // 如果没有传入参数,则初始化为空的 UserExamReqDTO 对象 + if(params == null) { params = new UserExamReqDTO(); } - params.setUserId(UserUtils.getUserId()); - + params.setUserId(UserUtils.getUserId()); // 设置当前用户的 ID - //转换结果 + // 使用 MyBatis-Plus 提供的 paging 方法进行分页查询,并转换为响应 DTO 类型 IPage pageData = baseMapper.paging(reqDTO.toPage(), params); - return pageData; + return pageData; // 返回分页查询结果 } @Override - public void joinResult(String userId, String examId, Integer score, boolean passed) { + public void joinResult(String userId, String examId, Integer score, boolean passed) { // 记录考试结果的方法 - //查询条件 + // 构建查询条件,查找用户的考试记录 QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.lambda().eq(UserExam::getUserId, userId) - .eq(UserExam::getExamId, examId); + wrapper.lambda().eq(UserExam::getUserId, userId) // 查询条件:用户 ID + .eq(UserExam::getExamId, examId); // 查询条件:考试 ID - UserExam record = this.getOne(wrapper, false); - if(record == null){ + UserExam record = this.getOne(wrapper, false); // 查找匹配的记录 + if(record == null) { // 如果记录不存在,则创建新记录 record = new UserExam(); - record.setCreateTime(new Date()); - record.setUpdateTime(new Date()); - record.setUserId(userId); - record.setExamId(examId); - record.setMaxScore(score); - record.setPassed(passed); - this.save(record); + record.setCreateTime(new Date()); // 设置创建时间 + record.setUpdateTime(new Date()); // 设置更新时间 + record.setUserId(userId); // 设置用户 ID + record.setExamId(examId); // 设置考试 ID + record.setMaxScore(score); // 设置最大分数 + record.setPassed(passed); // 设置是否通过 + this.save(record); // 保存新记录 return; } - // 修复低分数不加入统计问题 - record.setTryCount(record.getTryCount()+1); - record.setUpdateTime(new Date()); + // 如果记录存在,则更新该记录 + record.setTryCount(record.getTryCount() + 1); // 增加考试次数 + record.setUpdateTime(new Date()); // 更新更新时间 - if(record.getMaxScore() < score){ - record.setMaxScore(score); - record.setPassed(passed); + // 如果当前分数高于记录中的最大分数,则更新最大分数 + if(record.getMaxScore() < score) { + record.setMaxScore(score); // 更新最大分数 + record.setPassed(passed); // 更新是否通过 } - this.updateById(record); - - + this.updateById(record); // 更新记录 } } From be4ff0967febd638fe767b82889b29cc99e9eada Mon Sep 17 00:00:00 2001 From: kwc <3316977819@qq.com> Date: Thu, 28 Nov 2024 08:22:43 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=8C=A1=E6=96=87=E8=B6=85=E5=88=86?= =?UTF-8?q?=E6=94=AF=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/yf/exam/core/annon/Dict.java | 25 +- .../java/com/yf/exam/core/api/ApiError.java | 80 ++- .../java/com/yf/exam/core/api/ApiRest.java | 54 +- .../core/api/controller/BaseController.java | 136 +++-- .../com/yf/exam/core/api/dto/BaseDTO.java | 7 + .../yf/exam/core/api/dto/BaseIdReqDTO.java | 34 +- .../yf/exam/core/api/dto/BaseIdRespDTO.java | 30 +- .../yf/exam/core/api/dto/BaseIdsReqDTO.java | 30 +- .../yf/exam/core/api/dto/BaseStateReqDTO.java | 42 +- .../yf/exam/core/api/dto/PagingReqDTO.java | 59 +-- .../yf/exam/core/api/dto/PagingRespDTO.java | 28 +- .../yf/exam/core/api/utils/JsonConverter.java | 58 +-- .../com/yf/exam/core/enums/CommonState.java | 16 +- .../java/com/yf/exam/core/enums/OpenType.java | 11 +- .../exam/core/exception/ServiceException.java | 45 +- .../exception/ServiceExceptionHandler.java | 44 +- .../com/yf/exam/core/utils/BeanMapper.java | 45 +- .../com/yf/exam/core/utils/CronUtils.java | 33 +- .../com/yf/exam/core/utils/DateUtils.java | 90 ++-- .../java/com/yf/exam/core/utils/IpUtils.java | 48 +- .../com/yf/exam/core/utils/Reflections.java | 301 ++++++----- .../com/yf/exam/core/utils/SpringUtils.java | 37 +- .../com/yf/exam/core/utils/StringUtils.java | 39 +- .../yf/exam/core/utils/excel/ExportExcel.java | 481 +++++++++--------- .../yf/exam/core/utils/excel/ImportExcel.java | 326 ++++++------ .../utils/excel/annotation/ExcelField.java | 28 + .../core/utils/excel/fieldtype/ListType.java | 51 +- .../com/yf/exam/core/utils/file/Md5Util.java | 34 +- .../exam/core/utils/passwd/PassHandler.java | 33 +- .../yf/exam/core/utils/passwd/PassInfo.java | 51 +- 30 files changed, 1161 insertions(+), 1135 deletions(-) diff --git a/src-源文件/main/java/com/yf/exam/core/annon/Dict.java b/src-源文件/main/java/com/yf/exam/core/annon/Dict.java index 4aa3f07..17f8813 100644 --- a/src-源文件/main/java/com/yf/exam/core/annon/Dict.java +++ b/src-源文件/main/java/com/yf/exam/core/annon/Dict.java @@ -1,21 +1,22 @@ -package com.yf.exam.core.annon; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/annon/Dict.java +package com.yf.exam.core.annon; // 定义包名,表示该类属于 com.yf.exam.core.annon 包 -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import java.lang.annotation.ElementType; // 导入 ElementType 类,用于指定注解可以应用于的元素类型 +import java.lang.annotation.Retention; // 导入 Retention 类,用于指定注解的保留策略 +import java.lang.annotation.RetentionPolicy; // 导入 RetentionPolicy 类,定义注解的保留策略 +import java.lang.annotation.Target; // 导入 Target 类,用于指定注解的适用范围 /** * 数据字典注解 * @author bool */ -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Dict { +@Target(ElementType.FIELD) // 指定该注解可以应用于字段(类的属性) +@Retention(RetentionPolicy.RUNTIME) // 指定该注解在运行时仍然可用 +public @interface Dict { // 定义一个名为 Dict 的注解 - String dicCode(); + String dicCode(); // 定义一个抽象方法 dicCode,返回数据字典的代码 - String dicText() default ""; + String dicText() default ""; // 定义一个抽象方法 dicText,返回数据字典的文本,默认为空字符串 - String dictTable() default ""; -} + String dictTable() default ""; // 定义一个抽象方法 dictTable,返回数据字典的表名,默认为空字符串 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/ApiError.java b/src-源文件/main/java/com/yf/exam/core/api/ApiError.java index f299fac..d9584a9 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/ApiError.java +++ b/src-源文件/main/java/com/yf/exam/core/api/ApiError.java @@ -1,67 +1,63 @@ -package com.yf.exam.core.api; +package com.yf.exam.core.api; // 定义包名 +import lombok.AllArgsConstructor; // 导入Lombok的全参构造器注解 +import lombok.NoArgsConstructor; // 导入Lombok的无参构造器注解 -import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; - -import java.io.Serializable; +import java.io.Serializable; // 导入Serializable接口 /** - * 全局错误码定义,用于定义接口的响应数据, - * 枚举名称全部使用代码命名,在系统中调用,免去取名难的问题。 - * @author bool - * @date 2019-06-14 21:15 + * 全局错误码定义,用于定义接口的响应数据, // 类注释,说明该类的用途 + * 枚举名称全部使用代码命名,在系统中调用,免去取名难的问题。 // 说明枚举命名规则 + * @author bool // 作者信息 + * @date 2019-06-14 21:15 // 日期信息 */ -@NoArgsConstructor -@AllArgsConstructor -public enum ApiError implements Serializable { - +@NoArgsConstructor // 生成无参构造器 +@AllArgsConstructor // 生成全参构造器 +public enum ApiError implements Serializable { // 定义ApiError枚举,实现Serializable接口 /** * 通用错误,接口参数不全 */ - ERROR_10010001("参数不全或类型错误!"), - ERROR_10010002("您还未登录,请先登录!"), - ERROR_10010003("数据不存在!"), - ERROR_10010012("图形验证码错误!"), - ERROR_10010013("短信验证码错误!"), - ERROR_10010014("不允许重复评论!"), + ERROR_10010001("参数不全或类型错误!"), // 错误码10010001及其对应的消息 + ERROR_10010002("您还未登录,请先登录!"), // 错误码10010002及其对应的消息 + ERROR_10010003("数据不存在!"), // 错误码10010003及其对应的消息 + ERROR_10010012("图形验证码错误!"), // 错误码10010012及其对应的消息 + ERROR_10010013("短信验证码错误!"), // 错误码10010013及其对应的消息 + ERROR_10010014("不允许重复评论!"), // 错误码10010014及其对应的消息 /** * 考试相关错误 */ - ERROR_20010001("试题被删除,无法继续考试!"), - ERROR_20010002("您有正在进行的考试!"), - - - ERROR_90010001("账号不存在,请确认!"), - ERROR_90010002("账号或密码错误!"), - ERROR_90010003("至少要包含一个角色!"), - ERROR_90010004("管理员账号无法修改!"), - ERROR_90010005("账号被禁用,请联系管理员!"), - ERROR_90010006("活动用户不足,无法开启竞拍!"), - ERROR_90010007("旧密码不正确,请确认!"), + ERROR_20010001("试题被删除,无法继续考试!"), // 错误码20010001及其对应的消息 + ERROR_20010002("您有正在进行的考试!"), // 错误码20010002及其对应的消息 + ERROR_90010001("账号不存在,请确认!"), // 错误码90010001及其对应的消息 + ERROR_90010002("账号或密码错误!"), // 错误码90010002及其对应的消息 + ERROR_90010003("至少要包含一个角色!"), // 错误码90010003及其对应的消息 + ERROR_90010004("管理员账号无法修改!"), // 错误码90010004及其对应的消息 + ERROR_90010005("账号被禁用,请联系管理员!"), // 错误码90010005及其对应的消息 + ERROR_90010006("活动用户不足,无法开启竞拍!"), // 错误码90010006及其对应的消息 + ERROR_90010007("旧密码不正确,请确认!"), // 错误码90010007及其对应的消息 - ERROR_60000001("数据不存在!"); + ERROR_60000001("数据不存在!"); // 错误码60000001及其对应的消息 - public String msg; + public String msg; // 定义错误消息字段 /** - * 生成Markdown格式文档,用于更新文档用的 - * @param args + * 生成Markdown格式文档,用于更新文档用的 // 方法注释,说明该方法的用途 + * @param args // 参数说明 */ - public static void main(String[] args) { - for (ApiError e : ApiError.values()) { - System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',"); + public static void main(String[] args) { // 主方法 + for (ApiError e : ApiError.values()) { // 遍历所有ApiError枚举值 + System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',"); // 输出错误码和消息 } } /** - * 获取错误码 - * @return + * 获取错误码 // 方法注释,说明该方法的用途 + * @return // 返回值说明 */ - public Integer getCode(){ - return Integer.parseInt(this.name().replace("ERROR_", "")); + public Integer getCode(){ // 获取错误码的方法 + return Integer.parseInt(this.name().replace("ERROR_", "")); // 返回去掉"ERROR_"前缀的整数值 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/ApiRest.java b/src-源文件/main/java/com/yf/exam/core/api/ApiRest.java index 4785bfb..c10b277 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/ApiRest.java +++ b/src-源文件/main/java/com/yf/exam/core/api/ApiRest.java @@ -1,64 +1,64 @@ -package com.yf.exam.core.api; +package com.yf.exam.core.api; // 定义包名 -import com.yf.exam.core.api.ApiError; -import com.yf.exam.core.exception.ServiceException; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.yf.exam.core.api.ApiError; // 导入ApiError类 +import com.yf.exam.core.exception.ServiceException; // 导入ServiceException类 +import io.swagger.annotations.ApiModel; // 导入ApiModel注解 +import io.swagger.annotations.ApiModelProperty; // 导入ApiModelProperty注解 +import lombok.Data; // 导入Data注解 +import lombok.NoArgsConstructor; // 导入NoArgsConstructor注解 /** * 数据结果返回的封装 * @author bool * @date 2018/11/20 09:48 */ -@Data -@NoArgsConstructor -@ApiModel(value="接口响应", description="接口响应") -public class ApiRest{ +@Data // 自动生成getter、setter、toString等方法 +@NoArgsConstructor // 自动生成无参构造函数 +@ApiModel(value="接口响应", description="接口响应") // Swagger注解,描述API模型 +public class ApiRest{ // 定义泛型类ApiRest /** * 响应消息 */ - @ApiModelProperty(value = "响应消息") - private String msg; + @ApiModelProperty(value = "响应消息") // Swagger注解,描述响应消息属性 + private String msg; // 响应消息 + /** * 响应代码 */ - @ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true) - private Integer code; + @ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true) // Swagger注解,描述响应代码属性 + private Integer code; // 响应代码 /** * 请求或响应body */ - @ApiModelProperty(value = "响应内容") - protected T data; - + @ApiModelProperty(value = "响应内容") // Swagger注解,描述响应内容属性 + protected T data; // 响应内容 /** * 是否成功 * @return */ - public boolean isSuccess(){ - return code.equals(0); + public boolean isSuccess(){ // 判断请求是否成功 + return code.equals(0); // 如果响应代码为0,返回true } /** * 构造函数 * @param error */ - public ApiRest(ServiceException error){ - this.code = error.getCode(); - this.msg = error.getMsg(); + public ApiRest(ServiceException error){ // 构造函数,接收ServiceException对象 + this.code = error.getCode(); // 设置响应代码 + this.msg = error.getMsg(); // 设置响应消息 } /** * 构造函数 * @param error */ - public ApiRest(ApiError error){ - this.code = error.getCode(); - this.msg = error.msg; + public ApiRest(ApiError error){ // 构造函数,接收ApiError对象 + this.code = error.getCode(); // 设置响应代码 + this.msg = error.msg; // 设置响应消息 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/controller/BaseController.java b/src-源文件/main/java/com/yf/exam/core/api/controller/BaseController.java index 22fcf09..66e9fb7 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/controller/BaseController.java +++ b/src-源文件/main/java/com/yf/exam/core/api/controller/BaseController.java @@ -1,154 +1,150 @@ package com.yf.exam.core.api.controller; - -import com.yf.exam.core.api.ApiError; -import com.yf.exam.core.api.ApiRest; -import com.yf.exam.core.exception.ServiceException; +// 导入所需的类 +import com.yf.exam.core.api.ApiError; // 导入ApiError类,用于处理API错误 +import com.yf.exam.core.api.ApiRest; // 导入ApiRest类,用于构建API响应 +import com.yf.exam.core.exception.ServiceException; // 导入ServiceException类,用于处理服务异常 /** * 基础控制器 + * 该类提供了一些通用的方法,用于构建API的成功和失败响应 * @author Dav */ public class BaseController { /** * 成功默认消息 + * CODE_SUCCESS用于表示成功的状态码 */ - private static final Integer CODE_SUCCESS = 0; - private static final String MSG_SUCCESS = "操作成功!"; + private static final Integer CODE_SUCCESS = 0; // 定义成功状态码 + private static final String MSG_SUCCESS = "操作成功!"; // 定义成功消息 /** * 失败默认消息 + * CODE_FAILURE用于表示失败的状态码 */ - private static final Integer CODE_FAILURE = 1; - private static final String MSG_FAILURE = "请求失败!"; + private static final Integer CODE_FAILURE = 1; // 定义失败状态码 + private static final String MSG_FAILURE = "请求失败!"; // 定义失败消息 /** * 完成消息构造 - * @param code - * @param message - * @param data - * @param - * @return + * @param code 状态码 + * @param message 消息内容 + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回构造好的API响应 */ protected ApiRest message(Integer code, String message, T data){ - ApiRest response = new ApiRest<>(); - response.setCode(code); - response.setMsg(message); - if(data!=null) { - response.setData(data); + ApiRest response = new ApiRest<>(); // 创建ApiRest对象 + response.setCode(code); // 设置状态码 + response.setMsg(message); // 设置消息内容 + if(data!=null) { // 如果数据不为空 + response.setData(data); // 设置响应数据 } - return response; + return response; // 返回构造好的响应 } /** * 请求成功空数据 - * @param - * @return + * @param 数据类型 + * @return ApiRest 返回成功的API响应,数据为空 */ protected ApiRest success(){ - return message(0, "请求成功!", null); + return message(0, "请求成功!", null); // 调用message方法构造成功响应 } - - /** * 请求成功,通用代码 - * @param message - * @param data - * @param - * @return + * @param message 消息内容 + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回成功的API响应 */ protected ApiRest success(String message, T data){ - return message(CODE_SUCCESS, message, data); + return message(CODE_SUCCESS, message, data); // 调用message方法构造成功响应 } - /** * 请求成功,仅内容 - * @param data - * @param - * @return + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回成功的API响应 */ protected ApiRest success(T data){ - return message(CODE_SUCCESS, MSG_SUCCESS, data); + return message(CODE_SUCCESS, MSG_SUCCESS, data); // 调用message方法构造成功响应 } - /** * 请求失败,完整构造 - * @param code - * @param message - * @param data - * @param - * @return + * @param code 状态码 + * @param message 消息内容 + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回失败的API响应 */ protected ApiRest failure(Integer code, String message, T data){ - return message(code, message, data); + return message(code, message, data); // 调用message方法构造失败响应 } /** * 请求失败,消息和内容 - * @param message - * @param data - * @param - * @return + * @param message 消息内容 + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回失败的API响应 */ protected ApiRest failure(String message, T data){ - return message(CODE_FAILURE, message, data); + return message(CODE_FAILURE, message, data); // 调用message方法构造失败响应 } /** * 请求失败,消息 - * @param message - * @return + * @param message 消息内容 + * @return ApiRest 返回失败的API响应,数据为空 */ protected ApiRest failure(String message){ - return message(CODE_FAILURE, message, null); + return message(CODE_FAILURE, message, null); // 调用message方法构造失败响应 } /** * 请求失败,仅内容 - * @param data - * @param - * @return + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回失败的API响应 */ protected ApiRest failure(T data){ - return message(CODE_FAILURE, MSG_FAILURE, data); + return message(CODE_FAILURE, MSG_FAILURE, data); // 调用message方法构造失败响应 } - /** * 请求失败,仅内容 - * @param - * @return + * @param 数据类型 + * @return ApiRest 返回失败的API响应,数据为空 */ protected ApiRest failure(){ - return message(CODE_FAILURE, MSG_FAILURE, null); + return message(CODE_FAILURE, MSG_FAILURE, null); // 调用message方法构造失败响应 } - - /** * 请求失败,仅内容 - * @param - * @return + * @param error ApiError对象,包含错误信息 + * @param data 响应数据 + * @param 数据类型 + * @return ApiRest 返回失败的API响应 */ protected ApiRest failure(ApiError error, T data){ - return message(error.getCode(), error.msg, data); + return message(error.getCode(), error.msg, data); // 调用message方法构造失败响应 } - - /** * 请求失败,仅内容 - * @param ex - * @param - * @return + * @param ex ServiceException对象,包含异常信息 + * @param 数据类型 + * @return ApiRest 返回失败的API响应 */ protected ApiRest failure(ServiceException ex){ - ApiRest apiRest = message(ex.getCode(), ex.getMsg(), null); - return apiRest; + ApiRest apiRest = message(ex.getCode(), ex.getMsg(), null); // 调用message方法构造失败响应 + return apiRest; // 返回构造好的响应 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseDTO.java index a2f6a3e..12ae864 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseDTO.java @@ -1,7 +1,10 @@ +// 包声明,定义该类所在的包 package com.yf.exam.core.api.dto; +// 导入lombok库中的@Data注解,用于自动生成getter、setter等方法 import lombok.Data; +// 导入Serializable接口,用于对象序列化 import java.io.Serializable; /** @@ -9,7 +12,11 @@ import java.io.Serializable; * @author dav * @date 2019/3/16 15:56 */ +// 使用@Data注解,自动生成该类的getter、setter等方法 @Data +// 定义一个名为BaseDTO的公共类,实现Serializable接口 public class BaseDTO implements Serializable { + // 该类目前没有任何字段或方法 } + diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java index 074fea3..ef95013 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java @@ -1,28 +1,28 @@ -package com.yf.exam.core.api.dto; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/api/dto/BaseIdReqDTO.java +package com.yf.exam.core.api.dto; // 定义包名,表示该类属于哪个包 -import com.yf.exam.core.api.dto.BaseDTO; -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.core.api.dto.BaseDTO; // 导入BaseDTO类,BaseIdReqDTO类将继承自它 +import com.fasterxml.jackson.annotation.JsonIgnore; // 导入JsonIgnore注解,用于在序列化时忽略某个字段 +import io.swagger.annotations.ApiModel; // 导入ApiModel注解,用于Swagger文档生成 +import io.swagger.annotations.ApiModelProperty; // 导入ApiModelProperty注解,用于Swagger文档生成 +import lombok.Data; // 导入Lombok的Data注解,用于自动生成getter、setter等方法 /** *

* 主键通用请求类,用于根据ID查询 *

* - * @author 聪明笨狗 - * @since 2019-04-20 12:15 + * @author 聪明笨狗 // 类的作者信息 + * @since 2019-04-20 12:15 // 类的创建时间 */ -@Data -@ApiModel(value="主键通用请求类", description="主键通用请求类") -public class BaseIdReqDTO extends BaseDTO { +@Data // 使用Lombok的Data注解,自动生成toString、equals、hashCode、getter和setter方法 +@ApiModel(value="主键通用请求类", description="主键通用请求类") // Swagger文档中显示的模型信息 +public class BaseIdReqDTO extends BaseDTO { // 定义BaseIdReqDTO类,继承自BaseDTO - @ApiModelProperty(value = "主键ID", required=true) - private String id; + @ApiModelProperty(value = "主键ID", required=true) // Swagger文档中显示的属性信息,表示该字段是必需的 + private String id; // 定义主键ID字段 - @JsonIgnore - private String userId; - -} + @JsonIgnore // 在序列化时忽略该字段,不会被JSON输出 + private String userId; // 定义用户ID字段,通常用于内部逻辑,不需要暴露给外部 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdRespDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdRespDTO.java index a9a59e2..761a2be 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdRespDTO.java @@ -1,26 +1,28 @@ package com.yf.exam.core.api.dto; -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +// 导入所需的类 +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于API文档生成 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于API文档生成 +import lombok.AllArgsConstructor; // 导入Lombok注解,用于生成全参构造函数 +import lombok.Data; // 导入Lombok注解,用于自动生成getter、setter等方法 +import lombok.NoArgsConstructor; // 导入Lombok注解,用于生成无参构造函数 /** *

* 主键通用响应类,用于添加后返回内容 + * 该类用于封装主键ID的响应数据,通常在添加操作后返回给客户端。 *

* * @author 聪明笨狗 * @since 2019-04-20 12:15 */ -@Data -@ApiModel(value="主键通用响应类", description="主键通用响应类") -@AllArgsConstructor -@NoArgsConstructor -public class BaseIdRespDTO extends BaseDTO { +@Data // 自动生成getter、setter、toString、equals和hashCode方法 +@ApiModel(value="主键通用响应类", description="主键通用响应类") // Swagger注解,描述该类的用途 +@AllArgsConstructor // 自动生成全参构造函数 +@NoArgsConstructor // 自动生成无参构造函数 +public class BaseIdRespDTO extends BaseDTO { // 继承自BaseDTO类 - @ApiModelProperty(value = "主键ID", required=true) - private String id; -} + @ApiModelProperty(value = "主键ID", required=true) // Swagger注解,描述id属性 + private String id; // 主键ID属性,必填 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdsReqDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdsReqDTO.java index df80c18..a2befd1 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdsReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseIdsReqDTO.java @@ -1,26 +1,26 @@ package com.yf.exam.core.api.dto; -import com.yf.exam.core.api.dto.BaseDTO; -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.yf.exam.core.api.dto.BaseDTO; // 导入基础DTO类 +import com.fasterxml.jackson.annotation.JsonIgnore; // 导入JsonIgnore注解,用于序列化时忽略字段 +import io.swagger.annotations.ApiModel; // 导入ApiModel注解,用于Swagger文档生成 +import io.swagger.annotations.ApiModelProperty; // 导入ApiModelProperty注解,用于Swagger文档生成 +import lombok.Data; // 导入Lombok的Data注解,用于自动生成getter、setter等方法 -import java.util.List; +import java.util.List; // 导入List类,用于定义ID列表 /** * 通用ID列表类操作,用于批量删除、修改状态等 + * 该类用于封装要删除的ID列表和用户ID,便于在API中传递参数 * @author bool * @date 2019-08-01 19:07 */ -@Data -@ApiModel(value="删除参数", description="删除参数") -public class BaseIdsReqDTO extends BaseDTO { +@Data // Lombok注解,自动生成getter、setter、toString等方法 +@ApiModel(value="删除参数", description="删除参数") // Swagger注解,描述该类的用途 +public class BaseIdsReqDTO extends BaseDTO { // 继承自BaseDTO类 + @JsonIgnore // 在序列化时忽略该字段 + private String userId; // 用户ID,通常用于标识请求的用户 - @JsonIgnore - private String userId; - - @ApiModelProperty(value = "要删除的ID列表", required = true) - private List ids; -} + @ApiModelProperty(value = "要删除的ID列表", required = true) // Swagger注解,描述该字段 + private List ids; // 要删除的ID列表,必填项 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java index 15f26cb..4689bd8 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java @@ -1,32 +1,32 @@ -package com.yf.exam.core.api.dto; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/api/dto/BaseStateReqDTO.java +package com.yf.exam.core.api.dto; // 定义包名,表示该类属于com.yf.exam.core.api.dto包 -import com.yf.exam.core.api.dto.BaseDTO; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.yf.exam.core.api.dto.BaseDTO; // 导入BaseDTO类,BaseStateReqDTO类将继承自它 +import io.swagger.annotations.ApiModel; // 导入ApiModel注解,用于Swagger文档生成 +import io.swagger.annotations.ApiModelProperty; // 导入ApiModelProperty注解,用于Swagger文档生成 +import lombok.AllArgsConstructor; // 导入Lombok库的AllArgsConstructor注解,自动生成全参构造函数 +import lombok.Data; // 导入Lombok库的Data注解,自动生成getter、setter、toString等方法 +import lombok.NoArgsConstructor; // 导入Lombok库的NoArgsConstructor注解,自动生成无参构造函数 -import java.util.List; +import java.util.List; // 导入List类,用于定义ID列表 /** *

* 通用状态请求类,用于修改状态什么的 *

* - * @author 聪明笨狗 - * @since 2019-04-20 12:15 + * @author 聪明笨狗 // 类的作者 + * @since 2019-04-20 12:15 // 类的创建时间 */ -@Data -@ApiModel(value="通用状态请求类", description="通用状态请求类") -@AllArgsConstructor -@NoArgsConstructor -public class BaseStateReqDTO extends BaseDTO { +@Data // 自动生成getter、setter、toString等方法 +@ApiModel(value="通用状态请求类", description="通用状态请求类") // Swagger文档中类的描述 +@AllArgsConstructor // 自动生成全参构造函数 +@NoArgsConstructor // 自动生成无参构造函数 +public class BaseStateReqDTO extends BaseDTO { // 定义BaseStateReqDTO类,继承自BaseDTO + @ApiModelProperty(value = "要修改对象的ID列表", required=true) // Swagger文档中属性的描述,表示该属性为必填项 + private List ids; // 定义一个ID列表,用于存储要修改对象的ID - @ApiModelProperty(value = "要修改对象的ID列表", required=true) - private List ids; - - @ApiModelProperty(value = "通用状态,0为正常,1为禁用", required=true) - private Integer state; -} + @ApiModelProperty(value = "通用状态,0为正常,1为禁用", required=true) // Swagger文档中属性的描述,表示该属性为必填项 + private Integer state; // 定义一个状态字段,0表示正常,1表示禁用 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/PagingReqDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/PagingReqDTO.java index 276a0e0..1f96377 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/PagingReqDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/PagingReqDTO.java @@ -1,47 +1,44 @@ -package com.yf.exam.core.api.dto; +package com.yf.exam.core.api.dto; // 定义包名 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.fasterxml.jackson.annotation.JsonIgnore; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入MyBatis分页类 +import com.fasterxml.jackson.annotation.JsonIgnore; // 导入Jackson注解,用于忽略字段 +import io.swagger.annotations.ApiModel; // 导入Swagger注解,用于API文档 +import io.swagger.annotations.ApiModelProperty; // 导入Swagger注解,用于API文档属性 +import lombok.Data; // 导入Lombok注解,用于自动生成getter和setter /** * 分页查询类 - * @param + * @param 泛型类型 * @author bool */ -@ApiModel(value="分页参数", description="分页参数") -@Data -public class PagingReqDTO { +@ApiModel(value="分页参数", description="分页参数") // Swagger模型注解 +@Data // Lombok注解,自动生成getter、setter、toString等方法 +public class PagingReqDTO { // 定义分页请求DTO类,使用泛型T + @ApiModelProperty(value = "当前页码", required = true, example = "1") // Swagger属性注解 + private Integer current; // 当前页码 - @ApiModelProperty(value = "当前页码", required = true, example = "1") - private Integer current; + @ApiModelProperty(value = "每页数量", required = true, example = "10") // Swagger属性注解 + private Integer size; // 每页数量 - @ApiModelProperty(value = "每页数量", required = true, example = "10") - private Integer size; + @ApiModelProperty(value = "查询参数") // Swagger属性注解 + private T params; // 查询参数,类型为泛型T - @ApiModelProperty(value = "查询参数") - private T params; + @ApiModelProperty(value = "排序字符") // Swagger属性注解 + private String orderBy; // 排序字段 - @ApiModelProperty(value = "排序字符") - private String orderBy; - - @JsonIgnore - @ApiModelProperty(value = "当前用户的ID") - private String userId; + @JsonIgnore // Jackson注解,忽略该字段 + @ApiModelProperty(value = "当前用户的ID") // Swagger属性注解 + private String userId; // 当前用户的ID /** * 转换成MyBatis的简单分页对象 - * @return + * @return 返回MyBatis的Page对象 */ - public Page toPage(){ - Page page = new Page(); - page.setCurrent(this.current); - page.setSize(this.size); - return page; + public Page toPage(){ // 定义转换方法 + Page page = new Page(); // 创建Page对象 + page.setCurrent(this.current); // 设置当前页码 + page.setSize(this.size); // 设置每页数量 + return page; // 返回Page对象 } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/dto/PagingRespDTO.java b/src-源文件/main/java/com/yf/exam/core/api/dto/PagingRespDTO.java index 3b2a8f7..c405a4a 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/dto/PagingRespDTO.java +++ b/src-源文件/main/java/com/yf/exam/core/api/dto/PagingRespDTO.java @@ -1,30 +1,30 @@ -package com.yf.exam.core.api.dto; +package com.yf.exam.core.api.dto; // 定义包名 -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; // 导入分页类 /** * 分页响应类 * @author bool * @date 2019-07-20 15:17 - * @param + * @param 泛型参数 */ -public class PagingRespDTO extends Page { +public class PagingRespDTO extends Page { // 定义分页响应类,继承自Page类 /** * 获取页面总数量 - * @return + * @return 返回页面总数量 */ @Override - public long getPages() { - if (this.getSize() == 0L) { - return 0L; - } else { - long pages = this.getTotal() / this.getSize(); - if (this.getTotal() % this.getSize() != 0L) { - ++pages; + public long getPages() { // 重写getPages方法 + if (this.getSize() == 0L) { // 如果每页大小为0 + return 0L; // 返回0 + } else { // 否则 + long pages = this.getTotal() / this.getSize(); // 计算总页数 + if (this.getTotal() % this.getSize() != 0L) { // 如果总数不能被每页大小整除 + ++pages; // 页数加1 } - return pages; + return pages; // 返回总页数 } } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/api/utils/JsonConverter.java b/src-源文件/main/java/com/yf/exam/core/api/utils/JsonConverter.java index f9e4622..122619a 100644 --- a/src-源文件/main/java/com/yf/exam/core/api/utils/JsonConverter.java +++ b/src-源文件/main/java/com/yf/exam/core/api/utils/JsonConverter.java @@ -1,48 +1,48 @@ -package com.yf.exam.core.api.utils; +package com.yf.exam.core.api.utils; // 定义包名 -import com.alibaba.fastjson.serializer.SerializerFeature; -import com.alibaba.fastjson.support.config.FastJsonConfig; -import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; -import org.springframework.http.MediaType; -import org.springframework.http.converter.HttpMessageConverter; +import com.alibaba.fastjson.serializer.SerializerFeature; // 导入FastJson序列化特性 +import com.alibaba.fastjson.support.config.FastJsonConfig; // 导入FastJson配置类 +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; // 导入FastJson消息转换器 +import org.springframework.http.MediaType; // 导入媒体类型类 +import org.springframework.http.converter.HttpMessageConverter; // 导入HTTP消息转换器接口 -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.List; +import java.nio.charset.Charset; // 导入字符集类 +import java.util.ArrayList; // 导入ArrayList类 +import java.util.List; // 导入List接口 /** * JSON数据转换器,用于转换返回消息的格式 * @author dav * @date 2018/9/11 19:30 */ -public class JsonConverter { +public class JsonConverter { // 定义JsonConverter类 /** * FastJson消息转换器 * - * @return + * @return 返回HttpMessageConverter对象 */ - public static HttpMessageConverter fastConverter() { + public static HttpMessageConverter fastConverter() { // 定义静态方法fastConverter // 定义一个convert转换消息的对象 - FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); // 创建FastJson消息转换器实例 // 添加FastJson的配置信息 - FastJsonConfig fastJsonConfig = new FastJsonConfig(); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); // 创建FastJson配置实例 // 默认转换器 - fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, - SerializerFeature.WriteNullNumberAsZero, - SerializerFeature.MapSortField, - SerializerFeature.WriteNullStringAsEmpty, - SerializerFeature.DisableCircularReferenceDetect, - SerializerFeature.WriteDateUseDateFormat, - SerializerFeature.WriteNullListAsEmpty); - fastJsonConfig.setCharset(Charset.forName("UTF-8")); + fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, // 设置序列化特性:格式化输出 + SerializerFeature.WriteNullNumberAsZero, // 将null数字写为0 + SerializerFeature.MapSortField, // 对Map进行排序 + SerializerFeature.WriteNullStringAsEmpty, // 将null字符串写为空 + SerializerFeature.DisableCircularReferenceDetect, // 禁用循环引用检测 + SerializerFeature.WriteDateUseDateFormat, // 使用日期格式化 + SerializerFeature.WriteNullListAsEmpty); // 将null列表写为空列表 + fastJsonConfig.setCharset(Charset.forName("UTF-8")); // 设置字符集为UTF-8 // 处理中文乱码问题 - List fastMediaTypes = new ArrayList<>(); - fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); - fastConverter.setSupportedMediaTypes(fastMediaTypes); + List fastMediaTypes = new ArrayList<>(); // 创建媒体类型列表 + fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); // 添加支持的媒体类型:UTF-8 JSON + fastConverter.setSupportedMediaTypes(fastMediaTypes); // 设置支持的媒体类型 // 在convert中添加配置信息 - fastConverter.setFastJsonConfig(fastJsonConfig); + fastConverter.setFastJsonConfig(fastJsonConfig); // 设置FastJson配置 - return fastConverter; - } -} + return fastConverter; // 返回FastJson消息转换器 + } // 结束fastConverter方法 +} // 结束JsonConverter类 \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/enums/CommonState.java b/src-源文件/main/java/com/yf/exam/core/enums/CommonState.java index 21ef637..56fa93d 100644 --- a/src-源文件/main/java/com/yf/exam/core/enums/CommonState.java +++ b/src-源文件/main/java/com/yf/exam/core/enums/CommonState.java @@ -1,19 +1,21 @@ -package com.yf.exam.core.enums; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/enums/CommonState.java +package com.yf.exam.core.enums; // 定义包名 /** * 通用的状态枚举信息 * - * @author bool - * @date 2019-09-17 17:57 + * @author bool // 作者信息 + * @date 2019-09-17 17:57 // 日期信息 */ -public interface CommonState { +public interface CommonState { // 定义一个公共接口 /** * 普通状态,正常的 */ - Integer NORMAL = 0; + Integer NORMAL = 0; // 定义正常状态的常量,值为0 + /** * 非正常状态,禁用,下架等 */ - Integer ABNORMAL = 1; -} + Integer ABNORMAL = 1; // 定义非正常状态的常量,值为1 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/enums/OpenType.java b/src-源文件/main/java/com/yf/exam/core/enums/OpenType.java index 0012db5..f1b4495 100644 --- a/src-源文件/main/java/com/yf/exam/core/enums/OpenType.java +++ b/src-源文件/main/java/com/yf/exam/core/enums/OpenType.java @@ -1,18 +1,19 @@ -package com.yf.exam.core.enums; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/enums/OpenType.java +package com.yf.exam.core.enums; // 定义包名 /** * 开放方式 * @author bool */ -public interface OpenType { +public interface OpenType { // 定义接口 OpenType /** * 完全开放 */ - Integer OPEN = 1; + Integer OPEN = 1; // 定义常量 OPEN,值为 1 /** * 部门开放 */ - Integer DEPT_OPEN = 2; -} + Integer DEPT_OPEN = 2; // 定义常量 DEPT_OPEN,值为 2 +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/exception/ServiceException.java b/src-源文件/main/java/com/yf/exam/core/exception/ServiceException.java index 2d474c1..a87d044 100644 --- a/src-源文件/main/java/com/yf/exam/core/exception/ServiceException.java +++ b/src-源文件/main/java/com/yf/exam/core/exception/ServiceException.java @@ -1,51 +1,52 @@ -package com.yf.exam.core.exception; +// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/exception/ServiceException.java +package com.yf.exam.core.exception; // 定义包名 -import com.yf.exam.core.api.ApiError; -import com.yf.exam.core.api.ApiRest; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import com.yf.exam.core.api.ApiError; // 导入ApiError类 +import com.yf.exam.core.api.ApiRest; // 导入ApiRest类 +import lombok.AllArgsConstructor; // 导入AllArgsConstructor注解 +import lombok.Data; // 导入Data注解 +import lombok.NoArgsConstructor; // 导入NoArgsConstructor注解 -@Data -@AllArgsConstructor -@NoArgsConstructor -public class ServiceException extends RuntimeException{ +@Data // 自动生成getter、setter、toString等方法 +@AllArgsConstructor // 生成包含所有字段的构造函数 +@NoArgsConstructor // 生成无参构造函数 +public class ServiceException extends RuntimeException{ // 定义ServiceException类,继承RuntimeException /** * 错误码 */ - private Integer code; + private Integer code; // 定义错误码字段 /** * 错误消息 */ - private String msg; + private String msg; // 定义错误消息字段 /** * 从结果初始化 * @param apiRest */ - public ServiceException(ApiRest apiRest){ - this.code = apiRest.getCode(); - this.msg = apiRest.getMsg(); + public ServiceException(ApiRest apiRest){ // 构造函数,接受ApiRest对象 + this.code = apiRest.getCode(); // 初始化错误码 + this.msg = apiRest.getMsg(); // 初始化错误消息 } /** * 从枚举中获取参数 * @param apiError */ - public ServiceException(ApiError apiError){ - this.code = apiError.getCode(); - this.msg = apiError.msg; + public ServiceException(ApiError apiError){ // 构造函数,接受ApiError对象 + this.code = apiError.getCode(); // 初始化错误码 + this.msg = apiError.msg; // 初始化错误消息 } /** * 异常构造 * @param msg */ - public ServiceException(String msg){ - this.code = 1; - this.msg = msg; + public ServiceException(String msg){ // 构造函数,接受错误消息 + this.code = 1; // 默认错误码为1 + this.msg = msg; // 初始化错误消息 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/exception/ServiceExceptionHandler.java b/src-源文件/main/java/com/yf/exam/core/exception/ServiceExceptionHandler.java index 1c8de5d..0e4954d 100644 --- a/src-源文件/main/java/com/yf/exam/core/exception/ServiceExceptionHandler.java +++ b/src-源文件/main/java/com/yf/exam/core/exception/ServiceExceptionHandler.java @@ -1,46 +1,46 @@ -package com.yf.exam.core.exception; +package com.yf.exam.core.exception; // 定义包名 -import com.yf.exam.core.api.ApiRest; -import org.springframework.http.HttpStatus; -import org.springframework.ui.Model; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; +import com.yf.exam.core.api.ApiRest; // 导入ApiRest类 +import org.springframework.http.HttpStatus; // 导入HttpStatus类 +import org.springframework.ui.Model; // 导入Model类 +import org.springframework.web.bind.WebDataBinder; // 导入WebDataBinder类 +import org.springframework.web.bind.annotation.*; // 导入所有注解 /** * 统一异常处理类 * @author bool * @date 2019-06-21 19:27 */ -@RestControllerAdvice -public class ServiceExceptionHandler { +@RestControllerAdvice // 声明这是一个全局异常处理类 +public class ServiceExceptionHandler { // 定义ServiceExceptionHandler类 /** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 - * @param binder + * @param binder 数据绑定器 */ - @InitBinder - public void initWebBinder(WebDataBinder binder){ - + @InitBinder // 初始化数据绑定器 + public void initWebBinder(WebDataBinder binder){ // 定义初始化方法 + // 这里可以添加自定义的初始化逻辑 } /** * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 - * @param model + * @param model 模型对象 */ - @ModelAttribute - public void addAttribute(Model model) { - + @ModelAttribute // 将方法的返回值绑定到模型中 + public void addAttribute(Model model) { // 定义添加属性的方法 + // 这里可以添加需要绑定到模型的属性 } /** * 捕获ServiceException - * @param e - * @return + * @param e 捕获的异常 + * @return ApiRest 返回的API响应 */ - @ExceptionHandler({com.yf.exam.core.exception.ServiceException.class}) - @ResponseStatus(HttpStatus.OK) - public ApiRest serviceExceptionHandler(ServiceException e) { - return new ApiRest(e); + @ExceptionHandler({com.yf.exam.core.exception.ServiceException.class}) // 指定捕获的异常类型 + @ResponseStatus(HttpStatus.OK) // 设置响应状态为200 OK + public ApiRest serviceExceptionHandler(ServiceException e) { // 定义异常处理方法 + return new ApiRest(e); // 返回ApiRest对象,包含异常信息 } } \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/BeanMapper.java b/src-源文件/main/java/com/yf/exam/core/utils/BeanMapper.java index 8ee5ca4..c1e5da2 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/BeanMapper.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/BeanMapper.java @@ -1,13 +1,12 @@ -package com.yf.exam.core.utils; +package com.yf.exam.core.utils; // 定义包名 -import org.dozer.DozerBeanMapper; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.function.Function; -import java.util.stream.Collectors; +import org.dozer.DozerBeanMapper; // 导入DozerBeanMapper类 +import java.util.ArrayList; // 导入ArrayList类 +import java.util.Collection; // 导入Collection接口 +import java.util.List; // 导入List接口 +import java.util.function.Function; // 导入Function接口 +import java.util.stream.Collectors; // 导入Collectors类 /** * 简单封装Dozer, 实现深度转换Bean<->Bean的Mapper.实现: @@ -18,42 +17,42 @@ import java.util.stream.Collectors; * 4. 区分创建新的B对象与将对象A值复制到已存在的B对象两种函数. * */ -public class BeanMapper { +public class BeanMapper { // 定义BeanMapper类 /** * 持有Dozer单例, 避免重复创建DozerMapper消耗资源. */ - private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); + private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); // 创建DozerBeanMapper的单例 /** * 基于Dozer转换对象的类型. */ - public static T map(Object source, Class destinationClass) { - return dozerBeanMapper.map(source, destinationClass); + public static T map(Object source, Class destinationClass) { // 定义map方法,转换对象类型 + return dozerBeanMapper.map(source, destinationClass); // 使用Dozer进行对象转换 } /** * 基于Dozer转换Collection中对象的类型. */ - public static List mapList(Iterable sourceList, Class destinationClass) { - List destinationList = new ArrayList(); - for (Object sourceObject : sourceList) { - T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass); - destinationList.add(destinationObject); + public static List mapList(Iterable sourceList, Class destinationClass) { // 定义mapList方法,转换集合中的对象 + List destinationList = new ArrayList(); // 创建目标列表 + for (Object sourceObject : sourceList) { // 遍历源列表中的每个对象 + T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass); // 转换对象 + destinationList.add(destinationObject); // 将转换后的对象添加到目标列表 } - return destinationList; + return destinationList; // 返回目标列表 } /** * 基于Dozer将对象A的值拷贝到对象B中. */ - public static void copy(Object source, Object destinationObject) { - if(source!=null) { - dozerBeanMapper.map(source, destinationObject); + public static void copy(Object source, Object destinationObject) { // 定义copy方法,拷贝对象A的值到对象B + if(source!=null) { // 检查源对象是否为null + dozerBeanMapper.map(source, destinationObject); // 使用Dozer进行值拷贝 } } - public static List mapList(Collection source, Function mapper) { - return source.stream().map(mapper).collect(Collectors.toList()); + public static List mapList(Collection source, Function mapper) { // 定义重载的mapList方法,使用自定义映射函数 + return source.stream().map(mapper).collect(Collectors.toList()); // 使用流和映射函数转换集合并返回列表 } } \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/CronUtils.java b/src-源文件/main/java/com/yf/exam/core/utils/CronUtils.java index c019b3e..9e770d1 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/CronUtils.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/CronUtils.java @@ -1,31 +1,32 @@ -package com.yf.exam.core.utils; +language:yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/utils/CronUtils.java +package com.yf.exam.core.utils; // 包声明,定义了类的包路径 -import java.text.SimpleDateFormat; -import java.util.Date; +import java.text.SimpleDateFormat; // 导入用于格式化日期的类 +import java.util.Date; // 导入日期类 /** * 时间转换quartz表达式 - * @author bool - * @date 2020/11/29 下午3:00 + * @author bool // 作者信息 + * @date 2020/11/29 下午3:00 // 日期信息 */ -public class CronUtils { +public class CronUtils { // 定义CronUtils类 /** * 格式化数据 */ - private static final String DATE_FORMAT = "ss mm HH dd MM ? yyyy"; + private static final String DATE_FORMAT = "ss mm HH dd MM ? yyyy"; // 定义日期格式的常量 /** * 准确的时间点到表达式 - * @param date - * @return + * @param date // 输入的日期 + * @return // 返回格式化后的cron表达式 */ - public static String dateToCron(final Date date){ - SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT); - String formatTimeStr = ""; - if (date != null) { - formatTimeStr = fmt.format(date); + public static String dateToCron(final Date date){ // 定义静态方法,将日期转换为cron表达式 + SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT); // 创建SimpleDateFormat对象 + String formatTimeStr = ""; // 初始化格式化后的时间字符串 + if (date != null) { // 检查日期是否为null + formatTimeStr = fmt.format(date); // 格式化日期 } - return formatTimeStr; + return formatTimeStr; // 返回格式化后的字符串 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/DateUtils.java b/src-源文件/main/java/com/yf/exam/core/utils/DateUtils.java index 4121ef5..6932d2f 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/DateUtils.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/DateUtils.java @@ -1,9 +1,9 @@ -package com.yf.exam.core.utils; +package com.yf.exam.core.utils; // 包声明,定义该类所在的包 -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; +import java.text.SimpleDateFormat; // 导入用于日期格式化的类 +import java.util.Calendar; // 导入日历类 +import java.util.Date; // 导入日期类 +import java.util.GregorianCalendar; // 导入公历日历类 /** * 日期处理工具类 @@ -13,27 +13,27 @@ import java.util.GregorianCalendar; * @author Bool * @version */ -public class DateUtils { +public class DateUtils { // 定义DateUtils类 /** * * calcExpDays:计算某个日期与当前日期相差的天数,如果计算的日期大于现在时间,将返回负数;否则返回正数
* @author Bool - * @param userCreateTime - * @return + * @param userCreateTime 用户创建时间 + * @return 相差的天数 * @since JDK 1.6 */ - public static int calcExpDays(Date userCreateTime){ + public static int calcExpDays(Date userCreateTime){ // 计算日期差异的方法 - Calendar start = Calendar.getInstance(); - start.setTime(userCreateTime); + Calendar start = Calendar.getInstance(); // 获取当前日历实例 + start.setTime(userCreateTime); // 设置开始时间为用户创建时间 - Calendar now = Calendar.getInstance(); - now.setTime(new Date()); + Calendar now = Calendar.getInstance(); // 获取当前日历实例 + now.setTime(new Date()); // 设置当前时间 - long l = now.getTimeInMillis() - start.getTimeInMillis(); - int days = new Long(l / (1000 * 60 * 60 * 24)).intValue(); - return days; + long l = now.getTimeInMillis() - start.getTimeInMillis(); // 计算时间差(毫秒) + int days = new Long(l / (1000 * 60 * 60 * 24)).intValue(); // 将毫秒转换为天数 + return days; // 返回天数 } @@ -42,36 +42,34 @@ public class DateUtils { * dateNow:获取当前时间的字符串格式,根据传入的格式化来展示.
* @author Bool * @param format 日期格式化 - * @return + * @return 当前时间的字符串 */ - public static String dateNow(String format) { - SimpleDateFormat fmt = new SimpleDateFormat(format); - Calendar c = new GregorianCalendar(); - return fmt.format(c.getTime()); + public static String dateNow(String format) { // 获取当前时间字符串的方法 + SimpleDateFormat fmt = new SimpleDateFormat(format); // 创建日期格式化对象 + Calendar c = new GregorianCalendar(); // 获取公历日历实例 + return fmt.format(c.getTime()); // 返回格式化后的当前时间字符串 } /** * formatDate:格式化日期,返回指定的格式
* @author Bool - * @param time - * @param format - * @return + * @param time 日期对象 + * @param format 日期格式 + * @return 格式化后的日期字符串 */ - public static String formatDate(Date time, String format) { - SimpleDateFormat fmt = new SimpleDateFormat(format); - return fmt.format(time.getTime()); + public static String formatDate(Date time, String format) { // 格式化日期的方法 + SimpleDateFormat fmt = new SimpleDateFormat(format); // 创建日期格式化对象 + return fmt.format(time.getTime()); // 返回格式化后的日期字符串 } - - /** * parseDate:将字符串转换成日期,使用:yyyy-MM-dd HH:mm:ss 来格式化 * @author Bool - * @param date - * @return + * @param date 日期字符串 + * @return 转换后的日期对象 */ - public static Date parseDate(String date) { - return parseDate(date, "yyyy-MM-dd HH:mm:ss"); + public static Date parseDate(String date) { // 将字符串解析为日期的方法 + return parseDate(date, "yyyy-MM-dd HH:mm:ss"); // 使用默认格式解析 } @@ -79,25 +77,23 @@ public class DateUtils { * * parseDate:将字符串转换成日期,使用指定格式化来格式化 * @author Bool - * @param date - * @param pattern - * @return + * @param date 日期字符串 + * @param pattern 日期格式 + * @return 转换后的日期对象 */ - public static Date parseDate(String date, String pattern) { + public static Date parseDate(String date, String pattern) { // 使用指定格式解析字符串为日期 - if (pattern==null) { - pattern = "yyyy-MM-dd HH:mm:ss"; + if (pattern==null) { // 如果未指定格式 + pattern = "yyyy-MM-dd HH:mm:ss"; // 使用默认格式 } - SimpleDateFormat fmt = new SimpleDateFormat(pattern); + SimpleDateFormat fmt = new SimpleDateFormat(pattern); // 创建日期格式化对象 try { - - return fmt.parse(date); - } catch (Exception ex) { - ex.printStackTrace(); + return fmt.parse(date); // 尝试解析日期字符串 + } catch (Exception ex) { // 捕获异常 + ex.printStackTrace(); // 打印异常堆栈 } - return null; - + return null; // 返回null表示解析失败 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/IpUtils.java b/src-源文件/main/java/com/yf/exam/core/utils/IpUtils.java index 91277d7..e88b23f 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/IpUtils.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/IpUtils.java @@ -1,7 +1,6 @@ -package com.yf.exam.core.utils; +package com.yf.exam.core.utils; // 定义包名 - -import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequest; // 导入HttpServletRequest类 /** * IP获取工具类,用户获取网络请求过来的真实IP @@ -11,55 +10,52 @@ import javax.servlet.http.HttpServletRequest; * @author Bool * @version */ -public class IpUtils { +public class IpUtils { // 定义IpUtils类 - /** * * getClientIp:通过请求获取客户端的真实IP地址 * @author Bool - * @param request - * @return + * @param request HttpServletRequest对象 + * @return 返回客户端的真实IP地址 */ - public static String extractClientIp(HttpServletRequest request) { + public static String extractClientIp(HttpServletRequest request) { // 定义静态方法extractClientIp,接收HttpServletRequest参数 - String ip = null; + String ip = null; // 初始化ip变量为null //X-Forwarded-For:Squid 服务代理 - String ipAddresses = request.getHeader("X-Forwarded-For"); + String ipAddresses = request.getHeader("X-Forwarded-For"); // 获取请求头中的X-Forwarded-For字段 - if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知 //Proxy-Client-IP:apache 服务代理 - ipAddresses = request.getHeader("Proxy-Client-IP"); + ipAddresses = request.getHeader("Proxy-Client-IP"); // 获取Proxy-Client-IP字段 } - if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知 //WL-Proxy-Client-IP:weblogic 服务代理 - ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); // 获取WL-Proxy-Client-IP字段 } - if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知 //HTTP_CLIENT_IP:有些代理服务器 - ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); // 获取HTTP_CLIENT_IP字段 } - if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { + if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知 //X-Real-IP:nginx服务代理 - ipAddresses = request.getHeader("X-Real-IP"); + ipAddresses = request.getHeader("X-Real-IP"); // 获取X-Real-IP字段 } //有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP - if (ipAddresses != null && ipAddresses.length() != 0) { - ip = ipAddresses.split(",")[0]; + if (ipAddresses != null && ipAddresses.length() != 0) { // 检查ipAddresses是否不为空 + ip = ipAddresses.split(",")[0]; // 通过逗号分割并获取第一个IP地址 } //还是不能获取到,最后再通过request.getRemoteAddr();获取 - if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { - ip = request.getRemoteAddr(); + if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ip是否为空或未知 + ip = request.getRemoteAddr(); // 最后通过getRemoteAddr获取IP地址 } - return ip; + return ip; // 返回获取到的IP地址 } - - -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/Reflections.java b/src-源文件/main/java/com/yf/exam/core/utils/Reflections.java index 4d50bf2..a735b46 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/Reflections.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/Reflections.java @@ -1,22 +1,22 @@ /** * Copyright (c) 2005-2012 springside.org.cn */ -package com.yf.exam.core.utils; - -import lombok.extern.log4j.Log4j2; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.Validate; -import org.springframework.util.Assert; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +package com.yf.exam.core.utils; // 定义包名 + +import lombok.extern.log4j.Log4j2; // 引入Log4j2日志库 +import org.apache.commons.lang3.StringUtils; // 引入Apache Commons Lang的StringUtils类 +import org.apache.commons.lang3.Validate; // 引入Apache Commons Lang的Validate类 +import org.springframework.util.Assert; // 引入Spring的Assert类 + +import java.lang.reflect.Field; // 引入反射中的Field类 +import java.lang.reflect.InvocationTargetException; // 引入反射中的InvocationTargetException类 +import java.lang.reflect.Method; // 引入反射中的Method类 +import java.lang.reflect.Modifier; // 引入反射中的Modifier类 +import java.lang.reflect.ParameterizedType; // 引入反射中的ParameterizedType类 +import java.lang.reflect.Type; // 引入反射中的Type类 +import java.util.ArrayList; // 引入ArrayList类 +import java.util.Arrays; // 引入Arrays类 +import java.util.List; // 引入List接口 /** * 反射工具类. @@ -24,32 +24,32 @@ import java.util.List; * @author calvin * @version 2016-01-15 */ -@Log4j2 -public class Reflections { +@Log4j2 // 使用Log4j2注解 +public class Reflections { // 定义Reflections类 - private static final String SETTER_PREFIX = "set"; + private static final String SETTER_PREFIX = "set"; // 定义setter方法前缀 - private static final String GETTER_PREFIX = "get"; + private static final String GETTER_PREFIX = "get"; // 定义getter方法前缀 - private static final String CGLIB_CLASS_SEPARATOR = "$$"; + private static final String CGLIB_CLASS_SEPARATOR = "$$"; // 定义CGLIB类分隔符 /** * 获取类的所有属性,包括父类 * - * @param object - * @return + * @param object 目标对象 + * @return 所有属性的数组 */ - public static Field[] getAllFields(Object object) { - Class clazz = object.getClass(); - List fieldList = new ArrayList<>(); - while (clazz != null) { - fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); - clazz = clazz.getSuperclass(); + public static Field[] getAllFields(Object object) { // 定义获取所有字段的方法 + Class clazz = object.getClass(); // 获取对象的类 + List fieldList = new ArrayList<>(); // 创建字段列表 + while (clazz != null) { // 循环直到没有父类 + fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()))); // 添加当前类的字段 + clazz = clazz.getSuperclass(); // 获取父类 } - Field[] fields = new Field[fieldList.size()]; - fieldList.toArray(fields); - return fields; + Field[] fields = new Field[fieldList.size()]; // 创建字段数组 + fieldList.toArray(fields); // 将列表转换为数组 + return fields; // 返回字段数组 } @@ -57,29 +57,29 @@ public class Reflections { * 调用Getter方法. * 支持多级,如:对象名.对象名.方法 */ - public static Object invokeGetter(Object obj, String propertyName) { - Object object = obj; - for (String name : StringUtils.split(propertyName, ".")){ - String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); - object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); + public static Object invokeGetter(Object obj, String propertyName) { // 定义调用getter方法 + Object object = obj; // 初始化对象 + for (String name : StringUtils.split(propertyName, ".")){ // 分割属性名 + String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name); // 生成getter方法名 + object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); // 调用getter方法 } - return object; + return object; // 返回结果 } /** * 调用Setter方法, 仅匹配方法名。 * 支持多级,如:对象名.对象名.方法 */ - public static void invokeSetter(Object obj, String propertyName, Object value) { - Object object = obj; - String[] names = StringUtils.split(propertyName, "."); - for (int i=0; i[] parameterTypes, - final Object[] args) { - Method method = getAccessibleMethod(obj, methodName, parameterTypes); - if (method == null) { - throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + final Object[] args) { // 定义调用方法的方法 + Method method = getAccessibleMethod(obj, methodName, parameterTypes); // 获取可访问的方法 + if (method == null) { // 如果方法不存在 + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); // 抛出异常 } try { - return method.invoke(obj, args); - } catch (Exception e) { - throw convertReflectionExceptionToUnchecked(e); + return method.invoke(obj, args); // 调用方法并返回结果 + } catch (Exception e) { // 捕获异常 + throw convertReflectionExceptionToUnchecked(e); // 转换异常 } } @@ -144,16 +144,16 @@ public class Reflections { * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用. * 只匹配函数名,如果有多个同名函数调用第一个。 */ - public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { - Method method = getAccessibleMethodByName(obj, methodName); - if (method == null) { - throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); + public static Object invokeMethodByName(final Object obj, final String methodName, final Object[] args) { // 定义通过方法名调用方法 + Method method = getAccessibleMethodByName(obj, methodName); // 获取可访问的方法 + if (method == null) { // 如果方法不存在 + throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + obj + "]"); // 抛出异常 } try { - return method.invoke(obj, args); - } catch (Exception e) { - throw convertReflectionExceptionToUnchecked(e); + return method.invoke(obj, args); // 调用方法并返回结果 + } catch (Exception e) { // 捕获异常 + throw convertReflectionExceptionToUnchecked(e); // 转换异常 } } @@ -162,20 +162,20 @@ public class Reflections { * * 如向上转型到Object仍无法找到, 返回null. */ - public static Field getAccessibleField(final Object obj, final String fieldName) { - Validate.notNull(obj, "object can't be null"); - Validate.notBlank(fieldName, "fieldName can't be blank"); - for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { + public static Field getAccessibleField(final Object obj, final String fieldName) { // 定义获取可访问字段的方法 + Validate.notNull(obj, "object can't be null"); // 验证对象不为空 + Validate.notBlank(fieldName, "fieldName can't be blank"); // 验证字段名不为空 + for (Class superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) { // 循环向上转型 try { - Field field = superClass.getDeclaredField(fieldName); - makeAccessible(field); - return field; - } catch (NoSuchFieldException e) {//NOSONAR + Field field = superClass.getDeclaredField(fieldName); // 获取声明的字段 + makeAccessible(field); // 设置字段为可访问 + return field; // 返回字段 + } catch (NoSuchFieldException e) { // 捕获没有该字段的异常 // Field不在当前类定义,继续向上转型 - continue;// new add + continue; // 继续循环 } } - return null; + return null; // 返回null } /** @@ -186,21 +186,21 @@ public class Reflections { * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ public static Method getAccessibleMethod(final Object obj, final String methodName, - final Class... parameterTypes) { - Validate.notNull(obj, "object can't be null"); - Validate.notBlank(methodName, "methodName can't be blank"); + final Class... parameterTypes) { // 定义获取可访问方法的方法 + Validate.notNull(obj, "object can't be null"); // 验证对象不为空 + Validate.notBlank(methodName, "methodName can't be blank"); // 验证方法名不为空 - for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { // 循环向上转型 try { - Method method = searchType.getDeclaredMethod(methodName, parameterTypes); - makeAccessible(method); - return method; - } catch (NoSuchMethodException e) { + Method method = searchType.getDeclaredMethod(methodName, parameterTypes); // 获取声明的方法 + makeAccessible(method); // 设置方法为可访问 + return method; // 返回方法 + } catch (NoSuchMethodException e) { // 捕获没有该方法的异常 // Method不在当前类定义,继续向上转型 - continue;// new add + continue; // 继续循环 } } - return null; + return null; // 返回null } /** @@ -210,39 +210,39 @@ public class Reflections { * * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args) */ - public static Method getAccessibleMethodByName(final Object obj, final String methodName) { - Validate.notNull(obj, "object can't be null"); - Validate.notBlank(methodName, "methodName can't be blank"); - - for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { - Method[] methods = searchType.getDeclaredMethods(); - for (Method method : methods) { - if (method.getName().equals(methodName)) { - makeAccessible(method); - return method; + public static Method getAccessibleMethodByName(final Object obj, final String methodName) { // 定义通过方法名获取可访问方法的方法 + Validate.notNull(obj, "object can't be null"); // 验证对象不为空 + Validate.notBlank(methodName, "methodName can't be blank"); // 验证方法名不为空 + + for (Class searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass()) { // 循环向上转型 + Method[] methods = searchType.getDeclaredMethods(); // 获取声明的方法数组 + for (Method method : methods) { // 遍历方法 + if (method.getName().equals(methodName)) { // 如果方法名匹配 + makeAccessible(method); // 设置方法为可访问 + return method; // 返回方法 } } } - return null; + return null; // 返回null } /** * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ - public static void makeAccessible(Method method) { - if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) - && !method.isAccessible()) { - method.setAccessible(true); + public static void makeAccessible(Method method) { // 定义设置方法为可访问的方法 + if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) // 如果方法或类不是public + && !method.isAccessible()) { // 且方法不可访问 + method.setAccessible(true); // 设置为可访问 } } /** * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。 */ - public static void makeAccessible(Field field) { - if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier - .isFinal(field.getModifiers())) && !field.isAccessible()) { - field.setAccessible(true); + public static void makeAccessible(Field field) { // 定义设置字段为可访问的方法 + if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier // 如果字段或类不是public或字段是final + .isFinal(field.getModifiers())) && !field.isAccessible()) { // 且字段不可访问 + field.setAccessible(true); // 设置为可访问 } } @@ -256,8 +256,8 @@ public class Reflections { * @return the first generic declaration, or Object.class if cannot be determined */ @SuppressWarnings("unchecked") - public static Class getClassGenricType(final Class clazz) { - return getClassGenricType(clazz, 0); + public static Class getClassGenricType(final Class clazz) { // 定义获取类的泛型类型的方法 + return getClassGenricType(clazz, 0); // 调用重载方法 } /** @@ -270,55 +270,54 @@ public class Reflections { * @param index the Index of the generic ddeclaration,start from 0. * @return the index generic declaration, or Object.class if cannot be determined */ - public static Class getClassGenricType(final Class clazz, final int index) { + public static Class getClassGenricType(final Class clazz, final int index) { // 定义获取类的泛型类型的方法 + Type genType = clazz.getGenericSuperclass(); // 获取类的泛型超类 - Type genType = clazz.getGenericSuperclass(); - - if (!(genType instanceof ParameterizedType)) { - log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); - return Object.class; + if (!(genType instanceof ParameterizedType)) { // 如果不是参数化类型 + log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); // 记录警告 + return Object.class; // 返回Object.class } - Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); + Type[] params = ((ParameterizedType) genType).getActualTypeArguments(); // 获取实际类型参数 - if (index >= params.length || index < 0) { + if (index >= params.length || index < 0) { // 如果索引超出范围 log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " - + params.length); - return Object.class; + + params.length); // 记录警告 + return Object.class; // 返回Object.class } - if (!(params[index] instanceof Class)) { - log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); - return Object.class; + if (!(params[index] instanceof Class)) { // 如果参数不是Class类型 + log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter"); // 记录警告 + return Object.class; // 返回Object.class } - return (Class) params[index]; + return (Class) params[index]; // 返回指定索引的Class类型 } - public static Class getUserClass(Object instance) { - Assert.notNull(instance, "Instance must not be null"); - Class clazz = instance.getClass(); - if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { - Class superClass = clazz.getSuperclass(); - if (superClass != null && !Object.class.equals(superClass)) { - return superClass; + public static Class getUserClass(Object instance) { // 定义获取用户类的方法 + Assert.notNull(instance, "Instance must not be null"); // 验证实例不为空 + Class clazz = instance.getClass(); // 获取实例的类 + if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR)) { // 如果类名包含CGLIB分隔符 + Class superClass = clazz.getSuperclass(); // 获取父类 + if (superClass != null && !Object.class.equals(superClass)) { // 如果父类存在且不是Object + return superClass; // 返回父类 } } - return clazz; + return clazz; // 返回当前类 } /** * 将反射时的checked exception转换为unchecked exception. */ - public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { - if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException - || e instanceof NoSuchMethodException) { - return new IllegalArgumentException(e); - } else if (e instanceof InvocationTargetException) { - return new RuntimeException(((InvocationTargetException) e).getTargetException()); - } else if (e instanceof RuntimeException) { - return (RuntimeException) e; + public static RuntimeException convertReflectionExceptionToUnchecked(Exception e) { // 定义转换异常的方法 + if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException // 如果是非法访问或参数异常 + || e instanceof NoSuchMethodException) { // 或者没有该方法异常 + return new IllegalArgumentException(e); // 返回非法参数异常 + } else if (e instanceof InvocationTargetException) { // 如果是调用目标异常 + return new RuntimeException(((InvocationTargetException) e).getTargetException()); // 返回目标异常 + } else if (e instanceof RuntimeException) { // 如果是运行时异常 + return (RuntimeException) e; // 返回运行时异常 } - return new RuntimeException("Unexpected Checked Exception.", e); + return new RuntimeException("Unexpected Checked Exception.", e); // 返回未知异常 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/SpringUtils.java b/src-源文件/main/java/com/yf/exam/core/utils/SpringUtils.java index 295c827..1943685 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/SpringUtils.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/SpringUtils.java @@ -1,32 +1,33 @@ -package com.yf.exam.core.utils; +language:yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/utils/SpringUtils.java +package com.yf.exam.core.utils; // 定义包名 -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.stereotype.Component; +import org.springframework.beans.BeansException; // 导入BeansException类 +import org.springframework.context.ApplicationContext; // 导入ApplicationContext接口 +import org.springframework.context.ApplicationContextAware; // 导入ApplicationContextAware接口 +import org.springframework.stereotype.Component; // 导入Component注解 /** * Spring获取工具 * - * @author bool - * @date 2019-12-09 15:55 + * @author bool // 作者信息 + * @date 2019-12-09 15:55 // 日期信息 */ -@Component -public class SpringUtils implements ApplicationContextAware { +@Component // 将该类标记为Spring组件 +public class SpringUtils implements ApplicationContextAware { // 定义SpringUtils类并实现ApplicationContextAware接口 - private static ApplicationContext applicationContext; + private static ApplicationContext applicationContext; // 静态变量,用于存储ApplicationContext - @Override - public void setApplicationContext(ApplicationContext context) throws BeansException { - applicationContext = context; + @Override // 重写setApplicationContext方法 + public void setApplicationContext(ApplicationContext context) throws BeansException { // 设置ApplicationContext + applicationContext = context; // 将传入的context赋值给静态变量 } - public static T getBean(Class tClass) { - return applicationContext.getBean(tClass); + public static T getBean(Class tClass) { // 泛型方法,根据类获取Bean + return applicationContext.getBean(tClass); // 从ApplicationContext中获取指定类型的Bean } - public static T getBean(String name, Class type) { - return applicationContext.getBean(name, type); + public static T getBean(String name, Class type) { // 泛型方法,根据名称和类型获取Bean + return applicationContext.getBean(name, type); // 从ApplicationContext中获取指定名称和类型的Bean } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/StringUtils.java b/src-源文件/main/java/com/yf/exam/core/utils/StringUtils.java index c0bc43b..3d03f61 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/StringUtils.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/StringUtils.java @@ -1,39 +1,38 @@ -package com.yf.exam.core.utils; +package com.yf.exam.core.utils; // 定义包名 -import java.util.Map; +import java.util.Map; // 导入Map类 /** * 字符串常用工具类 * @author bool * @date 2019-05-15 11:40 */ -public class StringUtils { +public class StringUtils { // 定义StringUtils类 /** * 判断是否为空字符 - * @param str - * @return + * @param str 输入的字符串 + * @return 如果字符串为空或null,返回true;否则返回false */ - public static boolean isBlank(String str){ - return str==null || "".equals(str); + public static boolean isBlank(String str){ // 定义静态方法isBlank + return str==null || "".equals(str); // 检查字符串是否为null或空 } - /** * 将MAP转换成一个xml格式,格式为value... - * @param params - * @return + * @param params 输入的Map参数 + * @return 返回xml格式的字符串 */ - public static String mapToXml(Map params){ - StringBuffer sb = new StringBuffer(""); - for(String key:params.keySet()){ - sb.append("<") - .append(key).append(">") - .append(params.get(key)) - .append(""); + public static String mapToXml(Map params){ // 定义静态方法mapToXml + StringBuffer sb = new StringBuffer(""); // 创建StringBuffer并初始化为 + for(String key:params.keySet()){ // 遍历Map中的每个key + sb.append("<") // 添加开始标签 + .append(key).append(">") // 添加key + .append(params.get(key)) // 添加对应的value + .append(""); // 添加结束标签 } - sb.append(""); - return sb.toString(); + sb.append(""); // 添加结束的标签 + return sb.toString(); // 返回构建的xml字符串 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/excel/ExportExcel.java b/src-源文件/main/java/com/yf/exam/core/utils/excel/ExportExcel.java index d98b557..098af26 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/excel/ExportExcel.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/excel/ExportExcel.java @@ -1,82 +1,83 @@ + /** * Copyright © 2015-2020 JeePlus All rights reserved. */ -package com.yf.exam.core.utils.excel; +package com.yf.exam.core.utils.excel; // 包声明 -import com.google.common.collect.Lists; -import com.yf.exam.core.utils.Reflections; -import com.yf.exam.core.utils.excel.annotation.ExcelField; -import org.apache.commons.lang3.StringUtils; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.CellStyle; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.DataFormat; -import org.apache.poi.ss.usermodel.Font; -import org.apache.poi.ss.usermodel.IndexedColors; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.util.CellRangeAddress; -import org.apache.poi.xssf.streaming.SXSSFWorkbook; -import org.apache.poi.xssf.usermodel.XSSFClientAnchor; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import com.google.common.collect.Lists; // 导入Lists类 +import com.yf.exam.core.utils.Reflections; // 导入Reflections工具类 +import com.yf.exam.core.utils.excel.annotation.ExcelField; // 导入ExcelField注解 +import org.apache.commons.lang3.StringUtils; // 导入StringUtils工具类 +import org.apache.poi.ss.usermodel.Cell; // 导入Cell类 +import org.apache.poi.ss.usermodel.CellStyle; // 导入CellStyle类 +import org.apache.poi.ss.usermodel.Comment; // 导入Comment类 +import org.apache.poi.ss.usermodel.DataFormat; // 导入DataFormat类 +import org.apache.poi.ss.usermodel.Font; // 导入Font类 +import org.apache.poi.ss.usermodel.IndexedColors; // 导入IndexedColors类 +import org.apache.poi.ss.usermodel.Row; // 导入Row类 +import org.apache.poi.ss.usermodel.Sheet; // 导入Sheet类 +import org.apache.poi.ss.usermodel.Workbook; // 导入Workbook类 +import org.apache.poi.ss.util.CellRangeAddress; // 导入CellRangeAddress类 +import org.apache.poi.xssf.streaming.SXSSFWorkbook; // 导入SXSSFWorkbook类 +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; // 导入XSSFClientAnchor类 +import org.apache.poi.xssf.usermodel.XSSFRichTextString; // 导入XSSFRichTextString类 +import org.slf4j.Logger; // 导入Logger接口 +import org.slf4j.LoggerFactory; // 导入LoggerFactory类 -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.URLEncoder; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import javax.servlet.http.HttpServletResponse; // 导入HttpServletResponse类 +import java.io.IOException; // 导入IOException类 +import java.io.OutputStream; // 导入OutputStream类 +import java.lang.reflect.Field; // 导入Field类 +import java.lang.reflect.Method; // 导入Method类 +import java.net.URLEncoder; // 导入URLEncoder类 +import java.util.Collections; // 导入Collections类 +import java.util.Comparator; // 导入Comparator接口 +import java.util.Date; // 导入Date类 +import java.util.HashMap; // 导入HashMap类 +import java.util.List; // 导入List接口 +import java.util.Map; // 导入Map接口 /** * 导出Excel文件(导出“XLSX”格式,支持大数据量导出 @see org.apache.poi.ss.SpreadsheetVersion) * @author jeeplus * @version 2016-04-21 */ -public class ExportExcel { +public class ExportExcel { // ExportExcel类定义 - private static Logger log = LoggerFactory.getLogger(ExportExcel.class); + private static Logger log = LoggerFactory.getLogger(ExportExcel.class); // 日志记录器 /** * 工作薄对象 */ - private SXSSFWorkbook wb; + private SXSSFWorkbook wb; // 工作薄对象 /** * 工作表对象 */ - private Sheet sheet; + private Sheet sheet; // 工作表对象 /** * 样式列表 */ - private Map styles; + private Map styles; // 样式列表 /** * 当前行号 */ - private int rownum; + private int rownum; // 当前行号 /** * 注解列表(Object[]{ ExcelField, Field/Method }) */ - List annotationList = Lists.newArrayList(); + List annotationList = Lists.newArrayList(); // 注解列表 /** * 构造函数 * @param title 表格标题,传“空值”,表示无标题 * @param cls 实体对象,通过annotation.ExportField获取标题 */ - public ExportExcel(String title, Class cls){ - this(title, cls, 1); + public ExportExcel(String title, Class cls){ // 构造函数 + this(title, cls, 1); // 调用另一个构造函数 } /** @@ -86,123 +87,123 @@ public class ExportExcel { * @param type 导出类型(1:导出数据;2:导出模板) * @param groups 导入分组 */ - public ExportExcel(String title, Class cls, int type, int... groups){ + public ExportExcel(String title, Class cls, int type, int... groups){ // 构造函数 // Get annotation field - Field[] fs = cls.getDeclaredFields(); - for (Field f : fs){ - ExcelField ef = f.getAnnotation(ExcelField.class); - if (ef != null && (ef.type()==0 || ef.type()==type)){ - if (groups!=null && groups.length>0){ - boolean inGroup = false; - for (int g : groups){ - if (inGroup){ - break; + Field[] fs = cls.getDeclaredFields(); // 获取类的所有字段 + for (Field f : fs){ // 遍历字段 + ExcelField ef = f.getAnnotation(ExcelField.class); // 获取ExcelField注解 + if (ef != null && (ef.type()==0 || ef.type()==type)){ // 检查注解类型 + if (groups!=null && groups.length>0){ // 检查分组 + boolean inGroup = false; // 初始化分组标志 + for (int g : groups){ // 遍历分组 + if (inGroup){ // 如果已经在分组中 + break; // 退出循环 } - for (int efg : ef.groups()){ - if (g == efg){ - inGroup = true; - annotationList.add(new Object[]{ef, f}); - break; + for (int efg : ef.groups()){ // 遍历注解中的分组 + if (g == efg){ // 如果匹配 + inGroup = true; // 设置标志 + annotationList.add(new Object[]{ef, f}); // 添加到注解列表 + break; // 退出循环 } } } - }else{ - annotationList.add(new Object[]{ef, f}); + }else{ // 如果没有分组 + annotationList.add(new Object[]{ef, f}); // 添加到注解列表 } } } // Get annotation method - Method[] ms = cls.getDeclaredMethods(); - for (Method m : ms){ - ExcelField ef = m.getAnnotation(ExcelField.class); - if (ef != null && (ef.type()==0 || ef.type()==type)){ - if (groups!=null && groups.length>0){ - boolean inGroup = false; - for (int g : groups){ - if (inGroup){ - break; + Method[] ms = cls.getDeclaredMethods(); // 获取类的所有方法 + for (Method m : ms){ // 遍历方法 + ExcelField ef = m.getAnnotation(ExcelField.class); // 获取ExcelField注解 + if (ef != null && (ef.type()==0 || ef.type()==type)){ // 检查注解类型 + if (groups!=null && groups.length>0){ // 检查分组 + boolean inGroup = false; // 初始化分组标志 + for (int g : groups){ // 遍历分组 + if (inGroup){ // 如果已经在分组中 + break; // 退出循环 } - for (int efg : ef.groups()){ - if (g == efg){ - inGroup = true; - annotationList.add(new Object[]{ef, m}); - break; + for (int efg : ef.groups()){ // 遍历注解中的分组 + if (g == efg){ // 如果匹配 + inGroup = true; // 设置标志 + annotationList.add(new Object[]{ef, m}); // 添加到注解列表 + break; // 退出循环 } } } - }else{ - annotationList.add(new Object[]{ef, m}); + }else{ // 如果没有分组 + annotationList.add(new Object[]{ef, m}); // 添加到注解列表 } } } // Field sorting - Collections.sort(annotationList, new Comparator() { + Collections.sort(annotationList, new Comparator() { // 对注解列表进行排序 @Override - public int compare(Object[] o1, Object[] o2) { - return new Integer(((ExcelField)o1[0]).sort()).compareTo( + public int compare(Object[] o1, Object[] o2) { // 比较方法 + return new Integer(((ExcelField)o1[0]).sort()).compareTo( // 比较排序值 new Integer(((ExcelField)o2[0]).sort())); } }); // Initialize - List headerList = Lists.newArrayList(); - for (Object[] os : annotationList){ - String t = ((ExcelField)os[0]).title(); + List headerList = Lists.newArrayList(); // 初始化表头列表 + for (Object[] os : annotationList){ // 遍历注解列表 + String t = ((ExcelField)os[0]).title(); // 获取标题 // 如果是导出,则去掉注释 - if (type==1){ - String[] ss = StringUtils.split(t, "**", 2); - if (ss.length==2){ - t = ss[0]; + if (type==1){ // 如果是导出数据 + String[] ss = StringUtils.split(t, "**", 2); // 分割标题 + if (ss.length==2){ // 如果有注释 + t = ss[0]; // 去掉注释 } } - headerList.add(t); + headerList.add(t); // 添加标题到表头列表 } - initialize(title, headerList); + initialize(title, headerList); // 初始化工作薄 } /** * 初始化函数 * @param title 表格标题,传“空值”,表示无标题 * @param headerList 表头列表 */ - private void initialize(String title, List headerList) { - this.wb = new SXSSFWorkbook(500); - this.sheet = wb.createSheet("Export"); - this.styles = createStyles(wb); + private void initialize(String title, List headerList) { // 初始化方法 + this.wb = new SXSSFWorkbook(500); // 创建工作薄 + this.sheet = wb.createSheet("Export"); // 创建工作表 + this.styles = createStyles(wb); // 创建样式 // Create title - if (StringUtils.isNotBlank(title)){ - Row titleRow = sheet.createRow(rownum++); - titleRow.setHeightInPoints(30); - Cell titleCell = titleRow.createCell(0); - titleCell.setCellStyle(styles.get("title")); - titleCell.setCellValue(title); - sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), + if (StringUtils.isNotBlank(title)){ // 如果标题不为空 + Row titleRow = sheet.createRow(rownum++); // 创建标题行 + titleRow.setHeightInPoints(30); // 设置行高 + Cell titleCell = titleRow.createCell(0); // 创建单元格 + titleCell.setCellStyle(styles.get("title")); // 设置单元格样式 + titleCell.setCellValue(title); // 设置单元格值 + sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), // 合并单元格 titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1)); } // Create header - if (headerList == null){ - throw new RuntimeException("headerList not null!"); + if (headerList == null){ // 如果表头列表为空 + throw new RuntimeException("headerList not null!"); // 抛出异常 } - Row headerRow = sheet.createRow(rownum++); - headerRow.setHeightInPoints(16); - for (int i = 0; i < headerList.size(); i++) { - Cell cell = headerRow.createCell(i); - cell.setCellStyle(styles.get("header")); - String[] ss = StringUtils.split(headerList.get(i), "**", 2); - if (ss.length==2){ - cell.setCellValue(ss[0]); - Comment comment = this.sheet.createDrawingPatriarch().createCellComment( + Row headerRow = sheet.createRow(rownum++); // 创建表头行 + headerRow.setHeightInPoints(16); // 设置行高 + for (int i = 0; i < headerList.size(); i++) { // 遍历表头列表 + Cell cell = headerRow.createCell(i); // 创建单元格 + cell.setCellStyle(styles.get("header")); // 设置单元格样式 + String[] ss = StringUtils.split(headerList.get(i), "**", 2); // 分割表头 + if (ss.length==2){ // 如果有注释 + cell.setCellValue(ss[0]); // 设置单元格值 + Comment comment = this.sheet.createDrawingPatriarch().createCellComment( // 创建注释 new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6)); - comment.setString(new XSSFRichTextString(ss[1])); - cell.setCellComment(comment); - }else{ - cell.setCellValue(headerList.get(i)); + comment.setString(new XSSFRichTextString(ss[1])); // 设置注释内容 + cell.setCellComment(comment); // 设置单元格注释 + }else{ // 如果没有注释 + cell.setCellValue(headerList.get(i)); // 设置单元格值 } - sheet.autoSizeColumn(i); + sheet.autoSizeColumn(i); // 自动调整列宽 } - for (int i = 0; i < headerList.size(); i++) { - int colWidth = sheet.getColumnWidth(i)*2; - sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth); + for (int i = 0; i < headerList.size(); i++) { // 遍历表头列表 + int colWidth = sheet.getColumnWidth(i)*2; // 计算列宽 + sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth); // 设置列宽 } - log.debug("Initialize success."); + log.debug("Initialize success."); // 记录初始化成功日志 } /** @@ -210,73 +211,73 @@ public class ExportExcel { * @param wb 工作薄对象 * @return 样式列表 */ - private Map createStyles(Workbook wb) { - Map styles = new HashMap<>(16); + private Map createStyles(Workbook wb) { // 创建样式方法 + Map styles = new HashMap<>(16); // 初始化样式列表 - CellStyle style = wb.createCellStyle(); - style.setAlignment(CellStyle.ALIGN_CENTER); - style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); - Font titleFont = wb.createFont(); - titleFont.setFontName("Arial"); - titleFont.setFontHeightInPoints((short) 16); - titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); - style.setFont(titleFont); - styles.put("title", style); + CellStyle style = wb.createCellStyle(); // 创建样式 + style.setAlignment(CellStyle.ALIGN_CENTER); // 设置水平对齐方式 + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); // 设置垂直对齐方式 + Font titleFont = wb.createFont(); // 创建字体 + titleFont.setFontName("Arial"); // 设置字体名称 + titleFont.setFontHeightInPoints((short) 16); // 设置字体大小 + titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD); // 设置字体加粗 + style.setFont(titleFont); // 设置样式字体 + styles.put("title", style); // 添加样式到列表 - style = wb.createCellStyle(); - style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); - style.setBorderRight(CellStyle.BORDER_THIN); - style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderLeft(CellStyle.BORDER_THIN); - style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderTop(CellStyle.BORDER_THIN); - style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setBorderBottom(CellStyle.BORDER_THIN); - style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); - Font dataFont = wb.createFont(); - dataFont.setFontName("Arial"); - dataFont.setFontHeightInPoints((short) 10); - style.setFont(dataFont); - styles.put("data", style); + style = wb.createCellStyle(); // 创建样式 + style.setVerticalAlignment(CellStyle.VERTICAL_CENTER); // 设置垂直对齐方式 + style.setBorderRight(CellStyle.BORDER_THIN); // 设置右边框 + style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 设置右边框颜色 + style.setBorderLeft(CellStyle.BORDER_THIN); // 设置左边框 + style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 设置左边框颜色 + style.setBorderTop(CellStyle.BORDER_THIN); // 设置上边框 + style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 设置上边框颜色 + style.setBorderBottom(CellStyle.BORDER_THIN); // 设置下边框 + style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 设置下边框颜色 + Font dataFont = wb.createFont(); // 创建字体 + dataFont.setFontName("Arial"); // 设置字体名称 + dataFont.setFontHeightInPoints((short) 10); // 设置字体大小 + style.setFont(dataFont); // 设置样式字体 + styles.put("data", style); // 添加样式到列表 - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_LEFT); - styles.put("data1", style); + style = wb.createCellStyle(); // 创建样式 + style.cloneStyleFrom(styles.get("data")); // 克隆数据样式 + style.setAlignment(CellStyle.ALIGN_LEFT); // 设置左对齐 + styles.put("data1", style); // 添加样式到列表 - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_CENTER); - styles.put("data2", style); + style = wb.createCellStyle(); // 创建样式 + style.cloneStyleFrom(styles.get("data")); // 克隆数据样式 + style.setAlignment(CellStyle.ALIGN_CENTER); // 设置居中对齐 + styles.put("data2", style); // 添加样式到列表 - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); - style.setAlignment(CellStyle.ALIGN_RIGHT); - styles.put("data3", style); + style = wb.createCellStyle(); // 创建样式 + style.cloneStyleFrom(styles.get("data")); // 克隆数据样式 + style.setAlignment(CellStyle.ALIGN_RIGHT); // 设置右对齐 + styles.put("data3", style); // 添加样式到列表 - style = wb.createCellStyle(); - style.cloneStyleFrom(styles.get("data")); -// style.setWrapText(true); - style.setAlignment(CellStyle.ALIGN_CENTER); - style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); - style.setFillPattern(CellStyle.SOLID_FOREGROUND); - Font headerFont = wb.createFont(); - headerFont.setFontName("Arial"); - headerFont.setFontHeightInPoints((short) 10); - headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); - headerFont.setColor(IndexedColors.WHITE.getIndex()); - style.setFont(headerFont); - styles.put("header", style); + style = wb.createCellStyle(); // 创建样式 + style.cloneStyleFrom(styles.get("data")); // 克隆数据样式 +// style.setWrapText(true); // 设置文本换行 + style.setAlignment(CellStyle.ALIGN_CENTER); // 设置居中对齐 + style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex()); // 设置前景色 + style.setFillPattern(CellStyle.SOLID_FOREGROUND); // 设置填充模式 + Font headerFont = wb.createFont(); // 创建字体 + headerFont.setFontName("Arial"); // 设置字体名称 + headerFont.setFontHeightInPoints((short) 10); // 设置字体大小 + headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD); // 设置字体加粗 + headerFont.setColor(IndexedColors.WHITE.getIndex()); // 设置字体颜色 + style.setFont(headerFont); // 设置样式字体 + styles.put("header", style); // 添加样式到列表 - return styles; + return styles; // 返回样式列表 } /** * 添加一行 * @return 行对象 */ - public Row addRow(){ - return sheet.createRow(rownum++); + public Row addRow(){ // 添加行方法 + return sheet.createRow(rownum++); // 创建新行并返回 } @@ -287,8 +288,8 @@ public class ExportExcel { * @param val 添加值 * @return 单元格对象 */ - public Cell addCell(Row row, int column, Object val){ - return this.addCell(row, column, val, 0, Class.class); + public Cell addCell(Row row, int column, Object val){ // 添加单元格方法 + return this.addCell(row, column, val, 0, Class.class); // 调用重载方法 } /** @@ -299,104 +300,104 @@ public class ExportExcel { * @param align 对齐方式(1:靠左;2:居中;3:靠右) * @return 单元格对象 */ - public Cell addCell(Row row, int column, Object val, int align, Class fieldType){ - Cell cell = row.createCell(column); - CellStyle style = styles.get("data"+(align>=1&&align<=3?align:"")); - try { - if (val == null){ - cell.setCellValue(""); - } else if (val instanceof String) { - cell.setCellValue((String) val); - } else if (val instanceof Integer) { - cell.setCellValue((Integer) val); - } else if (val instanceof Long) { - cell.setCellValue((Long) val); - } else if (val instanceof Double) { - cell.setCellValue((Double) val); - } else if (val instanceof Float) { - cell.setCellValue((Float) val); - } else if (val instanceof Date) { - DataFormat format = wb.createDataFormat(); - style.setDataFormat(format.getFormat("yyyy-MM-dd")); - cell.setCellValue((Date) val); - } else { - if (fieldType != Class.class){ - cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); - }else{ + public Cell addCell(Row row, int column, Object val, int align, Class fieldType){ // 添加单元格重载方法 + Cell cell = row.createCell(column); // 创建单元格 + CellStyle style = styles.get("data"+(align>=1&&align<=3?align:"")); // 获取样式 + try { // 尝试设置单元格值 + if (val == null){ // 如果值为null + cell.setCellValue(""); // 设置为空字符串 + } else if (val instanceof String) { // 如果值是字符串 + cell.setCellValue((String) val); // 设置单元格值 + } else if (val instanceof Integer) { // 如果值是整数 + cell.setCellValue((Integer) val); // 设置单元格值 + } else if (val instanceof Long) { // 如果值是长整型 + cell.setCellValue((Long) val); // 设置单元格值 + } else if (val instanceof Double) { // 如果值是双精度浮点型 + cell.setCellValue((Double) val); // 设置单元格值 + } else if (val instanceof Float) { // 如果值是单精度浮点型 + cell.setCellValue((Float) val); // 设置单元格值 + } else if (val instanceof Date) { // 如果值是日期 + DataFormat format = wb.createDataFormat(); // 创建数据格式 + style.setDataFormat(format.getFormat("yyyy-MM-dd")); // 设置日期格式 + cell.setCellValue((Date) val); // 设置单元格值 + } else { // 如果值是其他类型 + if (fieldType != Class.class){ // 如果字段类型不是Class + cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val)); // 设置单元格值 + }else{ // 如果字段类型是Class cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), - "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); + "fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val)); // 设置单元格值 } } - } catch (Exception ex) { - log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); - cell.setCellValue(val.toString()); + } catch (Exception ex) { // 捕获异常 + log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString()); // 记录错误日志 + cell.setCellValue(val.toString()); // 设置单元格值为字符串 } - cell.setCellStyle(style); - return cell; + cell.setCellStyle(style); // 设置单元格样式 + return cell; // 返回单元格对象 } /** * 添加数据(通过annotation.ExportField添加数据) * @return list 数据列表 */ - public ExportExcel setDataList(List list){ - for (E e : list){ - int colunm = 0; - Row row = this.addRow(); - StringBuilder sb = new StringBuilder(); - for (Object[] os : annotationList){ - ExcelField ef = (ExcelField)os[0]; - Object val = null; - try{ - if (StringUtils.isNotBlank(ef.value())){ - val = Reflections.invokeGetter(e, ef.value()); - }else{ - if (os[1] instanceof Field){ - val = Reflections.invokeGetter(e, ((Field)os[1]).getName()); - }else if (os[1] instanceof Method){ - val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); + public ExportExcel setDataList(List list){ // 设置数据列表方法 + for (E e : list){ // 遍历数据列表 + int colunm = 0; // 初始化列号 + Row row = this.addRow(); // 添加新行 + StringBuilder sb = new StringBuilder(); // 初始化字符串构建器 + for (Object[] os : annotationList){ // 遍历注解列表 + ExcelField ef = (ExcelField)os[0]; // 获取ExcelField注解 + Object val = null; // 初始化值 + try{ // 尝试获取值 + if (StringUtils.isNotBlank(ef.value())){ // 如果注解值不为空 + val = Reflections.invokeGetter(e, ef.value()); // 通过反射获取值 + }else{ // 如果注解值为空 + if (os[1] instanceof Field){ // 如果是字段 + val = Reflections.invokeGetter(e, ((Field)os[1]).getName()); // 通过反射获取值 + }else if (os[1] instanceof Method){ // 如果是方法 + val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {}); // 通过反射获取值 } } - }catch(Exception ex) { - log.info(ex.toString()); - val = ""; + }catch(Exception ex) { // 捕获异常 + log.info(ex.toString()); // 记录错误日志 + val = ""; // 设置值为空字符串 } - this.addCell(row, colunm++, val, ef.align(), ef.fieldType()); - sb.append(val + ", "); + this.addCell(row, colunm++, val, ef.align(), ef.fieldType()); // 添加单元格 + sb.append(val + ", "); // 添加值到字符串构建器 } - log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); + log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); // 记录写入成功日志 } - return this; + return this; // 返回当前对象 } /** * 输出数据流 * @param os 输出数据流 */ - public ExportExcel write(OutputStream os) throws IOException{ - wb.write(os); - return this; + public ExportExcel write(OutputStream os) throws IOException{ // 输出数据流方法 + wb.write(os); // 写入工作薄到输出流 + return this; // 返回当前对象 } /** * 输出到客户端 * @param fileName 输出文件名 */ - public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{ - response.reset(); - response.setHeader("Access-Control-Allow-Origin", "*"); - response.setContentType("application/octet-stream; charset=utf-8"); - response.addHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName, "utf-8")); - write(response.getOutputStream()); - return this; + public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{ // 输出到客户端方法 + response.reset(); // 重置响应 + response.setHeader("Access-Control-Allow-Origin", "*"); // 设置跨域头 + response.setContentType("application/octet-stream; charset=utf-8"); // 设置内容类型 + response.addHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(fileName, "utf-8")); // 设置下载文件名 + write(response.getOutputStream()); // 写入输出流 + return this; // 返回当前对象 } /** * 清理临时文件 */ - public ExportExcel dispose(){ - wb.dispose(); - return this; + public ExportExcel dispose(){ // 清理临时文件方法 + wb.dispose(); // 释放工作薄资源 + return this; // 返回当前对象 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/excel/ImportExcel.java b/src-源文件/main/java/com/yf/exam/core/utils/excel/ImportExcel.java index fca308a..d91f504 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/excel/ImportExcel.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/excel/ImportExcel.java @@ -1,61 +1,60 @@ /** * Copyright © 2015-2020 JeePlus All rights reserved. */ -package com.yf.exam.core.utils.excel; +package com.yf.exam.core.utils.excel; // 定义包名 -import com.google.common.collect.Lists; -import com.yf.exam.core.utils.Reflections; -import com.yf.exam.core.utils.excel.annotation.ExcelField; -import org.apache.commons.lang3.StringUtils; -import org.apache.poi.hssf.usermodel.HSSFDateUtil; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; -import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.xssf.usermodel.XSSFWorkbook; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.multipart.MultipartFile; +import com.google.common.collect.Lists; // 导入Google的Lists工具类 +import com.yf.exam.core.utils.Reflections; // 导入自定义的Reflections工具类 +import com.yf.exam.core.utils.excel.annotation.ExcelField; // 导入ExcelField注解 +import org.apache.commons.lang3.StringUtils; // 导入Apache Commons的StringUtils工具类 +import org.apache.poi.hssf.usermodel.HSSFDateUtil; // 导入HSSFDateUtil类用于处理日期 +import org.apache.poi.hssf.usermodel.HSSFWorkbook; // 导入HSSFWorkbook类用于处理XLS文件 +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; // 导入异常类 +import org.apache.poi.ss.usermodel.Cell; // 导入Cell类表示单元格 +import org.apache.poi.ss.usermodel.Row; // 导入Row类表示行 +import org.apache.poi.ss.usermodel.Sheet; // 导入Sheet类表示工作表 +import org.apache.poi.ss.usermodel.Workbook; // 导入Workbook类表示工作簿 +import org.apache.poi.xssf.usermodel.XSSFWorkbook; // 导入XSSFWorkbook类用于处理XLSX文件 +import org.slf4j.Logger; // 导入Logger接口 +import org.slf4j.LoggerFactory; // 导入LoggerFactory类 +import org.springframework.web.multipart.MultipartFile; // 导入MultipartFile类用于处理文件上传 -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.List; +import java.io.IOException; // 导入IOException异常 +import java.io.InputStream; // 导入InputStream类 +import java.lang.reflect.Field; // 导入Field类用于反射 +import java.lang.reflect.Method; // 导入Method类用于反射 +import java.text.NumberFormat; // 导入NumberFormat类用于格式化数字 +import java.text.SimpleDateFormat; // 导入SimpleDateFormat类用于格式化日期 +import java.util.Collections; // 导入Collections类用于集合操作 +import java.util.Comparator; // 导入Comparator接口用于比较 +import java.util.Date; // 导入Date类表示日期 +import java.util.List; // 导入List接口表示列表 /** * 导入Excel文件(支持“XLS”和“XLSX”格式) * @author jeeplus * @version 2016-03-10 */ -public class ImportExcel { +public class ImportExcel { // 定义ImportExcel类 - private static Logger log = LoggerFactory.getLogger(ImportExcel.class); + private static Logger log = LoggerFactory.getLogger(ImportExcel.class); // 创建日志记录器 /** * 工作薄对象 */ - private Workbook wb; + private Workbook wb; // 定义工作簿对象 /** * 工作表对象 */ - private Sheet sheet; + private Sheet sheet; // 定义工作表对象 /** * 标题行号 */ - private int headerNum; + private int headerNum; // 定义标题行号 - /** * 构造函数 * @param multipartFile 导入文件对象 @@ -65,8 +64,8 @@ public class ImportExcel { * @throws IOException */ public ImportExcel(MultipartFile multipartFile, int headerNum, int sheetIndex) - throws InvalidFormatException, IOException { - this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex); + throws InvalidFormatException, IOException { // 构造函数,接收文件、标题行号和工作表索引 + this(multipartFile.getOriginalFilename(), multipartFile.getInputStream(), headerNum, sheetIndex); // 调用另一个构造函数 } /** @@ -78,22 +77,22 @@ public class ImportExcel { * @throws IOException */ public ImportExcel(String fileName, InputStream is, int headerNum, int sheetIndex) - throws IOException { - if (StringUtils.isBlank(fileName)){ - throw new RuntimeException("导入文档为空!"); - }else if(fileName.toLowerCase().endsWith("xls")){ - this.wb = new HSSFWorkbook(is); + throws IOException { // 构造函数,接收文件名、输入流、标题行号和工作表索引 + if (StringUtils.isBlank(fileName)){ // 检查文件名是否为空 + throw new RuntimeException("导入文档为空!"); // 抛出异常 + }else if(fileName.toLowerCase().endsWith("xls")){ // 检查文件格式 + this.wb = new HSSFWorkbook(is); // 创建HSSFWorkbook对象 }else if(fileName.toLowerCase().endsWith("xlsx")){ - this.wb = new XSSFWorkbook(is); + this.wb = new XSSFWorkbook(is); // 创建XSSFWorkbook对象 }else{ - throw new RuntimeException("文档格式不正确!"); + throw new RuntimeException("文档格式不正确!"); // 抛出异常 } - if (this.wb.getNumberOfSheets() List getDataList(Class cls, int... groups) throws InstantiationException, IllegalAccessException{ - List annotationList = Lists.newArrayList(); + public List getDataList(Class cls, int... groups) throws InstantiationException, IllegalAccessException{ // 获取导入数据列表 + List annotationList = Lists.newArrayList(); // 创建注解列表 // Get annotation field - Field[] fs = cls.getDeclaredFields(); - for (Field f : fs){ - ExcelField ef = f.getAnnotation(ExcelField.class); - if (ef != null && (ef.type()==0 || ef.type()==2)){ - if (groups!=null && groups.length>0){ - boolean inGroup = false; - for (int g : groups){ - if (inGroup){ - break; + Field[] fs = cls.getDeclaredFields(); // 获取类的所有字段 + for (Field f : fs){ // 遍历字段 + ExcelField ef = f.getAnnotation(ExcelField.class); // 获取字段上的ExcelField注解 + if (ef != null && (ef.type()==0 || ef.type()==2)){ // 检查注解类型 + if (groups!=null && groups.length>0){ // 检查分组 + boolean inGroup = false; // 初始化分组标志 + for (int g : groups){ // 遍历分组 + if (inGroup){ // 如果已经在分组中 + break; // 跳出循环 } - for (int efg : ef.groups()){ - if (g == efg){ - inGroup = true; - annotationList.add(new Object[]{ef, f}); - break; + for (int efg : ef.groups()){ // 遍历注解中的分组 + if (g == efg){ // 如果分组匹配 + inGroup = true; // 设置标志 + annotationList.add(new Object[]{ef, f}); // 添加到注解列表 + break; // 跳出循环 } } } }else{ - annotationList.add(new Object[]{ef, f}); + annotationList.add(new Object[]{ef, f}); // 添加到注解列表 } } } // Get annotation method - Method[] ms = cls.getDeclaredMethods(); - for (Method m : ms){ - ExcelField ef = m.getAnnotation(ExcelField.class); - if (ef != null && (ef.type()==0 || ef.type()==2)){ - if (groups!=null && groups.length>0){ - boolean inGroup = false; - for (int g : groups){ - if (inGroup){ - break; + Method[] ms = cls.getDeclaredMethods(); // 获取类的所有方法 + for (Method m : ms){ // 遍历方法 + ExcelField ef = m.getAnnotation(ExcelField.class); // 获取方法上的ExcelField注解 + if (ef != null && (ef.type()==0 || ef.type()==2)){ // 检查注解类型 + if (groups!=null && groups.length>0){ // 检查分组 + boolean inGroup = false; // 初始化分组标志 + for (int g : groups){ // 遍历分组 + if (inGroup){ // 如果已经在分组中 + break; // 跳出循环 } - for (int efg : ef.groups()){ - if (g == efg){ - inGroup = true; - annotationList.add(new Object[]{ef, m}); - break; + for (int efg : ef.groups()){ // 遍历注解中的分组 + if (g == efg){ // 如果分组匹配 + inGroup = true; // 设置标志 + annotationList.add(new Object[]{ef, m}); // 添加到注解列表 + break; // 跳出循环 } } } }else{ - annotationList.add(new Object[]{ef, m}); + annotationList.add(new Object[]{ef, m}); // 添加到注解列表 } } } // Field sorting - Collections.sort(annotationList, new Comparator() { + Collections.sort(annotationList, new Comparator() { // 对注解列表进行排序 @Override - public int compare(Object[] o1, Object[] o2) { - return new Integer(((ExcelField)o1[0]).sort()).compareTo( + public int compare(Object[] o1, Object[] o2) { // 比较两个对象 + return new Integer(((ExcelField)o1[0]).sort()).compareTo( // 根据排序值进行比较 new Integer(((ExcelField)o2[0]).sort())); } }); // Get excel data - List dataList = Lists.newArrayList(); - for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { - E e = (E)cls.newInstance(); - int column = 0; - Row row = this.getRow(i); - StringBuilder sb = new StringBuilder(); - for (Object[] os : annotationList){ - Object val = this.getCellValue(row, column++); - if (val != null){ - ExcelField ef = (ExcelField)os[0]; + List dataList = Lists.newArrayList(); // 创建数据列表 + for (int i = this.getDataRowNum(); i < this.getLastDataRowNum(); i++) { // 遍历数据行 + E e = (E)cls.newInstance(); // 创建对象实例 + int column = 0; // 初始化列索引 + Row row = this.getRow(i); // 获取行对象 + StringBuilder sb = new StringBuilder(); // 创建字符串构建器 + for (Object[] os : annotationList){ // 遍历注解列表 + Object val = this.getCellValue(row, column++); // 获取单元格值 + if (val != null){ // 检查值是否为空 + ExcelField ef = (ExcelField)os[0]; // 获取ExcelField注解 // Get param type and type cast - Class valType = Class.class; - if (os[1] instanceof Field){ - valType = ((Field)os[1]).getType(); - }else if (os[1] instanceof Method){ + Class valType = Class.class; // 初始化值类型 + if (os[1] instanceof Field){ // 检查是否为字段 + valType = ((Field)os[1]).getType(); // 获取字段类型 + }else if (os[1] instanceof Method){ // 检查是否为方法 Method method = ((Method)os[1]); - if ("get".equals(method.getName().substring(0, 3))){ - valType = method.getReturnType(); - }else if("set".equals(method.getName().substring(0, 3))){ - valType = ((Method)os[1]).getParameterTypes()[0]; + if ("get".equals(method.getName().substring(0, 3))){ // 检查方法名 + valType = method.getReturnType(); // 获取返回类型 + }else if("set".equals(method.getName().substring(0, 3))){ // 检查方法名 + valType = ((Method)os[1]).getParameterTypes()[0]; // 获取参数类型 } } //log.debug("Import value type: ["+i+","+column+"] " + valType); try { //如果导入的java对象,需要在这里自己进行变换。 - if (valType == String.class){ - String s = String.valueOf(val.toString()); - if(StringUtils.endsWith(s, ".0")){ - val = StringUtils.substringBefore(s, ".0"); + if (valType == String.class){ // 检查值类型 + String s = String.valueOf(val.toString()); // 转换为字符串 + if(StringUtils.endsWith(s, ".0")){ // 检查是否以.0结尾 + val = StringUtils.substringBefore(s, ".0"); // 去掉.0 }else{ - val = String.valueOf(val.toString()); + val = String.valueOf(val.toString()); // 转换为字符串 } - }else if (valType == Integer.class){ - val = Double.valueOf(val.toString()).intValue(); - }else if (valType == Long.class){ - val = Double.valueOf(val.toString()).longValue(); - }else if (valType == Double.class){ - val = Double.valueOf(val.toString()); - }else if (valType == Float.class){ - val = Float.valueOf(val.toString()); - }else if (valType == Date.class){ - SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); - val=sdf.parse(val.toString()); + }else if (valType == Integer.class){ // 检查值类型 + val = Double.valueOf(val.toString()).intValue(); // 转换为整数 + }else if (valType == Long.class){ // 检查值类型 + val = Double.valueOf(val.toString()).longValue(); // 转换为长整型 + }else if (valType == Double.class){ // 检查值类型 + val = Double.valueOf(val.toString()); // 转换为双精度浮点型 + }else if (valType == Float.class){ // 检查值类型 + val = Float.valueOf(val.toString()); // 转换为浮点型 + }else if (valType == Date.class){ // 检查值类型 + SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd"); // 定义日期格式 + val=sdf.parse(val.toString()); // 解析日期 }else{ - if (ef.fieldType() != Class.class){ - val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); + if (ef.fieldType() != Class.class){ // 检查字段类型 + val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); // 调用getValue方法 }else{ val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), - "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); + "fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); // 动态调用getValue方法 } } - } catch (Exception ex) { - log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); - val = null; + } catch (Exception ex) { // 捕获异常 + log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); // 记录错误日志 + val = null; // 设置值为null } // set entity value - if (os[1] instanceof Field){ - Reflections.invokeSetter(e, ((Field)os[1]).getName(), val); - }else if (os[1] instanceof Method){ - String mthodName = ((Method)os[1]).getName(); - if ("get".equals(mthodName.substring(0, 3))){ - mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); + if (os[1] instanceof Field){ // 检查是否为字段 + Reflections.invokeSetter(e, ((Field)os[1]).getName(), val); // 设置字段值 + }else if (os[1] instanceof Method){ // 检查是否为方法 + String mthodName = ((Method)os[1]).getName(); // 获取方法名 + if ("get".equals(mthodName.substring(0, 3))){ // 检查方法名 + mthodName = "set"+StringUtils.substringAfter(mthodName, "get"); // 转换为set方法名 } - Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); + Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); // 调用set方法 } } - sb.append(val+", "); + sb.append(val+", "); // 添加值到字符串构建器 } - dataList.add(e); - log.debug("Read success: ["+i+"] "+sb.toString()); + dataList.add(e); // 添加对象到数据列表 + log.debug("Read success: ["+i+"] "+sb.toString()); // 记录读取成功的日志 } - return dataList; + return dataList; // 返回数据列表 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/excel/annotation/ExcelField.java b/src-源文件/main/java/com/yf/exam/core/utils/excel/annotation/ExcelField.java index add0d1c..bc2da91 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/excel/annotation/ExcelField.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/excel/annotation/ExcelField.java @@ -1,59 +1,87 @@ +// ... existing code ... /** * Copyright © 2015-2020 JeePlus All rights reserved. +// 版权声明,包含版权信息和链接 */ package com.yf.exam.core.utils.excel.annotation; +// 包声明,定义该类所在的包 import java.lang.annotation.ElementType; +// 导入ElementType类,用于定义注解的适用范围 import java.lang.annotation.Retention; +// 导入Retention类,用于定义注解的保留策略 import java.lang.annotation.RetentionPolicy; +// 导入RetentionPolicy类,定义注解的保留策略类型 import java.lang.annotation.Target; +// 导入Target类,用于定义注解的目标 /** * Excel注解定义 * @author jeeplus * @version 2016-03-10 */ +// 注解类的描述,包含作者和版本信息 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) +// 定义该注解可以应用于方法、字段和类 @Retention(RetentionPolicy.RUNTIME) +// 定义该注解在运行时可用 public @interface ExcelField { +// 定义ExcelField注解 /** * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”) + * 字段名的描述,提供默认值和示例 */ String value() default ""; + // 字段名,默认为空字符串 /** * 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效) + * 字段标题的描述,说明如何添加批注 */ String title(); + // 字段标题,必填项 /** * 字段类型(0:导出导入;1:仅导出;2:仅导入) + * 字段类型的描述,提供可选值 */ int type() default 0; + // 字段类型,默认为0(导出导入) /** * 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右) + * 对齐方式的描述,提供可选值 */ int align() default 0; + // 对齐方式,默认为0(自动) /** * 导出字段字段排序(升序) + * 字段排序的描述,说明排序方式 */ int sort() default 0; + // 字段排序,默认为0(升序) /** * 如果是字典类型,请设置字典的type值 + * 字典类型的描述,说明如何设置字典类型 */ String dictType() default ""; + // 字典类型,默认为空字符串 /** * 反射类型 + * 反射类型的描述,说明该字段的类型 */ Class fieldType() default Class.class; + // 字段类型,默认为Class.class /** * 字段归属组(根据分组导出导入) + * 字段分组的描述,说明如何根据分组导出导入 */ int[] groups() default {}; + // 字段归属组,默认为空数组 } +// ... existing code ... \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/excel/fieldtype/ListType.java b/src-源文件/main/java/com/yf/exam/core/utils/excel/fieldtype/ListType.java index 9369888..d7716a5 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/excel/fieldtype/ListType.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/excel/fieldtype/ListType.java @@ -1,56 +1,57 @@ + /** * Copyright © 2015-2020 JeePlus All rights reserved. */ -package com.yf.exam.core.utils.excel.fieldtype; +package com.yf.exam.core.utils.excel.fieldtype; // 定义包名 -import com.google.common.collect.Lists; -import com.yf.exam.core.utils.StringUtils; +import com.google.common.collect.Lists; // 导入Google的Lists工具类 +import com.yf.exam.core.utils.StringUtils; // 导入自定义的StringUtils工具类 -import java.util.List; +import java.util.List; // 导入List接口 /** * 字段类型转换 * @author jeeplus * @version 2016-5-29 */ -public class ListType { +public class ListType { // 定义ListType类 /** * 获取对象值(导入) */ - public static Object getValue(String val) { - List list = Lists.newArrayList(); - if(!StringUtils.isBlank(val)) { - for (String s : val.split(",")) { - list.add(s); + public static Object getValue(String val) { // 定义静态方法getValue,接收一个字符串参数 + List list = Lists.newArrayList(); // 创建一个新的字符串列表 + if(!StringUtils.isBlank(val)) { // 检查输入字符串是否为空 + for (String s : val.split(",")) { // 按逗号分割字符串 + list.add(s); // 将分割后的字符串添加到列表中 } } - return list; + return list; // 返回列表 } /** * 设置对象值(导出) */ - public static String setValue(Object val) { - if (val != null){ - List list = (List)val; - StringBuffer sb = null; - for (String item: list){ - if(StringUtils.isBlank(item)){ - continue; + public static String setValue(Object val) { // 定义静态方法setValue,接收一个对象参数 + if (val != null){ // 检查输入对象是否为null + List list = (List)val; // 将对象强制转换为字符串列表 + StringBuffer sb = null; // 初始化字符串缓冲区 + for (String item: list){ // 遍历列表中的每个字符串 + if(StringUtils.isBlank(item)){ // 检查字符串是否为空 + continue; // 如果为空,跳过当前循环 } - if(sb == null){ - sb = new StringBuffer(item); + if(sb == null){ // 如果字符串缓冲区为空 + sb = new StringBuffer(item); // 初始化缓冲区为当前字符串 }else{ - sb.append(",").append(item); + sb.append(",").append(item); // 否则,添加逗号和当前字符串 } } - if(sb!=null) { - return sb.toString().replace("[]", ""); + if(sb!=null) { // 如果字符串缓冲区不为空 + return sb.toString().replace("[]", ""); // 返回缓冲区内容并替换"[]"为空 } } - return ""; + return ""; // 如果输入对象为null,返回空字符串 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/file/Md5Util.java b/src-源文件/main/java/com/yf/exam/core/utils/file/Md5Util.java index d5d33cf..d74ec67 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/file/Md5Util.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/file/Md5Util.java @@ -1,7 +1,6 @@ -package com.yf.exam.core.utils.file; - -import java.security.MessageDigest; +package com.yf.exam.core.utils.file; // 包声明 +import java.security.MessageDigest; // 导入MessageDigest类,用于生成MD5哈希 /** * MD5工具类 @@ -11,27 +10,26 @@ import java.security.MessageDigest; * @author Bool * @version */ -public class Md5Util { - +public class Md5Util { // 定义MD5工具类 /** * 简单MD5 - * @param str - * @return + * @param str 输入字符串 + * @return 返回MD5哈希值 */ - public static String md5(String str) { + public static String md5(String str) { // 定义静态方法md5,接受一个字符串参数 - try { - MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] array = md.digest(str.getBytes("UTF-8")); - StringBuilder sb = new StringBuilder(); - for (byte item : array) { - sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); + try { // 开始异常处理 + MessageDigest md = MessageDigest.getInstance("MD5"); // 获取MD5实例 + byte[] array = md.digest(str.getBytes("UTF-8")); // 计算输入字符串的MD5哈希值 + StringBuilder sb = new StringBuilder(); // 创建StringBuilder用于构建结果字符串 + for (byte item : array) { // 遍历哈希字节数组 + sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3)); // 将每个字节转换为十六进制并添加到StringBuilder } - return sb.toString(); - }catch(Exception e) { - return null; + return sb.toString(); // 返回最终的MD5哈希字符串 + }catch(Exception e) { // 捕获异常 + return null; // 如果发生异常,返回null } } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassHandler.java b/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassHandler.java index 1af239e..103e097 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassHandler.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassHandler.java @@ -1,8 +1,7 @@ -package com.yf.exam.core.utils.passwd; +package com.yf.exam.core.utils.passwd; // 定义包名 - -import com.yf.exam.core.utils.file.Md5Util; -import org.apache.commons.lang3.RandomStringUtils; +import com.yf.exam.core.utils.file.Md5Util; // 导入Md5Util类 +import org.apache.commons.lang3.RandomStringUtils; // 导入RandomStringUtils类 /** * 通用的密码处理类,用于生成密码和校验密码 @@ -12,7 +11,7 @@ import org.apache.commons.lang3.RandomStringUtils; * @author Bool * @version */ -public class PassHandler { +public class PassHandler { // 定义PassHandler类 /** * checkPass:校验密码是否一致 @@ -22,9 +21,9 @@ public class PassHandler { * @param pass 数据库保存的密码MD5 * @return */ - public static boolean checkPass(String inputPass , String salt , String pass){ - String pwdMd5 = Md5Util.md5(inputPass); - return Md5Util.md5(pwdMd5 + salt).equals(pass); + public static boolean checkPass(String inputPass , String salt , String pass){ // 定义静态方法checkPass + String pwdMd5 = Md5Util.md5(inputPass); // 将输入密码进行MD5加密 + return Md5Util.md5(pwdMd5 + salt).equals(pass); // 校验加密后的密码与数据库密码是否一致 } @@ -35,23 +34,23 @@ public class PassHandler { * @param inputPass 输入的密码 * @return PassInfo 返回一个密码对象,记得保存 */ - public static PassInfo buildPassword(String inputPass) { + public static PassInfo buildPassword(String inputPass) { // 定义静态方法buildPassword //产生一个6位数的随机码 - String salt = RandomStringUtils.randomAlphabetic(6); + String salt = RandomStringUtils.randomAlphabetic(6); // 生成6位随机字母作为盐 //加密后的密码 - String encryptPassword = Md5Util.md5(Md5Util.md5(inputPass)+salt); + String encryptPassword = Md5Util.md5(Md5Util.md5(inputPass)+salt); // 对输入密码和盐进行双重MD5加密 //返回对象 - return new PassInfo(salt,encryptPassword); + return new PassInfo(salt,encryptPassword); // 返回包含盐和加密密码的PassInfo对象 } - public static void main(String[] args) { + public static void main(String[] args) { // 主方法 - PassInfo info = buildPassword("190601"); + PassInfo info = buildPassword("190601"); // 调用buildPassword方法生成密码信息 - System.out.println(info.getPassword()); - System.out.println(info.getSalt()); + System.out.println(info.getPassword()); // 输出加密后的密码 + System.out.println(info.getSalt()); // 输出生成的盐 } -} +} \ No newline at end of file diff --git a/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassInfo.java b/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassInfo.java index 3634fb6..cba975b 100644 --- a/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassInfo.java +++ b/src-源文件/main/java/com/yf/exam/core/utils/passwd/PassInfo.java @@ -1,38 +1,45 @@ -package com.yf.exam.core.utils.passwd; +package com.yf.exam.core.utils.passwd; // 定义包名 /** * 密码实体 * ClassName: PassInfo
* date: 2018年2月13日 下午7:13:50
* - * @author Bool - * @version + * @author Bool // 作者 + * @version // 版本信息 */ -public class PassInfo { +public class PassInfo { // 定义PassInfo类 - //密码随机串码 - private String salt; + // 密码随机串码 + private String salt; // 声明salt变量 - //MD5后的密码 - private String password; + // MD5后的密码 + private String password; // 声明password变量 - public PassInfo(String salt, String password) { - super(); - this.salt = salt; - this.password = password; + // 构造函数,初始化salt和password + public PassInfo(String salt, String password) { + super(); // 调用父类构造函数 + this.salt = salt; // 设置salt + this.password = password; // 设置password } - public String getSalt() { - return salt; + // 获取salt + public String getSalt() { + return salt; // 返回salt } - public void setSalt(String salt) { - this.salt = salt; + + // 设置salt + public void setSalt(String salt) { + this.salt = salt; // 更新salt } - public String getPassword() { - return password; + + // 获取password + public String getPassword() { + return password; // 返回password } - public void setPassword(String password) { - this.password = password; + + // 设置password + public void setPassword(String password) { + this.password = password; // 更新password } -} - +} \ No newline at end of file