Compare commits

..

No commits in common. 'master' and 'zhangli_branch' have entirely different histories.

@ -1,17 +1,17 @@
package com.yf.exam; // 定义包路径
package com.yf.exam;
import com.yf.exam.core.api.utils.JsonConverter; // 导入JsonConverter工具类
import lombok.extern.log4j.Log4j2; // 导入log4j2日志工具
import org.springframework.boot.SpringApplication; // 导入Spring Boot的SpringApplication类
import org.springframework.boot.autoconfigure.SpringBootApplication; // 导入SpringBoot应用的启动注解
import org.springframework.context.ConfigurableApplicationContext; // 导入Spring上下文配置类
import org.springframework.core.env.Environment; // 导入Spring环境配置类
import org.springframework.http.converter.HttpMessageConverter; // 导入HTTP消息转换器接口
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; // 导入Web MVC配置接口
import com.yf.exam.core.api.utils.JsonConverter;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.net.InetAddress; // 导入InetAddress类用于获取IP地址
import java.net.UnknownHostException; // 导入UnknownHostException异常类
import java.util.List; // 导入List集合类
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
/**
* 线
@ -19,28 +19,23 @@ import java.util.List; // 导入List集合类
* @email 18365918@qq.com
* @date 2020-03-04 19:41
*/
@Log4j2 // 使用log4j2进行日志记录
@SpringBootApplication // 声明一个Spring Boot应用程序
public class ExamApplication implements WebMvcConfigurer { // 实现WebMvcConfigurer接口定制MVC配置
@Log4j2
@SpringBootApplication
public class ExamApplication implements WebMvcConfigurer {
public static void main(String[] args) throws UnknownHostException { // 主方法,应用程序入口
// 启动Spring Boot应用获取应用上下文
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext application = SpringApplication.run(ExamApplication.class, args);
// 获取环境配置信息
Environment env = application.getEnvironment();
// 获取本机IP地址
String ip = InetAddress.getLocalHost().getHostAddress();
// 获取端口号
String port = env.getProperty("server.port");
// 获取上下文路径
String path = env.getProperty("server.servlet.context-path");
// 如果没有配置路径,则默认为空字符串
// 未配置默认空白
if(path == null){
path = "";
}
// 输出启动信息到日志
log.info("\n----------------------------------------------------------\n\t" +
"云帆考试系统启动成功,访问路径如下:\n\t" +
"本地路径: \t\thttp://localhost:" + port + path + "/\n\t" +
@ -50,8 +45,9 @@ public class ExamApplication implements WebMvcConfigurer { // 实现WebMvcConfi
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) { // 扩展Spring MVC的消息转换器
// 保留原有的消息转换器将新的fastConverter插入到集合的头部确保其优先级
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
//保留原有converter,把新增fastConverter插入集合头,保证优先级
converters.add(0, JsonConverter.fastConverter());
}
}

@ -1,22 +1,21 @@
// 文件路径: 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 包
package com.yf.exam.core.annon;
import java.lang.annotation.ElementType; // 导入 ElementType 类,用于指定注解可以应用于的元素类型
import java.lang.annotation.Retention; // 导入 Retention 类,用于指定注解的保留策略
import java.lang.annotation.RetentionPolicy; // 导入 RetentionPolicy 类,定义注解的保留策略
import java.lang.annotation.Target; // 导入 Target 类,用于指定注解的适用范围
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
*
* @author bool
*/
@Target(ElementType.FIELD) // 指定该注解可以应用于字段(类的属性)
@Retention(RetentionPolicy.RUNTIME) // 指定该注解在运行时仍然可用
public @interface Dict { // 定义一个名为 Dict 的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dict {
String dicCode(); // 定义一个抽象方法 dicCode返回数据字典的代码
String dicCode();
String dicText() default ""; // 定义一个抽象方法 dicText返回数据字典的文本默认为空字符串
String dicText() default "";
String dictTable() default ""; // 定义一个抽象方法 dictTable返回数据字典的表名默认为空字符串
String dictTable() default "";
}

@ -1,63 +1,67 @@
package com.yf.exam.core.api; // 定义包名
package com.yf.exam.core.api;
import lombok.AllArgsConstructor; // 导入Lombok的全参构造器注解
import lombok.NoArgsConstructor; // 导入Lombok的无参构造器注解
import java.io.Serializable; // 导入Serializable接口
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* // 类注释,说明该类的用途
* 使 // 说明枚举命名规则
* @author bool // 作者信息
* @date 2019-06-14 21:15 // 日期信息
*
* 使
* @author bool
* @date 2019-06-14 21:15
*/
@NoArgsConstructor // 生成无参构造器
@AllArgsConstructor // 生成全参构造器
public enum ApiError implements Serializable { // 定义ApiError枚举实现Serializable接口
@NoArgsConstructor
@AllArgsConstructor
public enum ApiError implements Serializable {
/**
*
*/
ERROR_10010001("参数不全或类型错误!"), // 错误码10010001及其对应的消息
ERROR_10010002("您还未登录,请先登录!"), // 错误码10010002及其对应的消息
ERROR_10010003("数据不存在!"), // 错误码10010003及其对应的消息
ERROR_10010012("图形验证码错误!"), // 错误码10010012及其对应的消息
ERROR_10010013("短信验证码错误!"), // 错误码10010013及其对应的消息
ERROR_10010014("不允许重复评论!"), // 错误码10010014及其对应的消息
ERROR_10010001("参数不全或类型错误!"),
ERROR_10010002("您还未登录,请先登录!"),
ERROR_10010003("数据不存在!"),
ERROR_10010012("图形验证码错误!"),
ERROR_10010013("短信验证码错误!"),
ERROR_10010014("不允许重复评论!"),
/**
*
*/
ERROR_20010001("试题被删除,无法继续考试!"), // 错误码20010001及其对应的消息
ERROR_20010002("您有正在进行的考试!"), // 错误码20010002及其对应的消息
ERROR_20010001("试题被删除,无法继续考试!"),
ERROR_20010002("您有正在进行的考试!"),
ERROR_90010001("账号不存在,请确认!"),
ERROR_90010002("账号或密码错误!"),
ERROR_90010003("至少要包含一个角色!"),
ERROR_90010004("管理员账号无法修改!"),
ERROR_90010005("账号被禁用,请联系管理员!"),
ERROR_90010006("活动用户不足,无法开启竞拍!"),
ERROR_90010007("旧密码不正确,请确认!"),
ERROR_90010001("账号不存在,请确认!"), // 错误码90010001及其对应的消息
ERROR_90010002("账号或密码错误!"), // 错误码90010002及其对应的消息
ERROR_90010003("至少要包含一个角色!"), // 错误码90010003及其对应的消息
ERROR_90010004("管理员账号无法修改!"), // 错误码90010004及其对应的消息
ERROR_90010005("账号被禁用,请联系管理员!"), // 错误码90010005及其对应的消息
ERROR_90010006("活动用户不足,无法开启竞拍!"), // 错误码90010006及其对应的消息
ERROR_90010007("旧密码不正确,请确认!"), // 错误码90010007及其对应的消息
ERROR_60000001("数据不存在!"); // 错误码60000001及其对应的消息
ERROR_60000001("数据不存在!");
public String msg; // 定义错误消息字段
public String msg;
/**
* Markdown // 方法注释,说明该方法的用途
* @param args // 参数说明
* Markdown
* @param args
*/
public static void main(String[] args) { // 主方法
for (ApiError e : ApiError.values()) { // 遍历所有ApiError枚举值
System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',"); // 输出错误码和消息
public static void main(String[] args) {
for (ApiError e : ApiError.values()) {
System.out.println("'"+e.name().replace("ERROR_", "")+"':'"+e.msg+"',");
}
}
/**
* // 方法注释,说明该方法的用途
* @return // 返回值说明
*
* @return
*/
public Integer getCode(){ // 获取错误码的方法
return Integer.parseInt(this.name().replace("ERROR_", "")); // 返回去掉"ERROR_"前缀的整数值
public Integer getCode(){
return Integer.parseInt(this.name().replace("ERROR_", ""));
}
}

@ -1,64 +1,64 @@
package com.yf.exam.core.api;
package com.yf.exam.core.api; // 定义包名
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注解
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;
/**
*
* @author bool
* @date 2018/11/20 09:48
*/
@Data // 自动生成getter、setter、toString等方法
@NoArgsConstructor // 自动生成无参构造函数
@ApiModel(value="接口响应", description="接口响应") // Swagger注解描述API模型
public class ApiRest<T>{ // 定义泛型类ApiRest
@Data
@NoArgsConstructor
@ApiModel(value="接口响应", description="接口响应")
public class ApiRest<T>{
/**
*
*/
@ApiModelProperty(value = "响应消息") // Swagger注解描述响应消息属性
private String msg; // 响应消息
@ApiModelProperty(value = "响应消息")
private String msg;
/**
*
*/
@ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true) // Swagger注解描述响应代码属性
private Integer code; // 响应代码
@ApiModelProperty(value = "响应代码,0为成功,1为失败", required = true)
private Integer code;
/**
* body
*/
@ApiModelProperty(value = "响应内容") // Swagger注解描述响应内容属性
protected T data; // 响应内容
@ApiModelProperty(value = "响应内容")
protected T data;
/**
*
* @return
*/
public boolean isSuccess(){ // 判断请求是否成功
return code.equals(0); // 如果响应代码为0返回true
public boolean isSuccess(){
return code.equals(0);
}
/**
*
* @param error
*/
public ApiRest(ServiceException error){ // 构造函数接收ServiceException对象
this.code = error.getCode(); // 设置响应代码
this.msg = error.getMsg(); // 设置响应消息
public ApiRest(ServiceException error){
this.code = error.getCode();
this.msg = error.getMsg();
}
/**
*
* @param error
*/
public ApiRest(ApiError error){ // 构造函数接收ApiError对象
this.code = error.getCode(); // 设置响应代码
this.msg = error.msg; // 设置响应消息
public ApiRest(ApiError error){
this.code = error.getCode();
this.msg = error.msg;
}
}

@ -1,150 +1,154 @@
package com.yf.exam.core.api.controller;
// 导入所需的类
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类用于处理服务异常
import com.yf.exam.core.api.ApiError;
import com.yf.exam.core.api.ApiRest;
import com.yf.exam.core.exception.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 <T>
* @return ApiRest<T> API
* @param code
* @param message
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> message(Integer code, String message, T data){
ApiRest<T> response = new ApiRest<>(); // 创建ApiRest对象
response.setCode(code); // 设置状态码
response.setMsg(message); // 设置消息内容
if(data!=null) { // 如果数据不为空
response.setData(data); // 设置响应数据
ApiRest<T> response = new ApiRest<>();
response.setCode(code);
response.setMsg(message);
if(data!=null) {
response.setData(data);
}
return response; // 返回构造好的响应
return response;
}
/**
*
* @param <T>
* @return ApiRest<T> API
* @param <T>
* @return
*/
protected <T> ApiRest<T> success(){
return message(0, "请求成功!", null); // 调用message方法构造成功响应
return message(0, "请求成功!", null);
}
/**
*
* @param message
* @param data
* @param <T>
* @return ApiRest<T> API
* @param message
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> success(String message, T data){
return message(CODE_SUCCESS, message, data); // 调用message方法构造成功响应
return message(CODE_SUCCESS, message, data);
}
/**
*
* @param data
* @param <T>
* @return ApiRest<T> API
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> success(T data){
return message(CODE_SUCCESS, MSG_SUCCESS, data); // 调用message方法构造成功响应
return message(CODE_SUCCESS, MSG_SUCCESS, data);
}
/**
*
* @param code
* @param message
* @param data
* @param <T>
* @return ApiRest<T> API
* @param code
* @param message
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(Integer code, String message, T data){
return message(code, message, data); // 调用message方法构造失败响应
return message(code, message, data);
}
/**
*
* @param message
* @param data
* @param <T>
* @return ApiRest<T> API
* @param message
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(String message, T data){
return message(CODE_FAILURE, message, data); // 调用message方法构造失败响应
return message(CODE_FAILURE, message, data);
}
/**
*
* @param message
* @return ApiRest<T> API
* @param message
* @return
*/
protected <T> ApiRest<T> failure(String message){
return message(CODE_FAILURE, message, null); // 调用message方法构造失败响应
return message(CODE_FAILURE, message, null);
}
/**
*
* @param data
* @param <T>
* @return ApiRest<T> API
* @param data
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(T data){
return message(CODE_FAILURE, MSG_FAILURE, data); // 调用message方法构造失败响应
return message(CODE_FAILURE, MSG_FAILURE, data);
}
/**
*
* @param <T>
* @return ApiRest<T> API
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(){
return message(CODE_FAILURE, MSG_FAILURE, null); // 调用message方法构造失败响应
return message(CODE_FAILURE, MSG_FAILURE, null);
}
/**
*
* @param error ApiError
* @param data
* @param <T>
* @return ApiRest<T> API
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(ApiError error, T data){
return message(error.getCode(), error.msg, data); // 调用message方法构造失败响应
return message(error.getCode(), error.msg, data);
}
/**
*
* @param ex ServiceException
* @param <T>
* @return ApiRest<T> API
* @param ex
* @param <T>
* @return
*/
protected <T> ApiRest<T> failure(ServiceException ex){
ApiRest<T> apiRest = message(ex.getCode(), ex.getMsg(), null); // 调用message方法构造失败响应
return apiRest; // 返回构造好的响应
ApiRest<T> apiRest = message(ex.getCode(), ex.getMsg(), null);
return apiRest;
}
}

@ -1,10 +1,7 @@
// 包声明,定义该类所在的包
package com.yf.exam.core.api.dto;
// 导入lombok库中的@Data注解用于自动生成getter、setter等方法
import lombok.Data;
// 导入Serializable接口用于对象序列化
import java.io.Serializable;
/**
@ -12,11 +9,7 @@ import java.io.Serializable;
* @author dav
* @date 2019/3/16 15:56
*/
// 使用@Data注解自动生成该类的getter、setter等方法
@Data
// 定义一个名为BaseDTO的公共类实现Serializable接口
public class BaseDTO implements Serializable {
// 该类目前没有任何字段或方法
}

@ -1,28 +1,28 @@
// 文件路径: 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; // 定义包名,表示该类属于哪个包
package com.yf.exam.core.api.dto;
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等方法
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;
/**
* <p>
* ID
* </p>
*
* @author // 类的作者信息
* @since 2019-04-20 12:15 // 类的创建时间
* @author
* @since 2019-04-20 12:15
*/
@Data // 使用Lombok的Data注解自动生成toString、equals、hashCode、getter和setter方法
@ApiModel(value="主键通用请求类", description="主键通用请求类") // Swagger文档中显示的模型信息
public class BaseIdReqDTO extends BaseDTO { // 定义BaseIdReqDTO类继承自BaseDTO
@Data
@ApiModel(value="主键通用请求类", description="主键通用请求类")
public class BaseIdReqDTO extends BaseDTO {
@ApiModelProperty(value = "主键ID", required=true) // Swagger文档中显示的属性信息表示该字段是必需的
private String id; // 定义主键ID字段
@ApiModelProperty(value = "主键ID", required=true)
private String id;
@JsonIgnore
private String userId;
@JsonIgnore // 在序列化时忽略该字段不会被JSON输出
private String userId; // 定义用户ID字段通常用于内部逻辑不需要暴露给外部
}

@ -1,28 +1,26 @@
package com.yf.exam.core.api.dto;
// 导入所需的类
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注解用于生成无参构造函数
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;
/**
* <p>
*
* ID
* </p>
*
* @author
* @since 2019-04-20 12:15
*/
@Data // 自动生成getter、setter、toString、equals和hashCode方法
@ApiModel(value="主键通用响应类", description="主键通用响应类") // Swagger注解描述该类的用途
@AllArgsConstructor // 自动生成全参构造函数
@NoArgsConstructor // 自动生成无参构造函数
public class BaseIdRespDTO extends BaseDTO { // 继承自BaseDTO类
@Data
@ApiModel(value="主键通用响应类", description="主键通用响应类")
@AllArgsConstructor
@NoArgsConstructor
public class BaseIdRespDTO extends BaseDTO {
@ApiModelProperty(value = "主键ID", required=true) // Swagger注解描述id属性
private String id; // 主键ID属性必填
@ApiModelProperty(value = "主键ID", required=true)
private String id;
}

@ -1,26 +1,26 @@
package com.yf.exam.core.api.dto;
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 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 java.util.List; // 导入List类用于定义ID列表
import java.util.List;
/**
* ID
* IDID便API
* @author bool
* @date 2019-08-01 19:07
*/
@Data // Lombok注解自动生成getter、setter、toString等方法
@ApiModel(value="删除参数", description="删除参数") // Swagger注解描述该类的用途
public class BaseIdsReqDTO extends BaseDTO { // 继承自BaseDTO类
@Data
@ApiModel(value="删除参数", description="删除参数")
public class BaseIdsReqDTO extends BaseDTO {
@JsonIgnore // 在序列化时忽略该字段
private String userId; // 用户ID通常用于标识请求的用户
@ApiModelProperty(value = "要删除的ID列表", required = true) // Swagger注解描述该字段
private List<String> ids; // 要删除的ID列表必填项
@JsonIgnore
private String userId;
@ApiModelProperty(value = "要删除的ID列表", required = true)
private List<String> ids;
}

@ -1,32 +1,32 @@
// 文件路径: 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包
package com.yf.exam.core.api.dto;
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 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 java.util.List; // 导入List类用于定义ID列表
import java.util.List;
/**
* <p>
*
* </p>
*
* @author // 类的作者
* @since 2019-04-20 12:15 // 类的创建时间
* @author
* @since 2019-04-20 12:15
*/
@Data // 自动生成getter、setter、toString等方法
@ApiModel(value="通用状态请求类", description="通用状态请求类") // Swagger文档中类的描述
@AllArgsConstructor // 自动生成全参构造函数
@NoArgsConstructor // 自动生成无参构造函数
public class BaseStateReqDTO extends BaseDTO { // 定义BaseStateReqDTO类继承自BaseDTO
@Data
@ApiModel(value="通用状态请求类", description="通用状态请求类")
@AllArgsConstructor
@NoArgsConstructor
public class BaseStateReqDTO extends BaseDTO {
@ApiModelProperty(value = "要修改对象的ID列表", required=true) // Swagger文档中属性的描述表示该属性为必填项
private List<String> ids; // 定义一个ID列表用于存储要修改对象的ID
@ApiModelProperty(value = "通用状态0为正常1为禁用", required=true) // Swagger文档中属性的描述表示该属性为必填项
private Integer state; // 定义一个状态字段0表示正常1表示禁用
@ApiModelProperty(value = "要修改对象的ID列表", required=true)
private List<String> ids;
@ApiModelProperty(value = "通用状态0为正常1为禁用", required=true)
private Integer state;
}

@ -1,44 +1,47 @@
package com.yf.exam.core.api.dto; // 定义包名
package com.yf.exam.core.api.dto;
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
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;
/**
*
* @param <T>
* @param <T>
* @author bool
*/
@ApiModel(value="分页参数", description="分页参数") // Swagger模型注解
@Data // Lombok注解自动生成getter、setter、toString等方法
public class PagingReqDTO<T> { // 定义分页请求DTO类使用泛型T
@ApiModel(value="分页参数", description="分页参数")
@Data
public class PagingReqDTO<T> {
@ApiModelProperty(value = "当前页码", required = true, example = "1") // Swagger属性注解
private Integer current; // 当前页码
@ApiModelProperty(value = "每页数量", required = true, example = "10") // Swagger属性注解
private Integer size; // 每页数量
@ApiModelProperty(value = "当前页码", required = true, example = "1")
private Integer current;
@ApiModelProperty(value = "查询参数") // Swagger属性注解
private T params; // 查询参数类型为泛型T
@ApiModelProperty(value = "每页数量", required = true, example = "10")
private Integer size;
@ApiModelProperty(value = "排序字符") // Swagger属性注解
private String orderBy; // 排序字段
@ApiModelProperty(value = "查询参数")
private T params;
@JsonIgnore // Jackson注解忽略该字段
@ApiModelProperty(value = "当前用户的ID") // Swagger属性注解
private String userId; // 当前用户的ID
@ApiModelProperty(value = "排序字符")
private String orderBy;
@JsonIgnore
@ApiModelProperty(value = "当前用户的ID")
private String userId;
/**
* MyBatis
* @return MyBatisPage
* @return
*/
public Page toPage(){ // 定义转换方法
Page page = new Page(); // 创建Page对象
page.setCurrent(this.current); // 设置当前页码
page.setSize(this.size); // 设置每页数量
return page; // 返回Page对象
public Page toPage(){
Page page = new Page();
page.setCurrent(this.current);
page.setSize(this.size);
return page;
}
}

@ -1,29 +1,29 @@
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 <T>
* @param <T>
*/
public class PagingRespDTO<T> extends Page<T> { // 定义分页响应类继承自Page类
public class PagingRespDTO<T> extends Page<T> {
/**
*
* @return
* @return
*/
@Override
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
public long getPages() {
if (this.getSize() == 0L) {
return 0L;
} else {
long pages = this.getTotal() / this.getSize();
if (this.getTotal() % this.getSize() != 0L) {
++pages;
}
return pages; // 返回总页数
return pages;
}
}

@ -1,48 +1,48 @@
package com.yf.exam.core.api.utils; // 定义包名
package com.yf.exam.core.api.utils;
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 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 java.nio.charset.Charset; // 导入字符集类
import java.util.ArrayList; // 导入ArrayList类
import java.util.List; // 导入List接口
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* JSON
* @author dav
* @date 2018/9/11 19:30
*/
public class JsonConverter { // 定义JsonConverter类
public class JsonConverter {
/**
* FastJson
*
* @return HttpMessageConverter
* @return
*/
public static HttpMessageConverter fastConverter() { // 定义静态方法fastConverter
public static HttpMessageConverter fastConverter() {
// 定义一个convert转换消息的对象
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); // 创建FastJson消息转换器实例
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 添加FastJson的配置信息
FastJsonConfig fastJsonConfig = new FastJsonConfig(); // 创建FastJson配置实例
FastJsonConfig fastJsonConfig = new FastJsonConfig();
// 默认转换器
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
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.MapSortField,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.DisableCircularReferenceDetect,
SerializerFeature.WriteDateUseDateFormat,
SerializerFeature.WriteNullListAsEmpty);
fastJsonConfig.setCharset(Charset.forName("UTF-8"));
// 处理中文乱码问题
List<MediaType> fastMediaTypes = new ArrayList<>(); // 创建媒体类型列表
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); // 添加支持的媒体类型UTF-8 JSON
fastConverter.setSupportedMediaTypes(fastMediaTypes); // 设置支持的媒体类型
List<MediaType> fastMediaTypes = new ArrayList<>();
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
fastConverter.setSupportedMediaTypes(fastMediaTypes);
// 在convert中添加配置信息
fastConverter.setFastJsonConfig(fastJsonConfig); // 设置FastJson配置
fastConverter.setFastJsonConfig(fastJsonConfig);
return fastConverter; // 返回FastJson消息转换器
} // 结束fastConverter方法
} // 结束JsonConverter类
return fastConverter;
}
}

@ -1,21 +1,19 @@
// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/enums/CommonState.java
package com.yf.exam.core.enums; // 定义包名
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; // 定义正常状态的常量值为0
Integer NORMAL = 0;
/**
*
*/
Integer ABNORMAL = 1; // 定义非正常状态的常量值为1
Integer ABNORMAL = 1;
}

@ -1,19 +1,18 @@
// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/enums/OpenType.java
package com.yf.exam.core.enums; // 定义包名
package com.yf.exam.core.enums;
/**
*
* @author bool
*/
public interface OpenType { // 定义接口 OpenType
public interface OpenType {
/**
*
*/
Integer OPEN = 1; // 定义常量 OPEN值为 1
Integer OPEN = 1;
/**
*
*/
Integer DEPT_OPEN = 2; // 定义常量 DEPT_OPEN值为 2
Integer DEPT_OPEN = 2;
}

@ -1,52 +1,51 @@
// 文件路径: yfexam-exam-main/yfexam-exam-main/exam-api/src/main/java/com/yf/exam/core/exception/ServiceException.java
package com.yf.exam.core.exception; // 定义包名
package com.yf.exam.core.exception;
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注解
import com.yf.exam.core.api.ApiError;
import com.yf.exam.core.api.ApiRest;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data // 自动生成getter、setter、toString等方法
@AllArgsConstructor // 生成包含所有字段的构造函数
@NoArgsConstructor // 生成无参构造函数
public class ServiceException extends RuntimeException{ // 定义ServiceException类继承RuntimeException
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ServiceException extends RuntimeException{
/**
*
*/
private Integer code; // 定义错误码字段
private Integer code;
/**
*
*/
private String msg; // 定义错误消息字段
private String msg;
/**
*
* @param apiRest
*/
public ServiceException(ApiRest apiRest){ // 构造函数接受ApiRest对象
this.code = apiRest.getCode(); // 初始化错误码
this.msg = apiRest.getMsg(); // 初始化错误消息
public ServiceException(ApiRest apiRest){
this.code = apiRest.getCode();
this.msg = apiRest.getMsg();
}
/**
*
* @param apiError
*/
public ServiceException(ApiError apiError){ // 构造函数接受ApiError对象
this.code = apiError.getCode(); // 初始化错误码
this.msg = apiError.msg; // 初始化错误消息
public ServiceException(ApiError apiError){
this.code = apiError.getCode();
this.msg = apiError.msg;
}
/**
*
* @param msg
*/
public ServiceException(String msg){ // 构造函数,接受错误消息
this.code = 1; // 默认错误码为1
this.msg = msg; // 初始化错误消息
public ServiceException(String msg){
this.code = 1;
this.msg = msg;
}
}

@ -1,46 +1,46 @@
package com.yf.exam.core.exception; // 定义包名
package com.yf.exam.core.exception;
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.*; // 导入所有注解
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.*;
/**
*
* @author bool
* @date 2019-06-21 19:27
*/
@RestControllerAdvice // 声明这是一个全局异常处理类
public class ServiceExceptionHandler { // 定义ServiceExceptionHandler类
@RestControllerAdvice
public class 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 ApiRest API
* @param e
* @return
*/
@ExceptionHandler({com.yf.exam.core.exception.ServiceException.class}) // 指定捕获的异常类型
@ResponseStatus(HttpStatus.OK) // 设置响应状态为200 OK
public ApiRest serviceExceptionHandler(ServiceException e) { // 定义异常处理方法
return new ApiRest(e); // 返回ApiRest对象包含异常信息
@ExceptionHandler({com.yf.exam.core.exception.ServiceException.class})
@ResponseStatus(HttpStatus.OK)
public ApiRest serviceExceptionHandler(ServiceException e) {
return new ApiRest(e);
}
}

@ -1,12 +1,13 @@
package com.yf.exam.core.utils; // 定义包名
package com.yf.exam.core.utils;
import org.dozer.DozerBeanMapper; // 导入DozerBeanMapper类
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 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<->BeanMapper.:
@ -17,42 +18,42 @@ import java.util.stream.Collectors; // 导入Collectors类
* 4. BAB.
*
*/
public class BeanMapper { // 定义BeanMapper类
public class BeanMapper {
/**
* Dozer, DozerMapper.
*/
private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper(); // 创建DozerBeanMapper的单例
private static DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
/**
* Dozer.
*/
public static <T> T map(Object source, Class<T> destinationClass) { // 定义map方法转换对象类型
return dozerBeanMapper.map(source, destinationClass); // 使用Dozer进行对象转换
public static <T> T map(Object source, Class<T> destinationClass) {
return dozerBeanMapper.map(source, destinationClass);
}
/**
* DozerCollection.
*/
public static <T> List<T> mapList(Iterable<?> sourceList, Class<T> destinationClass) { // 定义mapList方法转换集合中的对象
List<T> destinationList = new ArrayList(); // 创建目标列表
for (Object sourceObject : sourceList) { // 遍历源列表中的每个对象
T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass); // 转换对象
destinationList.add(destinationObject); // 将转换后的对象添加到目标列表
public static <T> List<T> mapList(Iterable<?> sourceList, Class<T> destinationClass) {
List<T> destinationList = new ArrayList();
for (Object sourceObject : sourceList) {
T destinationObject = dozerBeanMapper.map(sourceObject, destinationClass);
destinationList.add(destinationObject);
}
return destinationList; // 返回目标列表
return destinationList;
}
/**
* DozerAB.
*/
public static void copy(Object source, Object destinationObject) { // 定义copy方法拷贝对象A的值到对象B
if(source!=null) { // 检查源对象是否为null
dozerBeanMapper.map(source, destinationObject); // 使用Dozer进行值拷贝
public static void copy(Object source, Object destinationObject) {
if(source!=null) {
dozerBeanMapper.map(source, destinationObject);
}
}
public static <T, S> List<T> mapList(Collection<S> source, Function<? super S, ? extends T> mapper) { // 定义重载的mapList方法使用自定义映射函数
return source.stream().map(mapper).collect(Collectors.toList()); // 使用流和映射函数转换集合并返回列表
public static <T, S> List<T> mapList(Collection<S> source, Function<? super S, ? extends T> mapper) {
return source.stream().map(mapper).collect(Collectors.toList());
}
}

@ -1,32 +1,31 @@
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; // 包声明,定义了类的包路径
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 { // 定义CronUtils类
public class 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 // 返回格式化后的cron表达式
* @param date
* @return
*/
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); // 格式化日期
public static String dateToCron(final Date date){
SimpleDateFormat fmt = new SimpleDateFormat(DATE_FORMAT);
String formatTimeStr = "";
if (date != null) {
formatTimeStr = fmt.format(date);
}
return formatTimeStr; // 返回格式化后的字符串
return formatTimeStr;
}
}

@ -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 { // 定义DateUtils类
public class DateUtils {
/**
*
* calcExpDays: <br/>
* @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,34 +42,36 @@ public class DateUtils { // 定义DateUtils类
* dateNow:. <br/>
* @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: <br/>
* @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");
}
@ -77,23 +79,25 @@ public class DateUtils { // 定义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; // 返回null表示解析失败
return null;
}
}

@ -1,6 +1,7 @@
package com.yf.exam.core.utils; // 定义包名
package com.yf.exam.core.utils;
import javax.servlet.http.HttpServletRequest; // 导入HttpServletRequest类
import javax.servlet.http.HttpServletRequest;
/**
* IPIP
@ -10,52 +11,55 @@ import javax.servlet.http.HttpServletRequest; // 导入HttpServletRequest类
* @author Bool
* @version
*/
public class IpUtils { // 定义IpUtils类
public class IpUtils {
/**
*
* getClientIp:IP
* @author Bool
* @param request HttpServletRequest
* @return IP
* @param request
* @return
*/
public static String extractClientIp(HttpServletRequest request) { // 定义静态方法extractClientIp接收HttpServletRequest参数
public static String extractClientIp(HttpServletRequest request) {
String ip = null; // 初始化ip变量为null
String ip = null;
//X-Forwarded-ForSquid 服务代理
String ipAddresses = request.getHeader("X-Forwarded-For"); // 获取请求头中的X-Forwarded-For字段
String ipAddresses = request.getHeader("X-Forwarded-For");
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//Proxy-Client-IPapache 服务代理
ipAddresses = request.getHeader("Proxy-Client-IP"); // 获取Proxy-Client-IP字段
ipAddresses = request.getHeader("Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//WL-Proxy-Client-IPweblogic 服务代理
ipAddresses = request.getHeader("WL-Proxy-Client-IP"); // 获取WL-Proxy-Client-IP字段
ipAddresses = request.getHeader("WL-Proxy-Client-IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//HTTP_CLIENT_IP有些代理服务器
ipAddresses = request.getHeader("HTTP_CLIENT_IP"); // 获取HTTP_CLIENT_IP字段
ipAddresses = request.getHeader("HTTP_CLIENT_IP");
}
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ipAddresses是否为空或未知
if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
//X-Real-IPnginx服务代理
ipAddresses = request.getHeader("X-Real-IP"); // 获取X-Real-IP字段
ipAddresses = request.getHeader("X-Real-IP");
}
//有些网络通过多层代理那么获取到的ip就会有多个一般都是通过逗号,分割开来并且第一个ip为客户端的真实IP
if (ipAddresses != null && ipAddresses.length() != 0) { // 检查ipAddresses是否不为空
ip = ipAddresses.split(",")[0]; // 通过逗号分割并获取第一个IP地址
if (ipAddresses != null && ipAddresses.length() != 0) {
ip = ipAddresses.split(",")[0];
}
//还是不能获取到最后再通过request.getRemoteAddr();获取
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) { // 检查ip是否为空或未知
ip = request.getRemoteAddr(); // 最后通过getRemoteAddr获取IP地址
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
ip = request.getRemoteAddr();
}
return ip; // 返回获取到的IP地址
return ip;
}
}

@ -1,22 +1,22 @@
/**
* Copyright (c) 2005-2012 springside.org.cn
*/
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接口
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;
/**
* .
@ -24,32 +24,32 @@ import java.util.List; // 引入List接口
* @author calvin
* @version 2016-01-15
*/
@Log4j2 // 使用Log4j2注解
public class Reflections { // 定义Reflections类
@Log4j2
public class Reflections {
private static final String SETTER_PREFIX = "set"; // 定义setter方法前缀
private static final String SETTER_PREFIX = "set";
private static final String GETTER_PREFIX = "get"; // 定义getter方法前缀
private static final String GETTER_PREFIX = "get";
private static final String CGLIB_CLASS_SEPARATOR = "$$"; // 定义CGLIB类分隔符
private static final String CGLIB_CLASS_SEPARATOR = "$$";
/**
*
*
* @param object
* @return
* @param object
* @return
*/
public static Field[] getAllFields(Object object) { // 定义获取所有字段的方法
Class<?> clazz = object.getClass(); // 获取对象的类
List<Field> 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<Field> 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 { // 定义Reflections类
* Getter.
* ..
*/
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方法
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[] {});
}
return object; // 返回结果
return object;
}
/**
* Setter,
* ..
*/
public static void invokeSetter(Object obj, String propertyName, Object value) { // 定义调用setter方法
Object object = obj; // 初始化对象
String[] names = StringUtils.split(propertyName, "."); // 分割属性名
for (int i=0; i<names.length; i++){ // 遍历属性名
if(i<names.length-1){ // 如果不是最后一个属性
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]); // 生成getter方法名
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {}); // 调用getter方法
}else{ // 如果是最后一个属性
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]); // 生成setter方法名
invokeMethodByName(object, setterMethodName, new Object[] { value }); // 调用setter方法
public static void invokeSetter(Object obj, String propertyName, Object value) {
Object object = obj;
String[] names = StringUtils.split(propertyName, ".");
for (int i=0; i<names.length; i++){
if(i<names.length-1){
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
}else{
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
invokeMethodByName(object, setterMethodName, new Object[] { value });
}
}
}
@ -87,36 +87,36 @@ public class Reflections { // 定义Reflections类
/**
* , private/protected, getter.
*/
public static Object getFieldValue(final Object obj, final String fieldName) { // 定义获取字段值的方法
Field field = getAccessibleField(obj, fieldName); // 获取可访问的字段
public static Object getFieldValue(final Object obj, final String fieldName) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) { // 如果字段不存在
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); // 抛出异常
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
Object result = null; // 初始化结果
Object result = null;
try {
result = field.get(obj); // 获取字段值
} catch (IllegalAccessException e) { // 捕获非法访问异常
log.error("不可能抛出的异常{}", e.getMessage()); // 记录错误
result = field.get(obj);
} catch (IllegalAccessException e) {
log.error("不可能抛出的异常{}", e.getMessage());
}
return result; // 返回结果
return result;
}
/**
* , private/protected, setter.
*/
public static void setFieldValue(final Object obj, final String fieldName, final Object value) { // 定义设置字段值的方法
Field field = getAccessibleField(obj, fieldName); // 获取可访问的字段
public static void setFieldValue(final Object obj, final String fieldName, final Object value) {
Field field = getAccessibleField(obj, fieldName);
if (field == null) { // 如果字段不存在
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]"); // 抛出异常
if (field == null) {
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + obj + "]");
}
try {
field.set(obj, value); // 设置字段值
} catch (IllegalAccessException e) { // 捕获非法访问异常
log.error("不可能抛出的异常:{}", e.getMessage()); // 记录错误
field.set(obj, value);
} catch (IllegalAccessException e) {
log.error("不可能抛出的异常:{}", e.getMessage());
}
}
@ -126,16 +126,16 @@ public class Reflections { // 定义Reflections类
* +
*/
public static Object invokeMethod(final Object obj, final String methodName, final Class<?>[] 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 { // 定义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 { // 定义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) { // 捕获没有该字段的异常
Field field = superClass.getDeclaredField(fieldName);
makeAccessible(field);
return field;
} catch (NoSuchFieldException e) {//NOSONAR
// Field不在当前类定义,继续向上转型
continue; // 继续循环
continue;// new add
}
}
return null; // 返回null
return null;
}
/**
@ -186,21 +186,21 @@ public class Reflections { // 定义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; // 继续循环
continue;// new add
}
}
return null; // 返回null
return null;
}
/**
@ -210,39 +210,39 @@ public class Reflections { // 定义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"); // 验证方法名不为空
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; // 返回方法
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; // 返回null
return null;
}
/**
* private/protectedpublicJDKSecurityManager
*/
public static void makeAccessible(Method method) { // 定义设置方法为可访问的方法
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) // 如果方法或类不是public
&& !method.isAccessible()) { // 且方法不可访问
method.setAccessible(true); // 设置为可访问
public static void makeAccessible(Method method) {
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
&& !method.isAccessible()) {
method.setAccessible(true);
}
}
/**
* private/protectedpublicJDKSecurityManager
*/
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); // 设置为可访问
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);
}
}
@ -256,8 +256,8 @@ public class Reflections { // 定义Reflections类
* @return the first generic declaration, or Object.class if cannot be determined
*/
@SuppressWarnings("unchecked")
public static <T> Class<T> getClassGenricType(final Class clazz) { // 定义获取类的泛型类型的方法
return getClassGenricType(clazz, 0); // 调用重载方法
public static <T> Class<T> getClassGenricType(final Class clazz) {
return getClassGenricType(clazz, 0);
}
/**
@ -270,54 +270,55 @@ public class Reflections { // 定义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) { // 定义获取类的泛型类型的方法
Type genType = clazz.getGenericSuperclass(); // 获取类的泛型超类
public static Class getClassGenricType(final Class clazz, final int index) {
if (!(genType instanceof ParameterizedType)) { // 如果不是参数化类型
log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType"); // 记录警告
return Object.class; // 返回Object.class
Type genType = clazz.getGenericSuperclass();
if (!(genType instanceof ParameterizedType)) {
log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
return 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; // 返回Object.class
+ params.length);
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
if (!(params[index] instanceof Class)) {
log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
return Object.class;
}
return (Class) params[index]; // 返回指定索引的Class类型
return (Class) params[index];
}
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; // 返回父类
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;
}
}
return clazz; // 返回当前类
return clazz;
}
/**
* checked exceptionunchecked 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; // 返回运行时异常
}
return new RuntimeException("Unexpected Checked Exception.", 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);
}
}

@ -1,33 +1,32 @@
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; // 定义包名
package com.yf.exam.core.utils;
import org.springframework.beans.BeansException; // 导入BeansException类
import org.springframework.context.ApplicationContext; // 导入ApplicationContext接口
import org.springframework.context.ApplicationContextAware; // 导入ApplicationContextAware接口
import org.springframework.stereotype.Component; // 导入Component注解
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring
*
* @author bool // 作者信息
* @date 2019-12-09 15:55 // 日期信息
* @author bool
* @date 2019-12-09 15:55
*/
@Component // 将该类标记为Spring组件
public class SpringUtils implements ApplicationContextAware { // 定义SpringUtils类并实现ApplicationContextAware接口
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext; // 静态变量用于存储ApplicationContext
private static ApplicationContext applicationContext;
@Override // 重写setApplicationContext方法
public void setApplicationContext(ApplicationContext context) throws BeansException { // 设置ApplicationContext
applicationContext = context; // 将传入的context赋值给静态变量
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
public static <T> T getBean(Class<T> tClass) { // 泛型方法根据类获取Bean
return applicationContext.getBean(tClass); // 从ApplicationContext中获取指定类型的Bean
public static <T> T getBean(Class<T> tClass) {
return applicationContext.getBean(tClass);
}
public static <T> T getBean(String name, Class<T> type) { // 泛型方法根据名称和类型获取Bean
return applicationContext.getBean(name, type); // 从ApplicationContext中获取指定名称和类型的Bean
public static <T> T getBean(String name, Class<T> type) {
return applicationContext.getBean(name, type);
}
}

@ -1,38 +1,39 @@
package com.yf.exam.core.utils; // 定义包名
package com.yf.exam.core.utils;
import java.util.Map; // 导入Map类
import java.util.Map;
/**
*
* @author bool
* @date 2019-05-15 11:40
*/
public class StringUtils { // 定义StringUtils类
public class StringUtils {
/**
*
* @param str
* @return nulltruefalse
* @param str
* @return
*/
public static boolean isBlank(String str){ // 定义静态方法isBlank
return str==null || "".equals(str); // 检查字符串是否为null或空
public static boolean isBlank(String str){
return str==null || "".equals(str);
}
/**
* MAPxml<xml><key>value</key>...</xml>
* @param params Map
* @return xml
* @param params
* @return
*/
public static String mapToXml(Map<String, String> params){ // 定义静态方法mapToXml
StringBuffer sb = new StringBuffer("<xml>"); // 创建StringBuffer并初始化为<xml>
for(String key:params.keySet()){ // 遍历Map中的每个key
sb.append("<") // 添加开始标签
.append(key).append(">") // 添加key
.append(params.get(key)) // 添加对应的value
.append("</").append(key).append(">"); // 添加结束标签
public static String mapToXml(Map<String, String> params){
StringBuffer sb = new StringBuffer("<xml>");
for(String key:params.keySet()){
sb.append("<")
.append(key).append(">")
.append(params.get(key))
.append("</").append(key).append(">");
}
sb.append("</xml>"); // 添加结束的</xml>标签
return sb.toString(); // 返回构建的xml字符串
sb.append("</xml>");
return sb.toString();
}
}

@ -1,83 +1,82 @@
/**
* Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
*/
package com.yf.exam.core.utils.excel; // 包声明
package com.yf.exam.core.utils.excel;
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 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 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接口
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;
/**
* ExcelXLSX @see org.apache.poi.ss.SpreadsheetVersion
* @author jeeplus
* @version 2016-04-21
*/
public class ExportExcel { // ExportExcel类定义
public class 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<String, CellStyle> styles; // 样式列表
private Map<String, CellStyle> styles;
/**
*
*/
private int rownum; // 当前行号
private int rownum;
/**
* Object[]{ ExcelField, Field/Method }
*/
List<Object[]> annotationList = Lists.newArrayList(); // 注解列表
List<Object[]> 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);
}
/**
@ -87,123 +86,123 @@ public class ExportExcel { // 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); // 获取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; // 退出循环
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;
}
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); // 获取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; // 退出循环
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;
}
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<Object[]>() { // 对注解列表进行排序
Collections.sort(annotationList, new Comparator<Object[]>() {
@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<String> headerList = Lists.newArrayList(); // 初始化表头列表
for (Object[] os : annotationList){ // 遍历注解列表
String t = ((ExcelField)os[0]).title(); // 获取标题
List<String> 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<String> headerList) { // 初始化方法
this.wb = new SXSSFWorkbook(500); // 创建工作薄
this.sheet = wb.createSheet("Export"); // 创建工作表
this.styles = createStyles(wb); // 创建样式
private void initialize(String title, List<String> 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!"); // 抛出异常
}
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( // 创建注释
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(
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.");
}
/**
@ -211,73 +210,73 @@ public class ExportExcel { // ExportExcel类定义
* @param wb
* @return
*/
private Map<String, CellStyle> createStyles(Workbook wb) { // 创建样式方法
Map<String, CellStyle> styles = new HashMap<>(16); // 初始化样式列表
private Map<String, CellStyle> createStyles(Workbook wb) {
Map<String, CellStyle> 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++);
}
@ -288,8 +287,8 @@ public class ExportExcel { // 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);
}
/**
@ -300,104 +299,104 @@ public class ExportExcel { // ExportExcel类定义
* @param align 123
* @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){ // 如果值为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
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{
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 <E> ExportExcel setDataList(List<E> 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 = ""; // 设置值为空字符串
}
this.addCell(row, colunm++, val, ef.align(), ef.fieldType()); // 添加单元格
sb.append(val + ", "); // 添加值到字符串构建器
}
log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString()); // 记录写入成功日志
}
return this; // 返回当前对象
public <E> ExportExcel setDataList(List<E> 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[] {});
}
}
}catch(Exception ex) {
log.info(ex.toString());
val = "";
}
this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
sb.append(val + ", ");
}
log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString());
}
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;
}
}

@ -1,58 +1,59 @@
/**
* Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
*/
package com.yf.exam.core.utils.excel; // 定义包名
package com.yf.exam.core.utils.excel;
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 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 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接口表示列表
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;
/**
* ExcelXLSXLSX
* @author jeeplus
* @version 2016-03-10
*/
public class ImportExcel { // 定义ImportExcel类
public class 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;
/**
@ -64,8 +65,8 @@ public class ImportExcel { // 定义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);
}
/**
@ -77,22 +78,22 @@ public class ImportExcel { // 定义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); // 创建HSSFWorkbook对象
throws IOException {
if (StringUtils.isBlank(fileName)){
throw new RuntimeException("导入文档为空!");
}else if(fileName.toLowerCase().endsWith("xls")){
this.wb = new HSSFWorkbook(is);
}else if(fileName.toLowerCase().endsWith("xlsx")){
this.wb = new XSSFWorkbook(is); // 创建XSSFWorkbook对象
this.wb = new XSSFWorkbook(is);
}else{
throw new RuntimeException("文档格式不正确!"); // 抛出异常
throw new RuntimeException("文档格式不正确!");
}
if (this.wb.getNumberOfSheets()<sheetIndex){ // 检查工作表索引是否有效
throw new RuntimeException("文档中没有工作表!"); // 抛出异常
if (this.wb.getNumberOfSheets()<sheetIndex){
throw new RuntimeException("文档中没有工作表!");
}
this.sheet = this.wb.getSheetAt(sheetIndex); // 获取指定的工作表
this.headerNum = headerNum; // 设置标题行号
log.debug("Initialize success."); // 记录初始化成功的日志
this.sheet = this.wb.getSheetAt(sheetIndex);
this.headerNum = headerNum;
log.debug("Initialize success.");
}
/**
@ -100,24 +101,24 @@ public class ImportExcel { // 定义ImportExcel类
* @param rownum
* @return
*/
public Row getRow(int rownum){ // 获取指定行
return this.sheet.getRow(rownum); // 返回行对象
public Row getRow(int rownum){
return this.sheet.getRow(rownum);
}
/**
*
* @return
*/
public int getDataRowNum(){ // 获取数据行号
return headerNum+1; // 返回标题行号加一
public int getDataRowNum(){
return headerNum+1;
}
/**
*
* @return
*/
public int getLastDataRowNum(){ // 获取最后一个数据行号
return this.sheet.getLastRowNum()+headerNum; // 返回最后一行号加标题行号
public int getLastDataRowNum(){
return this.sheet.getLastRowNum()+headerNum;
}
@ -127,37 +128,38 @@ public class ImportExcel { // 定义ImportExcel类
* @param column
* @return
*/
public Object getCellValue(Row row, int column) { // 获取指定单元格的值
Object val = ""; // 初始化单元格值
public Object getCellValue(Row row, int column) {
Object val = "";
try {
Cell cell = row.getCell(column); // 获取单元格
if (cell != null) { // 检查单元格是否为空
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) { // 检查单元格类型
Cell cell = row.getCell(column);
if (cell != null) {
if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
// 当excel 中的数据为数值或日期是需要特殊处理
if (HSSFDateUtil.isCellDateFormatted(cell)) { // 检查是否为日期格式
double d = cell.getNumericCellValue(); // 获取数值
Date date = HSSFDateUtil.getJavaDate(d); // 转换为Java日期
SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd"); // 定义日期格式
val = dformat.format(date); // 格式化日期
if (HSSFDateUtil.isCellDateFormatted(cell)) {
double d = cell.getNumericCellValue();
Date date = HSSFDateUtil.getJavaDate(d);
SimpleDateFormat dformat = new SimpleDateFormat(
"yyyy-MM-dd");
val = dformat.format(date);
} else {
NumberFormat nf = NumberFormat.getInstance(); // 获取数字格式化实例
nf.setGroupingUsed(false); // 设置不使用分组
val = nf.format(cell.getNumericCellValue()); // 格式化数值
NumberFormat nf = NumberFormat.getInstance();
nf.setGroupingUsed(false);// true时的格式1,234,567,890
val = nf.format(cell.getNumericCellValue());// 数值类型的数据为double所以需要转换一下
}
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) { // 检查是否为字符串类型
val = cell.getStringCellValue(); // 获取字符串值
} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) { // 检查是否为公式类型
val = cell.getCellFormula(); // 获取公式
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) { // 检查是否为布尔类型
val = cell.getBooleanCellValue(); // 获取布尔值
} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) { // 检查是否为错误类型
val = cell.getErrorCellValue(); // 获取错误值
} else if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
val = cell.getStringCellValue();
} else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
val = cell.getCellFormula();
} else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
val = cell.getBooleanCellValue();
} else if (cell.getCellType() == Cell.CELL_TYPE_ERROR) {
val = cell.getErrorCellValue();
}
}
} catch (Exception e) { // 捕获异常
return val; // 返回值
} catch (Exception e) {
return val;
}
return val; // 返回单元格值
return val;
}
/**
@ -165,137 +167,137 @@ public class ImportExcel { // 定义ImportExcel类
* @param cls
* @param groups
*/
public <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{ // 获取导入数据列表
List<Object[]> annotationList = Lists.newArrayList(); // 创建注解列表
public <E> List<E> getDataList(Class<E> cls, int... groups) throws InstantiationException, IllegalAccessException{
List<Object[]> annotationList = Lists.newArrayList();
// Get annotation field
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; // 跳出循环
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;
}
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); // 获取方法上的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; // 跳出循环
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;
}
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<Object[]>() { // 对注解列表进行排序
Collections.sort(annotationList, new Comparator<Object[]>() {
@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<E> 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注解
List<E> 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];
// 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")){ // 检查是否以.0结尾
val = StringUtils.substringBefore(s, ".0"); // 去掉.0
if (valType == String.class){
String s = String.valueOf(val.toString());
if(StringUtils.endsWith(s, ".0")){
val = StringUtils.substringBefore(s, ".0");
}else{
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()); // 解析日期
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 (ef.fieldType() != Class.class){ // 检查字段类型
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString()); // 调用getValue方法
if (ef.fieldType() != Class.class){
val = ef.fieldType().getMethod("getValue", String.class).invoke(null, val.toString());
}else{
val = Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(),
"fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString()); // 动态调用getValue方法
"fieldtype."+valType.getSimpleName()+"Type")).getMethod("getValue", String.class).invoke(null, val.toString());
}
}
} catch (Exception ex) { // 捕获异常
log.info("Get cell value ["+i+","+column+"] error: " + ex.toString()); // 记录错误日志
val = null; // 设置值为null
} catch (Exception ex) {
log.info("Get cell value ["+i+","+column+"] error: " + ex.toString());
val = 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"); // 转换为set方法名
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");
}
Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val}); // 调用set方法
Reflections.invokeMethod(e, mthodName, new Class[] {valType}, new Object[] {val});
}
}
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;
}
}

@ -1,87 +1,59 @@
// ... existing code ...
/**
* Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> 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.nameoffice.name
*
*/
String value() default "";
// 字段名,默认为空字符串
/**
* ****
*
*/
String title();
// 字段标题,必填项
/**
* 012
*
*/
int type() default 0;
// 字段类型默认为0导出导入
/**
* 0123
*
*/
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 ...

@ -1,57 +1,56 @@
/**
* Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> 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; // 导入Google的Lists工具类
import com.yf.exam.core.utils.StringUtils; // 导入自定义的StringUtils工具类
import com.google.common.collect.Lists;
import com.yf.exam.core.utils.StringUtils;
import java.util.List; // 导入List接口
import java.util.List;
/**
*
* @author jeeplus
* @version 2016-5-29
*/
public class ListType { // 定义ListType类
public class ListType {
/**
*
*/
public static Object getValue(String val) { // 定义静态方法getValue接收一个字符串参数
List<String> list = Lists.newArrayList(); // 创建一个新的字符串列表
if(!StringUtils.isBlank(val)) { // 检查输入字符串是否为空
for (String s : val.split(",")) { // 按逗号分割字符串
list.add(s); // 将分割后的字符串添加到列表中
public static Object getValue(String val) {
List<String> 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) { // 定义静态方法setValue接收一个对象参数
if (val != null){ // 检查输入对象是否为null
List<String> list = (List<String>)val; // 将对象强制转换为字符串列表
StringBuffer sb = null; // 初始化字符串缓冲区
for (String item: list){ // 遍历列表中的每个字符串
if(StringUtils.isBlank(item)){ // 检查字符串是否为空
continue; // 如果为空,跳过当前循环
}
if(sb == null){ // 如果字符串缓冲区为空
sb = new StringBuffer(item); // 初始化缓冲区为当前字符串
public static String setValue(Object val) {
if (val != null){
List<String> list = (List<String>)val;
StringBuffer sb = null;
for (String item: list){
if(StringUtils.isBlank(item)){
continue;
}
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 ""; // 如果输入对象为null返回空字符串
return "";
}
}

@ -1,6 +1,7 @@
package com.yf.exam.core.utils.file; // 包声明
package com.yf.exam.core.utils.file;
import java.security.MessageDigest;
import java.security.MessageDigest; // 导入MessageDigest类用于生成MD5哈希
/**
* MD5
@ -10,25 +11,26 @@ import java.security.MessageDigest; // 导入MessageDigest类用于生成MD5
* @author Bool
* @version
*/
public class Md5Util { // 定义MD5工具类
public class Md5Util {
/**
* MD5
* @param str
* @return MD5
* @param str
* @return
*/
public static String md5(String str) { // 定义静态方法md5接受一个字符串参数
public static String md5(String str) {
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
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));
}
return sb.toString(); // 返回最终的MD5哈希字符串
}catch(Exception e) { // 捕获异常
return null; // 如果发生异常返回null
return sb.toString();
}catch(Exception e) {
return null;
}
}

@ -1,7 +1,8 @@
package com.yf.exam.core.utils.passwd; // 定义包名
package com.yf.exam.core.utils.passwd;
import com.yf.exam.core.utils.file.Md5Util; // 导入Md5Util类
import org.apache.commons.lang3.RandomStringUtils; // 导入RandomStringUtils类
import com.yf.exam.core.utils.file.Md5Util;
import org.apache.commons.lang3.RandomStringUtils;
/**
*
@ -11,7 +12,7 @@ import org.apache.commons.lang3.RandomStringUtils; // 导入RandomStringUtils类
* @author Bool
* @version
*/
public class PassHandler { // 定义PassHandler类
public class PassHandler {
/**
* checkPass:
@ -21,9 +22,9 @@ public class PassHandler { // 定义PassHandler类
* @param pass MD5
* @return
*/
public static boolean checkPass(String inputPass , String salt , String pass){ // 定义静态方法checkPass
String pwdMd5 = Md5Util.md5(inputPass); // 将输入密码进行MD5加密
return Md5Util.md5(pwdMd5 + salt).equals(pass); // 校验加密后的密码与数据库密码是否一致
public static boolean checkPass(String inputPass , String salt , String pass){
String pwdMd5 = Md5Util.md5(inputPass);
return Md5Util.md5(pwdMd5 + salt).equals(pass);
}
@ -34,23 +35,23 @@ public class PassHandler { // 定义PassHandler类
* @param inputPass
* @return PassInfo
*/
public static PassInfo buildPassword(String inputPass) { // 定义静态方法buildPassword
public static PassInfo buildPassword(String inputPass) {
//产生一个6位数的随机码
String salt = RandomStringUtils.randomAlphabetic(6); // 生成6位随机字母作为盐
String salt = RandomStringUtils.randomAlphabetic(6);
//加密后的密码
String encryptPassword = Md5Util.md5(Md5Util.md5(inputPass)+salt); // 对输入密码和盐进行双重MD5加密
String encryptPassword = Md5Util.md5(Md5Util.md5(inputPass)+salt);
//返回对象
return new PassInfo(salt,encryptPassword); // 返回包含盐和加密密码的PassInfo对象
return new PassInfo(salt,encryptPassword);
}
public static void main(String[] args) { // 主方法
public static void main(String[] args) {
PassInfo info = buildPassword("190601"); // 调用buildPassword方法生成密码信息
PassInfo info = buildPassword("190601");
System.out.println(info.getPassword()); // 输出加密后的密码
System.out.println(info.getSalt()); // 输出生成的盐
System.out.println(info.getPassword());
System.out.println(info.getSalt());
}
}

@ -1,45 +1,38 @@
package com.yf.exam.core.utils.passwd; // 定义包名
package com.yf.exam.core.utils.passwd;
/**
*
* ClassName: PassInfo <br/>
* date: 2018213 7:13:50 <br/>
*
* @author Bool // 作者
* @version // 版本信息
* @author Bool
* @version
*/
public class PassInfo { // 定义PassInfo类
public class PassInfo {
// 密码随机串码
private String salt; // 声明salt变量
//密码随机串码
private String salt;
// MD5后的密码
private String password; // 声明password变量
//MD5后的密码
private String password;
// 构造函数初始化salt和password
public PassInfo(String salt, String password) {
super(); // 调用父类构造函数
this.salt = salt; // 设置salt
this.password = password; // 设置password
super();
this.salt = salt;
this.password = password;
}
// 获取salt
public String getSalt() {
return salt; // 返回salt
return salt;
}
// 设置salt
public void setSalt(String salt) {
this.salt = salt; // 更新salt
this.salt = salt;
}
// 获取password
public String getPassword() {
return password; // 返回password
return password;
}
// 设置password
public void setPassword(String password) {
this.password = password; // 更新password
this.password = password;
}
}

@ -1,15 +1,14 @@
package com.yf.exam.modules; // 包名:表示该类属于 modules 包
package com.yf.exam.modules;
/**
*
* 使
* @ bool
*
* @author bool
*/
public class Constant {
/**
*
* Token
*
*/
public static final String TOKEN = "token"; // 定义一个常量 TOKEN表示会话中的 Token 名称
public static final String TOKEN = "token";
}

@ -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;
* <p>
*
* </p>
*
*
* @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<IPage<PaperListRespDTO>> paging(@RequestBody PagingReqDTO<PaperListReqDTO> reqDTO) {
// 调用业务层进行分页查询
//分页查询并转换
IPage<PaperListRespDTO> 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<BaseIdRespDTO> 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<ExamDetailRespDTO> paperDetail(@RequestBody BaseIdReqDTO reqDTO) {
// 调用业务层获取试卷详情
//根据ID删除
ExamDetailRespDTO respDTO = baseService.paperDetail(reqDTO.getId());
// 返回成功响应,并附带试卷详情
return super.success(respDTO);
}
/**
*
* @param reqDTO IDID
* @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<PaperQuDetailDTO> 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<PaperQuDetailDTO> 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<PaperQuDetailDTO> 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<ExamResultRespDTO> 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<PaperDTO> checkProcess() {
// 调用业务层检测用户是否有未完成的考试
//复制参数
PaperDTO dto = baseService.checkProcess(UserUtils.getUserId());
// 返回成功响应,并附带考试进程数据
return super.success(dto);
}
}

@ -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;
/**
* <p>
*
* </p>
* 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接口表示该类的对象可以被序列化
* <p>
*
* </p>
*
* @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)
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; // 截止时间,表示考试的最后提交时间
}

@ -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;
/**
* <p>
*
* </p>
* IDID
*
*
* @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接口表示该类的对象可以被序列化
* <p>
*
* </p>
*
* @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)
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 等,表示该备选答案的标识符
}

@ -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;
/**
* <p>
*
* </p>
* IDID
*
* @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接口表示该类的对象可以被序列化
* <p>
*
* </p>
*
* @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)
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; // 是否答对,布尔值,表示用户是否答对了该题目
}

@ -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;
/**
* <p>
*
* </p>
* 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)
private String image;
@ApiModelProperty(value = "答案内容", required=true)
private String content;
@ApiModelProperty(value = "试题图片", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private String image; // 试题对应的图片内容
@ApiModelProperty(value = "答案内容", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private String content; // 备选答案的具体内容
}

@ -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;
/**
* <p>
*
* </p>
* 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<PaperQuAnswerExtDTO> answerList; // 存储该题目的备选答案使用List集合存储多个答案
@ApiModelProperty(value = "答案内容", required=true)
List<PaperQuAnswerExtDTO> answerList;
}

@ -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<String> answers;
@ApiModelProperty(value = "回答列表", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private List<String> answers; // 存储多个选择题答案的列表
@ApiModelProperty(value = "主观答案", required=true)
private String answer;
@ApiModelProperty(value = "主观答案", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private String answer; // 存储主观题的答案内容
}

@ -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
* IDID
*/
@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用于创建试卷时指定关联的考试
}

@ -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;
/**
* <p>
*
* </p>
* IDIDID
*
*
* @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;
@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; // 存储试卷的状态,可能的值如:未开始、进行中、已完成等
}

@ -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
*
* IDID
*/
@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用于查询指定试卷中的某一道题目
}

@ -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;
/**
* <p>
*
* </p>
* 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<PaperQuDTO> radioList; // 存储单选题的列表使用PaperQuDTO表示单个试题
@ApiModelProperty(value = "单选题列表", required=true)
private List<PaperQuDTO> radioList;
@ApiModelProperty(value = "多选题列表", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private List<PaperQuDTO> multiList; // 存储多选题的列表使用PaperQuDTO表示单个试题
@ApiModelProperty(value = "多选题列表", required=true)
private List<PaperQuDTO> multiList;
@ApiModelProperty(value = "判断题", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private List<PaperQuDTO> judgeList; // 存储判断题的列表使用PaperQuDTO表示单个试题
@ApiModelProperty(value = "判断题", required=true)
private List<PaperQuDTO> 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;
}
}

@ -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;
/**
* <p>
*
* </p>
* 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<PaperQuDetailDTO> quList; // 存储试题详细信息的列表使用PaperQuDetailDTO表示每个试题的详细数据
@ApiModelProperty(value = "问题列表", required=true)
private List<PaperQuDetailDTO> quList;
}

@ -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;
/**
* <p>
*
* </p>
* PaperDTOrealName
*
*
* @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
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 17:31
*/
@Data
@ApiModel(value="试卷列表响应类", description="试卷列表响应类")
public class PaperListRespDTO extends PaperDTO {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "人员", required=true)
private String realName;
private static final long serialVersionUID = 1L; // 序列化版本ID用于序列化和反序列化操作
@ApiModelProperty(value = "人员", required=true) // Swagger注解描述该字段在API文档中的含义并标注该字段为必填项
private String realName; // 存储人员姓名,用于表示与该试卷相关的人员信息
}

@ -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;
/**
* <p>
*
* </p>
* `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<Paper> { // 继承MyBatis Plus的Model类提供了CRUD等基础操作
private static final long serialVersionUID = 1L; // 序列化版本ID用于序列化和反序列化操作
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 17:31
*/
@Data
@TableName("el_paper")
public class Paper extends Model<Paper> {
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;
}

@ -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;
/**
* <p>
*
* </p>
* `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<PaperQu> { // 继承MyBatis Plus的Model类提供了基础的CRUD等操作
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 17:31
*/
@Data
@TableName("el_paper_qu")
public class PaperQu extends Model<PaperQu> {
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;
}

@ -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;
/**
* <p>
*
* </p>
* `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<PaperQuAnswer> { // 继承MyBatis Plus的Model类提供了基础的CRUD等操作
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 17:31
*/
@Data
@TableName("el_paper_qu_answer")
public class PaperQuAnswer extends Model<PaperQuAnswer> {
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;
}

@ -1,38 +1,33 @@
package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径
package com.yf.exam.modules.paper.enums;
/**
* <p>
*
* </p>
* 使
*
*
* @author bool
* @date 2019-10-30 13:11
*/
public interface ExamState {
/**
*
*
*/
Integer ENABLE = 0;
/**
*
*
*/
Integer DISABLED = 1;
/**
*
*
*/
Integer READY_START = 2;
/**
*
*
*/
Integer OVERDUE = 3;
}

@ -1,38 +1,33 @@
package com.yf.exam.modules.paper.enums; // 定义当前类所在的包路径
package com.yf.exam.modules.paper.enums;
/**
* <p>
*
* </p>
* 使
*
*
* @author bool
* @date 2019-10-30 13:11
*/
public interface PaperState {
/**
*
*
*/
Integer ING = 0;
/**
*
*
*/
Integer WAIT_OPT = 1;
/**
*
*
*/
Integer FINISHED = 2;
/**
*
* 退
*/
Integer BREAK = 3;
}

@ -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;
/**
*
* <p>
* Quartz
* PaperService
* </p>
*
* @author bool
*/
@Log4j2 // 启用 log4j2 日志记录
@Component // 标识该类为一个 Spring 组件Spring 会自动将其注册为 Bean
@Log4j2
@Component
public class BreakExamJob implements Job {
// 自动注入 PaperService用于处理与试卷相关的业务逻辑
@Autowired
private PaperService paperService;
/**
*
*
* <p>
* Quartz
* PaperService
* </p>
*
* @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);
}
}

@ -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;
/**
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-05-25 16:33
*/
public interface PaperMapper extends BaseMapper<Paper> { // 继承 MyBatis-Plus 提供的 BaseMapper自动实现 CRUD 操作
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-05-25 16:33
*/
public interface PaperMapper extends BaseMapper<Paper> {
/**
*
* <p>
* `Page` `PaperListReqDTO`
* </p>
*
* @param page
* @param query ID ID
* @return `IPage<PaperListRespDTO>`
* @param page
* @param query
* @return
*/
IPage<PaperListRespDTO> paging(Page page, @Param("query") PaperListReqDTO query);
/**
*
* <p>
*
* </p>
*
* @param query ID ID
* @return `List<PaperListRespDTO>` DTO
* @param query
* @return
*/
List<PaperListRespDTO> list(@Param("query") PaperDTO query);
}

@ -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;
// 导入List接口表示返回类型为List集合用于存储多个备选答案
import java.util.List;
/**
* <p>
* Mapper
* Mapper
* </p>
* MyBatis-PlusBaseMapperCRUD
*
* @author
* @since 2020-05-25 16:33
*/
public interface PaperQuAnswerMapper extends BaseMapper<PaperQuAnswer> { // 继承自BaseMapper接口提供了所有的基本CRUD操作
public interface PaperQuAnswerMapper extends BaseMapper<PaperQuAnswer> {
/**
*
* @param paperId ID
* @param quId ID
* @return IDID
* @param paperId
* @param quId
* @return
*/
List<PaperQuAnswerExtDTO> list(@Param("paperId") String paperId, @Param("quId") String quId); // 根据试卷ID和题目ID查询对应的备选答案列表
List<PaperQuAnswerExtDTO> list(@Param("paperId") String paperId, @Param("quId") String quId);
}

@ -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;
// 导入List接口用于返回多个试题
import java.util.List;
/**
* <p>
* Mapper
* Mapper
* </p>
* MyBatis-PlusBaseMapperCRUD
*
* @author
* @since 2020-05-25 16:33
*/
public interface PaperQuMapper extends BaseMapper<PaperQu> { // 继承自BaseMapper接口提供通用的CRUD操作
public interface PaperQuMapper extends BaseMapper<PaperQu> {
/**
*
* @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<PaperQuDetailDTO> listByPaper(@Param("paperId") String paperId); // 根据试卷ID查询所有试题的详细信息
List<PaperQuDetailDTO> listByPaper(@Param("paperId") String paperId);
}

@ -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;
/**
* <p>
*
* </p>
*
*
* @author
* @since 2020-05-25 16:33
@ -23,24 +21,24 @@ public interface PaperQuAnswerService extends IService<PaperQuAnswer> {
/**
*
* @param reqDTO DTO
* @return PaperQuAnswerDTO
* @param reqDTO
* @return
*/
IPage<PaperQuAnswerDTO> paging(PagingReqDTO<PaperQuAnswerDTO> reqDTO);
/**
*
* @param paperId ID
* @param quId ID
* @return PaperQuAnswerExtDTO
*
* @param paperId
* @param quId
* @return
*/
List<PaperQuAnswerExtDTO> listForExam(String paperId, String quId);
/**
*
* @param paperId ID
* @param quId ID
* @return PaperQuAnswer
*
* @param paperId
* @param quId
* @return
*/
List<PaperQuAnswer> listForFill(String paperId, String quId);
}

@ -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;
/**
* <p>
*
* </p>
*
*
* @author
* @since 2020-05-25 16:33
@ -23,50 +21,50 @@ public interface PaperQuService extends IService<PaperQu> {
/**
*
* @param reqDTO DTO
* @return PaperQuDTO
* @param reqDTO
* @return
*/
IPage<PaperQuDTO> paging(PagingReqDTO<PaperQuDTO> reqDTO);
/**
*
* @param paperId ID
* @return PaperQuDTO
* @param paperId
* @return
*/
List<PaperQuDTO> 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<PaperQuDetailDTO> listForPaperResult(String paperId);
}

@ -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;
/**
* <p>
*
* </p>
*
*
* @author
* @since 2020-05-25 16:33
@ -26,57 +24,60 @@ public interface PaperService extends IService<Paper> {
/**
*
* @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<PaperListRespDTO>
*
* @param reqDTO
* @return
*/
IPage<PaperListRespDTO> paging(PagingReqDTO<PaperListReqDTO> reqDTO);
/**
*
* @param userId ID
* @return PaperDTO
*
* @param userId
* @return
*/
PaperDTO checkProcess(String userId);
}

@ -1,95 +1,61 @@
package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径
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接口用于返回多个结果
import java.util.List;
/**
* <p>
*
*
* </p>
* PaperQuAnswerService
*
* @author
* @since 2020-05-25 16:33
*/
@Service // 标注为Spring的服务类
public class PaperQuAnswerServiceImpl extends ServiceImpl<PaperQuAnswerMapper, PaperQuAnswer> implements PaperQuAnswerService { // 继承ServiceImpl类提供基本的数据库操作功能
@Service
public class PaperQuAnswerServiceImpl extends ServiceImpl<PaperQuAnswerMapper, PaperQuAnswer> implements PaperQuAnswerService {
/**
*
* @param reqDTO
* @return
*/
@Override
public IPage<PaperQuAnswerDTO> paging(PagingReqDTO<PaperQuAnswerDTO> reqDTO) {
// 创建分页对象
//创建分页对象
IPage<PaperQuAnswer> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
// 查询条件,可以根据需要添加更多过滤条件
//查询条件
QueryWrapper<PaperQuAnswer> wrapper = new QueryWrapper<>();
// 执行分页查询操作
//获得数据
IPage<PaperQuAnswer> page = this.page(query, wrapper);
// 将查询结果转换为DTO对象返回分页后的结果
//转换结果
IPage<PaperQuAnswerDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<PaperQuAnswerDTO>>(){});
return pageData; // 返回分页结果
return pageData;
}
/**
* IDID
* @param paperId ID
* @param quId ID
* @return DTO
*/
@Override
public List<PaperQuAnswerExtDTO> listForExam(String paperId, String quId) {
// 调用Mapper中的list方法查询并返回试题的备选答案列表
return baseMapper.list(paperId, quId);
}
/**
*
* @param paperId ID
* @param quId ID
* @return
*/
@Override
public List<PaperQuAnswer> listForFill(String paperId, String quId) {
// 创建查询条件
//查询条件
QueryWrapper<PaperQuAnswer> 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);
}
}

@ -1,150 +1,94 @@
package com.yf.exam.modules.paper.service.impl; // 指定该类所在的包路径
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接口用于返回多个结果
import java.util.List;
/**
* <p>
*
*
* </p>
* PaperQuService
*
* @author
* @since 2020-05-25 16:33
*/
@Service // 标注为Spring的服务类
public class PaperQuServiceImpl extends ServiceImpl<PaperQuMapper, PaperQu> implements PaperQuService { // 继承ServiceImpl类提供基本的数据库操作功能
/**
*
* @param reqDTO
* @return
*/
@Service
public class PaperQuServiceImpl extends ServiceImpl<PaperQuMapper, PaperQu> implements PaperQuService {
@Override
public IPage<PaperQuDTO> paging(PagingReqDTO<PaperQuDTO> reqDTO) {
// 创建分页对象
//创建分页对象
IPage<PaperQu> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
// 查询条件
//查询条件
QueryWrapper<PaperQu> wrapper = new QueryWrapper<>();
// 执行分页查询操作
//获得数据
IPage<PaperQu> page = this.page(query, wrapper);
// 将查询结果转换为DTO对象返回分页后的结果
//转换结果
IPage<PaperQuDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<PaperQuDTO>>(){});
return pageData; // 返回分页结果
return pageData;
}
/**
* ID
* @param paperId ID
* @return DTO
*/
@Override
public List<PaperQuDTO> listByPaper(String paperId) {
// 查询条件
//查询条件
QueryWrapper<PaperQu> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(PaperQu::getPaperId, paperId) // 通过试卷ID过滤
.orderByAsc(PaperQu::getSort); // 按照题目排序字段升序排列
wrapper.lambda().eq(PaperQu::getPaperId, paperId)
.orderByAsc(PaperQu::getSort);
// 执行查询,获取试卷考题列表
List<PaperQu> list = this.list(wrapper);
// 使用BeanMapper工具类将实体对象列表转换为DTO对象列表
return BeanMapper.mapList(list, PaperQuDTO.class);
}
/**
* IDID
* @param paperId ID
* @param quId ID
* @return
*/
@Override
public PaperQu findByKey(String paperId, String quId) {
// 查询条件
//查询条件
QueryWrapper<PaperQu> 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);
}
/**
* IDID
* @param qu
*/
@Override
public void updateByKey(PaperQu qu) {
// 查询条件
//查询条件
QueryWrapper<PaperQu> 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<PaperQuDetailDTO> listForPaperResult(String paperId) {
return baseMapper.listByPaper(paperId); // 调用Mapper方法获取试卷考题详细信息
return baseMapper.listByPaper(paperId);
}
}

@ -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接口
/**
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 16:33
*/
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 16:33
*/
@Service
public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> 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,83 +106,68 @@ public class PaperServiceImpl extends ServiceImpl<PaperMapper, Paper> implements
,"Y","Z"
});
// 声明创建试卷的方法,使用事务管理,如果发生异常则回滚
/**
*
* @param userId ID
* @param examId ID
* @return ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public String createPaper(String userId, String examId) {
// 构建查询条件,查询是否有正在考试的试卷
// 校验是否有正在考试的试卷
QueryWrapper<Paper> 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<PaperQu> quList = this.generateByRepo(examId);
// 如果题目列表为空,则抛出服务异常
if(CollectionUtils.isEmpty(quList)){
throw new ServiceException(1, "规则不正确,无对应的考题!");
}
// 保存试卷内容并返回试卷ID
//保存试卷内容
Paper paper = this.savePaper(userId, exam, quList);
// 添加强制交卷任务
// 强制交卷任务
String jobName = JobPrefix.BREAK_EXAM + paper.getId();
jobService.addCronJob(BreakExamJob.class, jobName, CronUtils.dateToCron(paper.getLimitTime()), paper.getId());
return paper.getId();
}
}
@Override
public ExamDetailRespDTO paperDetail(String paperId) {
// 声明查询试卷详情的方法
/**
*
* @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<PaperQuDTO> list = paperQuService.listByPaper(paperId);
// 分类题目列表
List<PaperQuDTO> radioList = new ArrayList<>();
List<PaperQuDTO> multiList = new ArrayList<>();
List<PaperQuDTO> judgeList = new ArrayList<>();
@ -262,87 +183,69 @@ public ExamDetailRespDTO paperDetail(String paperId) {
}
}
// 设置分类后的题目列表到响应DTO中
respDTO.setRadioList(radioList);
respDTO.setMultiList(multiList);
respDTO.setJudgeList(judgeList);
return respDTO;
}
}
// 声明查询试卷结果的方法
/**
*
* @param paperId ID
* @return DTO
*/
@Override
public ExamResultRespDTO paperResult(String paperId) {
@Override
public ExamResultRespDTO paperResult(String paperId) {
// 创建考试结果响应DTO对象
ExamResultRespDTO respDTO = new ExamResultRespDTO();
// 根据试卷ID查询试卷基本信息并复制到响应DTO中
// 试题基本信息
Paper paper = paperService.getById(paperId);
BeanMapper.copy(paper, respDTO);
// 根据试卷ID查询题目列表
List<PaperQuDetailDTO> quList = paperQuService.listForPaperResult(paperId);
respDTO.setQuList(quList);
return respDTO;
}
}
// 声明查询题目详情的方法
/**
*
* @param paperId ID
* @param quId ID
* @return DTO
*/
@Override
public PaperQuDetailDTO findQuDetail(String paperId, String quId) {
@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<PaperQuAnswerExtDTO> list = paperQuAnswerService.listForExam(paperId, quId);
respDTO.setAnswerList(list);
return respDTO;
}
}
// 声明题库组题方式产生题目列表的私有方法
/**
*
* @param examId ID
* @return
/**
*
* @param examId
* @return
*/
private List<PaperQu> generateByRepo(String examId){
private List<PaperQu> generateByRepo(String examId){
// 查询规则指定的题库
// 查找规则指定的题库
List<ExamRepoExtDTO> list = examRepoService.listByExam(examId);
// 最终的题目列表
//最终的题目列表
List<PaperQu> quList = new ArrayList<>();
// 排除ID避免题目重复
//排除ID避免题目重复
List<String> excludes = new ArrayList<>();
excludes.add("none");
// 如果题库列表不为空,则进行题目抽取
if (!CollectionUtils.isEmpty(list)) {
for (ExamRepoExtDTO item : list) {
// 抽取单选题
// 单选题
if(item.getRadioCount() > 0){
List<Qu> radioList = quService.listByRandom(item.getRepoId(), QuType.RADIO, excludes, item.getRadioCount());
for (Qu qu : radioList) {
@ -352,7 +255,7 @@ private List<PaperQu> generateByRepo(String examId){
}
}
// 抽取多选题
//多选题
if(item.getMultiCount() > 0) {
List<Qu> multiList = quService.listByRandom(item.getRepoId(), QuType.MULTI, excludes,
item.getMultiCount());
@ -363,7 +266,7 @@ private List<PaperQu> generateByRepo(String examId){
}
}
// 抽取判断题
// 判断题
if(item.getJudgeCount() > 0) {
List<Qu> judgeList = quService.listByRandom(item.getRepoId(), QuType.JUDGE, excludes,
item.getJudgeCount());
@ -376,60 +279,58 @@ private List<PaperQu> generateByRepo(String examId){
}
}
return quList;
}
}
// 声明填充试题题目信息的私有方法
/**
*
* @param repo DTO
* @param qu
* @return
/**
*
* @param repo
* @param qu
* @return
*/
private PaperQu processPaperQu(ExamRepoDTO repo, Qu qu) {
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;
}
}
// 声明保存试卷的私有方法
/**
*
* @param userId ID
* @param exam DTO
* @param quList
* @return
/**
*
* @param userId
* @param exam
* @param quList
* @return
*/
private Paper savePaper(String userId, ExamDTO exam, List<PaperQu> quList) {
private Paper savePaper(String userId, ExamDTO exam, List<PaperQu> quList) {
// 根据用户ID查询用户信息
// 查找用户
SysUser user = sysUserService.getById(userId);
// 创建试卷基本信息,并设置属性
//保存试卷基本信息
Paper paper = new Paper();
paper.setDepartId(user.getDepartId());
paper.setExamId(exam.getId());
@ -444,51 +345,45 @@ private Paper savePaper(String userId, ExamDTO exam, List<PaperQu> quList) {
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 ID
* @param quList
/**
*
* @param paperId
* @param quList
*/
private void savePaperQu(String paperId, List<PaperQu> quList){
private void savePaperQu(String paperId, List<PaperQu> quList){
// 创建批量保存的题目列表和答案列表
List<PaperQu> batchQuList = new ArrayList<>();
List<PaperQuAnswer> batchAnswerList = new ArrayList<>();
// 初始化排序号
int sort = 0;
for (PaperQu item : quList) {
// 设置试卷ID和排序号并生成ID
item.setPaperId(paperId);
item.setSort(sort);
item.setId(IdWorker.getIdStr());
// 查询题目的答案列表
//回答列表
List<QuAnswer> answerList = quAnswerService.listAnswerByRandom(item.getQuId());
// 如果答案列表不为空,则进行处理
if (!CollectionUtils.isEmpty(answerList)) {
// 初始化答案排序号
int ii = 0;
for (QuAnswer answer : answerList) {
PaperQuAnswer paperQuAnswer = new PaperQuAnswer();
@ -505,57 +400,51 @@ private void savePaperQu(String paperId, List<PaperQu> quList){
}
}
// 添加到批量保存的题目列表中
batchQuList.add(item);
sort++;
}
// 批量添加题
//添加
paperQuService.saveBatch(batchQuList);
// 批量添加答案
//批量添加问题答案
paperQuAnswerService.saveBatch(batchAnswerList);
}
}
// 声明填充答案的方法,使用事务管理
/**
*
* @param reqDTO DTO
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void fillAnswer(PaperAnswerDTO reqDTO) {
@Transactional(rollbackFor = Exception.class)
@Override
public void fillAnswer(PaperAnswerDTO reqDTO) {
// 如果答案列表为空且答案字符串也为空,则直接返回
// 未作答
if(CollectionUtils.isEmpty(reqDTO.getAnswers())
&& StringUtils.isBlank(reqDTO.getAnswer())){
return;
}
// 查询答案列表
//查找答案列表
List<PaperQuAnswer> list = paperQuAnswerService.listForFill(reqDTO.getPaperId(), reqDTO.getQuId());
// 初始化是否正确的标记
//是否正确
boolean right = true;
// 更新正确答案
//更新正确答案
for (PaperQuAnswer item : list) {
// 设置答案是否被选中
if (reqDTO.getAnswers().contains(item.getId())) {
item.setChecked(true);
} else {
item.setChecked(false);
}
// 如果有一个答案不正确,则标记为错误
//有一个对不上就是错的
if (item.getIsRight()!=null && !item.getIsRight().equals(item.getChecked())) {
right = false;
}
paperQuAnswerService.updateById(item);
}
// 修改为已回答
//修改为已回答
PaperQu qu = new PaperQu();
qu.setQuId(reqDTO.getQuId());
qu.setPaperId(reqDTO.getPaperId());
@ -565,34 +454,29 @@ public void fillAnswer(PaperAnswerDTO reqDTO) {
paperQuService.updateByKey(qu);
}
}
// 声明交卷的方法,使用事务管理
/**
*
* @param paperId ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void handExam(String paperId) {
@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, "试卷状态不正确!");
}
// 计算客观
// 客观分
int objScore = paperQuService.sumObjective(paperId);
paper.setObjScore(objScore);
paper.setUserScore(objScore);
// 设置主观题分数为0
// 主观分,因为要阅卷,所以给0
paper.setSubjScore(0);
// 如果有主观题,则设置状态为待阅卷
// 待阅卷
if(paper.getHasSaq()) {
paper.setState(PaperState.WAIT_OPT);
}else {
@ -600,12 +484,11 @@ public void handExam(String paperId) {
// 同步保存考试成绩
userExamService.joinResult(paper.getUserId(), paper.getExamId(), objScore, objScore>=paper.getQualifyScore());
// 设置状态为已完成
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);
@ -614,14 +497,15 @@ public void handExam(String paperId) {
}
paper.setUserTime(userTime);
// 更新试卷信息
//更新试卷
paperService.updateById(paper);
// 终止定时任务
String name = JobPrefix.BREAK_EXAM + paperId;
jobService.deleteJob(name, JobGroup.SYSTEM);
// 把打错的问题加入错题本
//把打错的问题加入错题本
List<PaperQuDTO> list = paperQuService.listByPaper(paperId);
for(PaperQuDTO qu: list){
// 主观题和对的都不加入错题库
@ -631,42 +515,28 @@ public void handExam(String paperId) {
//加入错题本
new Thread(() -> userBookService.addBook(paper.getExamId(), qu.getQuId())).run();
}
}
}
// 声明分页查询试卷列表的方法
/**
*
* @param reqDTO DTO
* @return
*/
@Override
public IPage<PaperListRespDTO> paging(PagingReqDTO<PaperListReqDTO> reqDTO) {
@Override
public IPage<PaperListRespDTO> paging(PagingReqDTO<PaperListReqDTO> reqDTO) {
return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams());
}
}
// 声明检查考试进度的方法
/**
*
* @param userId ID
* @return DTO
*/
@Override
public PaperDTO checkProcess(String userId) {
// 构建查询条件,查询是否有正在进行的考试
@Override
public PaperDTO checkProcess(String userId) {
QueryWrapper<Paper> 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;
}
}

@ -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;
/**
* <p>
*
* </p>
*
*
* @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<BaseIdRespDTO> save(@RequestBody QuDetailDTO reqDTO) {
baseService.save(reqDTO); // 调用服务层保存或更新问题数据
return super.success(); // 返回成功响应
baseService.save(reqDTO);
return super.success();
}
/**
*
*
*
* @param reqDTO IDID
* @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 IDID
* @return
* @param reqDTO
* @return
*/
@ApiOperation(value = "查找详情") // Swagger注解描述该方法的功能
@RequestMapping(value = "/detail", method = {RequestMethod.POST}) // POST请求表示获取详情操作
@ApiOperation(value = "查找详情")
@RequestMapping(value = "/detail", method = {RequestMethod.POST})
public ApiRest<QuDetailDTO> 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<IPage<QuDTO>> paging(@RequestBody PagingReqDTO<QuQueryReqDTO> reqDTO) {
IPage<QuDTO> page = baseService.paging(reqDTO); // 调用服务层进行分页查询
return super.success(page); // 返回分页结果
//分页查询并转换
IPage<QuDTO> 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<QuExportDTO> list = baseService.listForExport(reqDTO); // 获取导出数据
List<QuExportDTO> 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<QuExportDTO> 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<QuExportDTO> 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<QuExportDTO> 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 + "行,题目序号不能为空!<br>");
}
// 校验题目内容和其他字段是否为空
if (quNo == null || !quNo.equals(no)) {
if (item.getQuType() == null) {
sb.append("第" + line + "行,题目类型不能为空<br>");
}
if (StringUtils.isBlank(item.getQContent())) {
sb.append("第" + line + "行,题目内容不能为空<br>");
}
if (CollectionUtils.isEmpty(item.getRepoList())) {
sb.append("第" + line + "行,题目必须包含一个题库<br>");
}
}
if (StringUtils.isBlank(item.getAIsRight())) {
sb.append("第" + line + "行,选项是否正确不能为空<br>");
}
if (StringUtils.isBlank(item.getAContent()) && StringUtils.isBlank(item.getAImage())) {
sb.append("第" + line + "行,选项内容和选项图片必须有一个不为空<br>");
}
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<QuExportDTO> list = Lists.newArrayList(); // 创建模板数据列表
// 模板数据(包含问题内容、题型、选项等)
String fileName = "试题导入模板.xlsx";
List<QuExportDTO> list = Lists.newArrayList();
QuExportDTO l1 = new QuExportDTO();
l1.setNo("正式导入,请删除此说明行:数字,相同的数字表示同一题的序列");
l1.setQContent("问题内容");
@ -244,17 +286,39 @@ public class QuController extends BaseController {
l1.setAIsRight("只能填写0或10表示否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());
}
}
}

@ -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;
/**
* <p>
*
* </p>
*
*
*
* @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;
@ApiModelProperty(value = "答案ID", required=true)
private String id;
/**
* ID
*
*/
@ApiModelProperty(value = "答案ID", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String id; // 答案ID
@ApiModelProperty(value = "问题ID", required=true)
private String quId;
/**
* ID
* ID
*/
@ApiModelProperty(value = "问题ID", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String quId; // 题目ID
@ApiModelProperty(value = "是否正确", required=true)
private Boolean isRight;
/**
*
* `true``false`
*/
@ApiModelProperty(value = "是否正确", required=true) // Swagger注解描述字段信息标明该字段是必填项
private Boolean isRight; // 是否正确
@ApiModelProperty(value = "选项图片", required=true)
private String image;
/**
*
* URL
*/
@ApiModelProperty(value = "选项图片", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String image; // 选项图片URL
@ApiModelProperty(value = "答案内容", required=true)
private String content;
/**
*
*
*/
@ApiModelProperty(value = "答案内容", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String content; // 答案内容
@ApiModelProperty(value = "答案分析", required=true)
private String analysis;
/**
*
*
*/
@ApiModelProperty(value = "答案分析", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String analysis; // 答案分析
}

@ -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;
/**
* <p>
*
* </p>
*
*
*
* @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
/**
* ID
* ID
*/
@ApiModelProperty(value = "题目ID", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String id; // 题目ID
/**
*
*
*/
@ApiModelProperty(value = "题目类型", required=true) // Swagger注解描述字段信息标明该字段是必填项
private Integer quType; // 题目类型
/**
*
* 12
*/
@ApiModelProperty(value = "1普通,2较难", required=true) // Swagger注解描述字段信息标明该字段是必填项
private Integer level; // 题目难度
/**
*
* URL
*/
@ApiModelProperty(value = "题目图片", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String image; // 题目图片URL
/**
*
*
*/
@ApiModelProperty(value = "题目内容", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String content; // 题目内容
/**
*
*
*/
@ApiModelProperty(value = "创建时间", required=true) // Swagger注解描述字段信息标明该字段是必填项
private Date createTime; // 创建时间
/**
*
*
*/
@ApiModelProperty(value = "更新时间", required=true) // Swagger注解描述字段信息标明该字段是必填项
private Date updateTime; // 更新时间
/**
*
*
*/
@ApiModelProperty(value = "题目备注", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String remark; // 题目备注
/**
*
*
*/
@ApiModelProperty(value = "整题解析", required=true) // Swagger注解描述字段信息标明该字段是必填项
private String analysis; // 整题解析
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "题目ID", required=true)
private String id;
@ApiModelProperty(value = "题目类型", required=true)
private Integer quType;
@ApiModelProperty(value = "1普通,2较难", required=true)
private Integer level;
@ApiModelProperty(value = "题目图片", required=true)
private String image;
@ApiModelProperty(value = "题目内容", required=true)
private String content;
@ApiModelProperty(value = "创建时间", required=true)
private Date createTime;
@ApiModelProperty(value = "更新时间", required=true)
private Date updateTime;
@ApiModelProperty(value = "题目备注", required=true)
private String remark;
@ApiModelProperty(value = "整题解析", required=true)
private String analysis;
}

@ -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;
/**
* <p>
*
* </p>
*
* IDID
*
* @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;
}

@ -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<String> 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<String> 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;
}

@ -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;
/**
*
* 1234
*/
private String quType; // 题目类型,表示题目的类别
/**
*
*
*/
private String qContent; // 题目内容,表示题目的实际问题
/**
*
*
*/
private String qAnalysis; // 题目解析,解释题目的答案或相关说明
/**
*
* URL
*/
private String qImage; // 题目图片存储图片URL或路径
/**
*
*
*/
private String repoName; // 题目所属的题库名称
/**
*
*
*/
private List<QuAnswerDTO> answerList; // 答案选项列表,包含该题目的所有答案选项
private String quType;
private String qContent;
private String qAnalysis;
private String qImage;
private String repoName;
private List<QuAnswerDTO> answerList;
}

@ -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;
/**
* <p>
*
* </p>
*
* `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
/**
*
*
*
*/
@ApiModelProperty(value = "备选项列表", required=true) // Swagger注解用于生成文档
private List<QuAnswerDTO> answerList; // 备选项列表,包含该题目的所有答案选项
/**
*
* ID
*
*/
@ApiModelProperty(value = "题库列表", required=true) // Swagger注解用于生成文档
private List<String> repoIds; // 题库列表存储题库ID的列表
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "备选项列表", required=true)
private List<QuAnswerDTO> answerList;
@ApiModelProperty(value = "题库列表", required=true)
private List<String> repoIds;
}

@ -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;
/**
* <p>
*
* </p>
*
*
* 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<String> repoIds; // 题库ID列表题目可以归属于多个题库
/**
*
*
*/
@ApiModelProperty(value = "题目内容") // Swagger注解描述字段信息
private String content; // 题目内容,支持模糊查询
/**
* ID
* IDID
*/
@ApiModelProperty(value = "排除ID列表") // Swagger注解描述字段信息
private List<String> excludes; // 排除的题目ID列表
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "题目类型")
private Integer quType;
@ApiModelProperty(value = "归属题库")
private List<String> repoIds;
@ApiModelProperty(value = "题目内容")
private String content;
@ApiModelProperty(value = "排除ID列表")
private List<String> excludes;
}

@ -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;
/**
* <p>
*
*
* </p>
*
*
*
*
* @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<String> quIds; // 要操作的题目ID列表
/**
* ID
* ID
*/
@ApiModelProperty(value = "题目类型", required=true) // Swagger注解描述字段信息标明该字段是必填项
private List<String> 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<String> quIds;
@ApiModelProperty(value = "题目类型", required=true)
private List<String> repoIds;
@ApiModelProperty(value = "是否移除,否就新增;是就移除", required=true)
private Boolean remove;
}

@ -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;
/**
* <p>
*
* </p>
*
* 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<Qu> {
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;
/**
*
* 12
* 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;
}

@ -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;
/**
* <p>
*
* </p>
*
* 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<QuAnswer> {
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;
/**
*
* truefalse
*/
@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;
}

@ -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;
/**
* <p>
*
* </p>
*
*
*
* @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<QuRepo> {
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;
}

@ -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;

@ -4,13 +4,13 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yf.exam.modules.qu.entity.QuAnswer;
/**
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
public interface QuAnswerMapper extends BaseMapper<QuAnswer> {
}

@ -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;
/**
* <p>
@ -19,34 +19,38 @@ import java.util.List; // 导入 List用于返回多个对象的集合
* @author
* @since 2020-05-25 13:23
*/
public interface QuMapper extends BaseMapper<Qu> { // QuMapper 继承自 BaseMapper提供基本的 CRUD 操作
public interface QuMapper extends BaseMapper<Qu> {
/**
*
* @param repoId ID
* @param quType
* @param level
* @param repoId
* @param quType
* @param level
* @param excludes ID
* @param size
* @return
* @param size
* @return
*/
List<Qu> listByRandom(@Param("repoId") String repoId, // 题库ID
@Param("quType") Integer quType, // 题目类型
@Param("excludes") List<String> excludes, // 要排除的题目ID列表
@Param("size") Integer size); // 抽取的题目数量
List<Qu> listByRandom(@Param("repoId") String repoId,
@Param("quType") Integer quType,
@Param("excludes") List<String> excludes,
@Param("size") Integer size);
/**
*
* @param query
* @return
* @param query
* @return
*/
List<QuExportDTO> listForExport(@Param("query") QuQueryReqDTO query); // 根据查询条件查找导出数据
List<QuExportDTO> listForExport(@Param("query") QuQueryReqDTO query);
/**
*
* @param page
* @param query
* @return
* @param page
* @param query
* @return
*/
IPage<QuDTO> paging(Page page, @Param("query") QuQueryReqDTO query); // 分页查询题目数据,返回 QuDTO 类型的数据
IPage<QuDTO> paging(Page page, @Param("query") QuQueryReqDTO query);
}

@ -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;
/**
* <p>
@ -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<QuRepo> { // QuRepoMapper 继承自 BaseMapper提供基本的 CRUD 操作
public interface QuRepoMapper extends BaseMapper<QuRepo> {
}

@ -10,7 +10,7 @@ import java.util.List;
/**
* <p>
*
*
* </p>
*
* @author
@ -19,30 +19,30 @@ import java.util.List;
public interface QuAnswerService extends IService<QuAnswer> {
/**
*
* @param reqDTO
* @return
*
* @param reqDTO
* @return
*/
IPage<QuAnswerDTO> paging(PagingReqDTO<QuAnswerDTO> reqDTO);
/**
* ID
* @param quId ID
* @return
* ID
* @param quId
* @return
*/
List<QuAnswer> listAnswerByRandom(String quId);
/**
* ID
* @param quId ID
* @return
*
* @param quId
* @return
*/
List<QuAnswerDTO> listByQu(String quId);
/**
*
* @param quId ID
* @param list
*
* @param quId
* @param list
*/
void saveAll(String quId, List<QuAnswerDTO> list);
}

@ -1,65 +1,58 @@
// 定义包名表示该接口属于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;
/**
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
public interface QuRepoService extends IService<QuRepo> {
/**
*
* @param reqDTO DTO
* @return
*
* @param reqDTO
* @return
*/
IPage<QuRepoDTO> paging(PagingReqDTO<QuRepoDTO> reqDTO);
/**
*
* @param quId ID
* @param quType
* @param ids ID
*
* @param quId
* @param quType
* @param ids
*/
void saveAll(String quId, Integer quType, List<String> ids);
/**
*
* @param quId ID
* @return ID
*
* @param quId
* @return
*/
List<String> listByQu(String quId);
/**
* ID
* @param repoId ID
* @param quType
* @param rand
* @return ID
* ID
* @param repoId
* @param quType
* @param rand
* @return
*/
List<String> listByRepo(String repoId, Integer quType, boolean rand);
/**
*
* @param reqDTO DTO
*
* @param reqDTO
*/
void batchAction(QuRepoBatchReqDTO reqDTO);

@ -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;
/**
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
public interface QuService extends IService<Qu> {
/**
*
* @param reqDTO DTO
* @return
*
* @param reqDTO
* @return
*/
IPage<QuDTO> paging(PagingReqDTO<QuQueryReqDTO> reqDTO);
/**
*
* @param ids ID
*
* @param ids
*/
void delete(List<String> ids);
/**
*
* @param repoId ID
* @param quType
*
* @param repoId
* @param quType
* @param excludes ID
* @param size
* @return
* @param size
* @return
*/
List<Qu> listByRandom(String repoId,
Integer quType,
@ -57,29 +48,29 @@ public interface QuService extends IService<Qu> {
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<QuExportDTO> listForExport(QuQueryReqDTO query);
/**
* Excel
* @param dtoList DTO
* @return
* Excel
* @param dtoList
* @return
*/
int importExcel(List<QuExportDTO> dtoList);
}

@ -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;
/**
* <p>
@ -28,77 +28,65 @@ import java.util.List; // 导入 List 接口,作为列表类型
* @author
* @since 2020-05-25 13:23
*/
@Service // 表示这是一个服务类Spring 会自动扫描并管理该类
@Service
public class QuAnswerServiceImpl extends ServiceImpl<QuAnswerMapper, QuAnswer> implements QuAnswerService {
@Autowired
private ImageCheckUtils imageCheckUtils; // 自动注入图片校验工具类,用于校验图片地址是否合法
private ImageCheckUtils imageCheckUtils;
@Override
public IPage<QuAnswerDTO> paging(PagingReqDTO<QuAnswerDTO> reqDTO) {
// 创建分页对象,传入当前页和每页大小
//创建分页对象
IPage<QuAnswer> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
// 创建查询条件包装器
//查询条件
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
// 执行分页查询,获取分页结果
//获得数据
IPage<QuAnswer> page = this.page(query, wrapper);
// 将查询结果转换为 QuAnswerDTO 类型的分页结果
//转换结果
IPage<QuAnswerDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<QuAnswerDTO>>(){});
return pageData;
}
@Override
public List<QuAnswer> listAnswerByRandom(String quId) {
// 创建查询条件包装器
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
// 设置查询条件,过滤出与 quId 相同的记录
wrapper.lambda().eq(QuAnswer::getQuId, quId);
// 使用 SQL 的随机排序来随机获取答案
wrapper.last(" ORDER BY RAND() ");
// 执行查询并返回结果
return this.list(wrapper);
}
@Override
public List<QuAnswerDTO> listByQu(String quId) {
// 创建查询条件包装器
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
// 设置查询条件,过滤出与 quId 相同的记录
wrapper.lambda().eq(QuAnswer::getQuId, quId);
// 执行查询,获取答案列表
List<QuAnswer> 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<String> findExistsList(String quId) {
// 创建空的结果列表
//返回结果
List<String> ids = new ArrayList<>();
// 创建查询条件包装器
QueryWrapper<QuAnswer> wrapper = new QueryWrapper();
// 设置查询条件,过滤出与 quId 相同的记录
wrapper.lambda().eq(QuAnswer::getQuId, quId);
// 执行查询,获取答案列表
List<QuAnswer> 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<QuAnswerMapper, QuAnswer> i
@Override
public void saveAll(String quId, List<QuAnswerDTO> list) {
// 创建保存的答案列表
//最终要保存的列表
List<QuAnswer> saveList = new ArrayList<>();
// 获取已有的答案 ID 列表
//已存在的标签列表
List<String> 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<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuAnswer::getQuId, quId);
this.remove(wrapper);
}
}
}

@ -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;
/**
* <p>
*
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Service // 表示这是一个 Spring 服务类Spring 会自动扫描并管理该类
@Service
public class QuRepoServiceImpl extends ServiceImpl<QuRepoMapper, QuRepo> implements QuRepoService {
@Autowired
private QuMapper quMapper; // 自动注入试题的 Mapper 接口
private QuMapper quMapper;
@Autowired
private RepoService repoService; // 自动注入题库服务接口
private RepoService repoService;
@Override
public IPage<QuRepoDTO> paging(PagingReqDTO<QuRepoDTO> reqDTO) {
// 创建分页对象,传入当前页和每页大小
//创建分页对象
IPage<QuRepo> query = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
// 创建查询条件包装器
//查询条件
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
// 执行分页查询,获取分页结果
//获得数据
IPage<QuRepo> page = this.page(query, wrapper);
// 将查询结果转换为 QuRepoDTO 类型的分页结果
//转换结果
IPage<QuRepoDTO> pageData = JSON.parseObject(JSON.toJSONString(page), new TypeReference<Page<QuRepoDTO>>(){});
return pageData;
}
@Override
public void saveAll(String quId, Integer quType, List<String> ids) {
// 先删除已有的试题题库记录
// 先删除
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getQuId, quId);
this.remove(wrapper);
// 如果题库 ID 列表不为空,保存新的记录
// 保存全部
if(!CollectionUtils.isEmpty(ids)){
List<QuRepo> 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<String> listByQu(String quId) {
// 根据试题 ID 查找题库记录
// 先删除
QueryWrapper<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getQuId, quId);
List<QuRepo> list = this.list(wrapper);
List<String> ids = new ArrayList<>();
if(!CollectionUtils.isEmpty(list)){
// 提取题库 ID 列表
for(QuRepo item: list){
ids.add(item.getRepoId());
}
}
return ids; // 返回题库 ID 列表
return ids;
}
@Override
public List<String> listByRepo(String repoId, Integer quType, boolean rand) {
// 根据题库 ID 和题目类型查询题库记录
QueryWrapper<QuRepo> 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<QuRepo> list = this.list(wrapper);
List<String> 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<QuRepo> 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<QuRepo> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(QuRepo::getRepoId, repoId);
List<QuRepo> list = this.list(wrapper);
// 如果题库下没有试题,返回
List<QuRepo> list = this.list(wrapper);
if(CollectionUtils.isEmpty(list)){
return;
}
// 按照顺序设置每个试题的排序值
int sort = 1;
for(QuRepo item: list){
item.setSort(sort);
sort++;
}
// 批量更新排序值
this.updateBatchById(list);
}
}

@ -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;
/**
* <p>
*
*
* </p>
*
* @author
@ -50,136 +46,125 @@ import java.util.Map;
@Service
public class QuServiceImpl extends ServiceImpl<QuMapper, Qu> implements QuService {
// 注入QuAnswerService服务
@Autowired
private QuAnswerService quAnswerService;
// 注入QuRepoService服务
@Autowired
private QuRepoService quRepoService;
// 注入图片校验工具类
@Autowired
private ImageCheckUtils imageCheckUtils;
// 分页查询题目列表
@Override
public IPage<QuDTO> paging(PagingReqDTO<QuQueryReqDTO> reqDTO) {
// 创建分页对象
//创建分页对象
Page page = new Page<>(reqDTO.getCurrent(), reqDTO.getSize());
// 调用baseMapper的分页查询方法获取分页数据
//转换结果
IPage<QuDTO> pageData = baseMapper.paging(page, reqDTO.getParams());
return pageData;
}
// 删除题目、答案和题库绑定
@Transactional(rollbackFor = Exception.class)
@Override
public void delete(List<String> ids) {
// 除题目
// 除题目
this.removeByIds(ids);
// 删除与题目相关的选项
// 移除选项
QueryWrapper<QuAnswer> wrapper = new QueryWrapper<>();
wrapper.lambda().in(QuAnswer::getQuId, ids);
quAnswerService.remove(wrapper);
// 删除题库与题目的绑定
// 移除题库绑定
QueryWrapper<QuRepo> wrapper1 = new QueryWrapper<>();
wrapper1.lambda().in(QuRepo::getQuId, ids);
quRepoService.remove(wrapper1);
}
// 随机获取题目
@Override
public List<Qu> listByRandom(String repoId, Integer quType, List<String> 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<QuAnswerDTO> answerList = quAnswerService.listByQu(id);
respDTO.setAnswerList(answerList);
// 获取题目所属的题库
List<String> 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<QuExportDTO> listForExport(QuQueryReqDTO query) {
return baseMapper.listForExport(query);
}
// 导入Excel数据
@Override
public int importExcel(List<QuExportDTO> dtoList) {
// 根据题目名称分组
//根据题目名称分组
Map<Integer, List<QuExportDTO>> anMap = new HashMap<>(16);
// 存储题目信息
//题目本体信息
Map<Integer, QuExportDTO> 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<QuExportDTO> subList = new ArrayList<>();
subList.add(item);
anMap.put(key, subList);
@ -189,46 +174,49 @@ public class QuServiceImpl extends ServiceImpl<QuMapper, Qu> 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<QuAnswerDTO> 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<QuAnswerDTO> processAnswerList(List<QuExportDTO> importList) {
List<QuAnswerDTO> 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<QuMapper, Qu> 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<QuAnswerDTO> 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 (StringUtils.isEmpty(a.getContent())) {
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 + "单选题不能包含多个正确项!");
}
}
}

@ -1,41 +1,30 @@
// 定义包名表示该类属于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);
}
}

@ -1,113 +1,117 @@
package com.yf.exam.modules.repo.controller; // 包名:表示该类属于 repo.controller 包
package com.yf.exam.modules.repo.controller;
// 导入所需的类和包
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 控制器
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;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-05-25 13:25
*/
@Api(tags = {"题库"}) // Swagger 注解:定义 API 文档中该控制器的标签为“题库”
@RestController // Spring 注解:标识该类为 REST 控制器
@RequestMapping("/exam/api/repo") // 定义请求路径前缀为 /exam/api/repo
public class RepoController extends BaseController { // 题库控制器类,继承基础控制器
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:25
*/
@Api(tags={"题库"})
@RestController
@RequestMapping("/exam/api/repo")
public class RepoController extends BaseController {
@Autowired // 自动注入题库服务
@Autowired
private RepoService baseService;
@Autowired // 自动注入题库批量操作服务
@Autowired
private QuRepoService quRepoService;
/**
*
* @param reqDTO
* @return
*
* @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(); // 返回成功结果
@RequiresRoles("sa")
@ApiOperation(value = "添加或修改")
@RequestMapping(value = "/save", method = { RequestMethod.POST})
public ApiRest save(@RequestBody RepoDTO reqDTO) {
baseService.save(reqDTO);
return super.success();
}
/**
*
* @param reqDTO ID
* @return
*
* @param reqDTO
* @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(); // 返回成功结果
@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
*
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情”
@RequestMapping(value = "/detail", method = {RequestMethod.POST}) // 定义请求路径为 /detail请求方法为 POST
public ApiRest<RepoDTO> find(@RequestBody BaseIdReqDTO reqDTO) { // 查找题库详情的方法
Repo entity = baseService.getById(reqDTO.getId()); // 根据 ID 查找题库实体
RepoDTO dto = new RepoDTO(); // 创建题库数据传输对象
BeanUtils.copyProperties(entity, dto); // 将实体属性拷贝到 DTO 中
return super.success(dto); // 返回成功结果,包含题库详情
@RequiresRoles("sa")
@ApiOperation(value = "查找详情")
@RequestMapping(value = "/detail", method = { RequestMethod.POST})
public ApiRest<RepoDTO> find(@RequestBody BaseIdReqDTO reqDTO) {
Repo entity = baseService.getById(reqDTO.getId());
RepoDTO dto = new RepoDTO();
BeanUtils.copyProperties(entity, dto);
return super.success(dto);
}
/**
*
* @param reqDTO
* @return
*
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "分页查找") // Swagger 注解:定义接口操作说明为“分页查找”
@RequestMapping(value = "/paging", method = {RequestMethod.POST}) // 定义请求路径为 /paging请求方法为 POST
public ApiRest<IPage<RepoRespDTO>> paging(@RequestBody PagingReqDTO<RepoReqDTO> reqDTO) { // 分页查找题库的方法
IPage<RepoRespDTO> page = baseService.paging(reqDTO); // 调用服务进行分页查询
return super.success(page); // 返回成功结果,包含分页数据
@RequiresRoles("sa")
@ApiOperation(value = "分页查找")
@RequestMapping(value = "/paging", method = { RequestMethod.POST})
public ApiRest<IPage<RepoRespDTO>> paging(@RequestBody PagingReqDTO<RepoReqDTO> reqDTO) {
//分页查询并转换
IPage<RepoRespDTO> page = baseService.paging(reqDTO);
return super.success(page);
}
/**
*
* @param reqDTO
* @return
*
* @param reqDTO
* @return
*/
@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(); // 返回成功结果
@RequiresRoles("sa")
@ApiOperation(value = "批量操作", notes = "批量加入或从题库移除")
@RequestMapping(value = "/batch-action", method = { RequestMethod.POST})
public ApiRest batchAction(@RequestBody QuRepoBatchReqDTO reqDTO) {
//分页查询并转换
quRepoService.batchAction(reqDTO);
return super.success();
}
}

@ -1,42 +1,43 @@
package com.yf.exam.modules.repo.dto; // 包名:表示该类属于 repo.dto 包
package com.yf.exam.modules.repo.dto;
import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型
import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性
import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; // 导入 Serializable 接口,用于支持序列化
import java.util.Date; // 导入 Date 类,用于处理日期和时间
import java.io.Serializable;
import java.util.Date;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-05-25 13:23
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@ApiModel(value = "题库", description = "题库") // Swagger 注解,定义该类的 API 模型名称及描述
public class RepoDTO implements Serializable { // 定义类 RepoDTO实现 Serializable 接口以支持序列化
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Data
@ApiModel(value="题库", description="题库")
public class RepoDTO implements 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 = "题库编号", required = true) // Swagger 注解,描述该属性为“题库编号”
private String code; // 定义属性:题库编号
@ApiModelProperty(value = "题库ID", required=true)
private String id;
@ApiModelProperty(value = "题库名称", required = true) // Swagger 注解,描述该属性为“题库名称”
private String title; // 定义属性:题库名称
@ApiModelProperty(value = "题库编号", required=true)
private String code;
@ApiModelProperty(value = "题库备注", required = true) // Swagger 注解,描述该属性为“题库备注”
private String remark; // 定义属性:题库备注信息
@ApiModelProperty(value = "题库名称", required=true)
private String title;
@ApiModelProperty(value = "创建时间", required = true) // Swagger 注解,描述该属性为“创建时间”
private Date createTime; // 定义属性:题库的创建时间
@ApiModelProperty(value = "题库备注", required=true)
private String remark;
@ApiModelProperty(value = "创建时间", required=true)
private Date createTime;
@ApiModelProperty(value = "更新时间", required=true)
private Date updateTime;
@ApiModelProperty(value = "更新时间", required = true) // Swagger 注解,描述该属性为“更新时间”
private Date updateTime; // 定义属性:题库的最后更新时间
}

@ -1,30 +1,30 @@
package com.yf.exam.modules.repo.dto.request; // 包名:表示该类属于 repo.dto.request 包
package com.yf.exam.modules.repo.dto.request;
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 com.yf.exam.modules.repo.dto.RepoDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List; // 导入 Java 的 List 接口,用于存储排除的题库 ID 列表
import java.util.List;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-05-25 13:23
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@ApiModel(value = "题库分页请求类", description = "题库分页请求类") // Swagger 注解,定义该类的 API 模型名称及描述
public class RepoReqDTO extends RepoDTO { // 定义类 RepoReqDTO继承自 RepoDTO
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Data
@ApiModel(value="题库分页请求类", description="题库分页请求类")
public class RepoReqDTO extends RepoDTO {
private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "排除题库ID", required = true) // Swagger 注解,描述该属性为“需要排除的题库 ID 列表”
private List<String> excludes; // 定义属性:排除的题库 ID 列表
@ApiModelProperty(value = "排除题库ID", required=true)
private List<String> excludes;
@ApiModelProperty(value = "单选题数量", required=true)
private String title;
@ApiModelProperty(value = "单选题数量", required = true) // Swagger 注解,描述该属性为“单选题数量”
private String title; // 定义属性:单选题数量(注意:变量名可能存在歧义,建议确认或重命名)
}

@ -1,31 +1,31 @@
package com.yf.exam.modules.repo.dto.response; // 包名:表示该类属于 repo.dto.response 包
package com.yf.exam.modules.repo.dto.response;
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 com.yf.exam.modules.repo.dto.RepoDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-05-25 13:23
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@ApiModel(value = "题库分页响应类", description = "题库分页响应类") // Swagger 注解,定义该类的 API 模型名称及描述
public class RepoRespDTO extends RepoDTO { // 定义类 RepoRespDTO继承自 RepoDTO
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Data
@ApiModel(value="题库分页响应类", description="题库分页响应类")
public class RepoRespDTO extends RepoDTO {
private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "多选题数量", required = true) // Swagger 注解,描述该属性为“多选题数量”
private Integer multiCount; // 定义属性:多选题的数量
@ApiModelProperty(value = "多选题数量", required=true)
private Integer multiCount;
@ApiModelProperty(value = "单选题数量", required = true) // Swagger 注解,描述该属性为“单选题数量”
private Integer radioCount; // 定义属性:单选题的数量
@ApiModelProperty(value = "单选题数量", required=true)
private Integer radioCount;
@ApiModelProperty(value = "判断题数量", required=true)
private Integer judgeCount;
@ApiModelProperty(value = "判断题数量", required = true) // Swagger 注解,描述该属性为“判断题数量”
private Integer judgeCount; // 定义属性:判断题的数量
}

@ -1,59 +1,59 @@
package com.yf.exam.modules.repo.entity; // 包名:表示该类属于 repo.entity 包
package com.yf.exam.modules.repo.entity;
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 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; // 导入 Java 的 Date 类,用于表示日期和时间
import java.util.Date;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-05-25 13:23
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@TableName("el_repo") // MyBatis-Plus 注解,指定该实体类映射的数据库表名为 "el_repo"
public class Repo extends Model<Repo> { // 定义类 Repo继承 MyBatis-Plus 的 Model 类以支持 ActiveRecord 模式
private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Data
@TableName("el_repo")
public class Repo extends Model<Repo> {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,标识主键字段,并指定主键生成策略为分配 ID
private String id; // 定义字段:题库的唯一标识符
@TableId(value = "id", type = IdType.ASSIGN_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") // MyBatis-Plus 注解,指定该字段映射数据库中的 "create_time" 列
private Date createTime; // 定义字段:题库的创建时间
@TableField("create_time")
private Date createTime;
/**
*
*/
@TableField("update_time") // MyBatis-Plus 注解,指定该字段映射数据库中的 "update_time" 列
private Date updateTime; // 定义字段:题库的最后更新时间
@TableField("update_time")
private Date updateTime;
}

@ -1,29 +1,29 @@
package com.yf.exam.modules.repo.mapper; // 包名:表示该类属于 repo.mapper 包
package com.yf.exam.modules.repo.mapper;
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 注解,用于标注参数
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;
/**
* <p>
* Mapper
* </p>
* Mapper
*
* @
* @ 2020-05-25 13:23
*/
public interface RepoMapper extends BaseMapper<Repo> { // RepoMapper 接口,继承自 MyBatis-Plus 的 BaseMapper提供常见的数据库操作
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
public interface RepoMapper extends BaseMapper<Repo> {
/**
*
* @param page
* @param query
* @return
* @param page
* @param query
* @return
*/
IPage<RepoRespDTO> paging(Page page, @Param("query") RepoReqDTO query); // 自定义分页查询方法,返回题库分页响应数据
IPage<RepoRespDTO> paging(Page page, @Param("query") RepoReqDTO query);
}

@ -1,34 +1,34 @@
package com.yf.exam.modules.repo.service; // 包名:表示该类属于 repo.service 包
package com.yf.exam.modules.repo.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; // 导入分页请求数据传输对象
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.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;
/**
* <p>
*
* </p>
* MyBatis-Plus IService
*
* @
* @ 2020-05-25 13:23
*/
public interface RepoService extends IService<Repo> { // RepoService 接口,继承 MyBatis-Plus 的 IService提供常见数据库操作
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
public interface RepoService extends IService<Repo> {
/**
*
* @param reqDTO
* @return
* @param reqDTO
* @return
*/
IPage<RepoRespDTO> paging(PagingReqDTO<RepoReqDTO> reqDTO); // 分页查询方法,接收分页请求数据对象,并返回分页结果
IPage<RepoRespDTO> paging(PagingReqDTO<RepoReqDTO> reqDTO);
/**
*
* @param reqDTO
*
* @param reqDTO
*/
void save(RepoDTO reqDTO); // 保存题库方法,用于保存或更新题库信息
void save(RepoDTO reqDTO);
}

@ -1,49 +1,39 @@
package com.yf.exam.modules.repo.service.impl; // 包名:表示该类属于 repo.service.impl 包
package com.yf.exam.modules.repo.service.impl;
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 注解,标识该类为服务层组件
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;
/**
* <p>
*
* </p>
* RepoService
*
* @
* @ 2020-05-25 13:23
*/
@Service // Spring 注解,标识该类为服务层组件
public class RepoServiceImpl extends ServiceImpl<RepoMapper, Repo> implements RepoService { // 继承 MyBatis-Plus 提供的 ServiceImpl简化数据库操作
* <p>
*
* </p>
*
* @author
* @since 2020-05-25 13:23
*/
@Service
public class RepoServiceImpl extends ServiceImpl<RepoMapper, Repo> implements RepoService {
/**
*
* @param reqDTO
* @return
*/
@Override
public IPage<RepoRespDTO> paging(PagingReqDTO<RepoReqDTO> reqDTO) {
return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams()); // 调用 Mapper 的分页查询方法,传入分页信息和查询条件
return baseMapper.paging(reqDTO.toPage(), reqDTO.getParams());
}
/**
*
* @param reqDTO
*/
@Override
public void save(RepoDTO reqDTO) {
// 复制参数,将请求数据传输对象的属性复制到实体类中
Repo entity = new Repo(); // 创建 Repo 实体对象
BeanMapper.copy(reqDTO, entity); // 使用 BeanMapper 工具类复制属性
this.saveOrUpdate(entity); // 调用 MyBatis-Plus 提供的 saveOrUpdate 方法,保存或更新实体
//复制参数
Repo entity = new Repo();
BeanMapper.copy(reqDTO, entity);
this.saveOrUpdate(entity);
}
}

@ -1,71 +1,70 @@
package com.yf.exam.modules.sys.config.controller; // 包名:表示该类属于 sys.config.controller 包
package com.yf.exam.modules.sys.config.controller;
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 控制器
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;
/**
* <p>
*
* </p>
*
*
* @
* @ 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提供通用功能
* <p>
*
* </p>
*
* @author
* @since 2020-04-17 09:12
*/
@Api(tags={"通用配置"})
@RestController
@RequestMapping("/exam/api/sys/config")
public class SysConfigController extends BaseController {
@Autowired // 自动注入 SysConfigService 服务
@Autowired
private SysConfigService baseService;
@Autowired // 自动注入 ImageCheckUtils 工具类
@Autowired
private ImageCheckUtils imageCheckUtils;
/**
*
* @param reqDTO
* @return ID
*
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "添加或修改") // Swagger 注解:定义接口操作说明为“添加或修改”
@RequestMapping(value = "/save", method = { RequestMethod.POST}) // 定义请求路径为 /save方法为 POST
public ApiRest<BaseIdRespDTO> save(@RequestBody SysConfigDTO reqDTO) { // 定义保存或修改系统配置的方法
@RequiresRoles("sa")
@ApiOperation(value = "添加或修改")
@RequestMapping(value = "/save", method = { RequestMethod.POST})
public ApiRest<BaseIdRespDTO> save(@RequestBody SysConfigDTO reqDTO) {
// 复制请求参数到实体对象
SysConfig entity = new SysConfig(); // 创建 SysConfig 实体对象
BeanMapper.copy(reqDTO, entity); // 使用 BeanMapper 工具类将 DTO 的属性拷贝到实体对象
//复制参数
SysConfig entity = new SysConfig();
BeanMapper.copy(reqDTO, entity);
// 校验图片地址是否有效
imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误"); // 检查系统LOGO地址是否有效
// 校验图片地址
imageCheckUtils.checkImage(entity.getBackLogo(), "系统LOGO地址错误");
baseService.saveOrUpdate(entity); // 调用服务的保存或更新方法
return super.success(new BaseIdRespDTO(entity.getId())); // 返回成功响应,并包含系统配置 ID
baseService.saveOrUpdate(entity);
return super.success(new BaseIdRespDTO(entity.getId()));
}
/**
*
* @return
*
* @return
*/
@ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情”
@RequestMapping(value = "/detail", method = { RequestMethod.POST}) // 定义请求路径为 /detail方法为 POST
public ApiRest<SysConfigDTO> find() { // 定义查找系统配置详情的方法
SysConfigDTO dto = baseService.find(); // 调用服务查找系统配置详情
return super.success(dto); // 返回成功响应,包含系统配置详情
@ApiOperation(value = "查找详情")
@RequestMapping(value = "/detail", method = { RequestMethod.POST})
public ApiRest<SysConfigDTO> find() {
SysConfigDTO dto = baseService.find();
return super.success(dto);
}
}

@ -1,38 +1,39 @@
package com.yf.exam.modules.sys.config.dto; // 包名:表示该类属于 sys.config.dto 包
package com.yf.exam.modules.sys.config.dto;
import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型
import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性
import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; // 导入 Serializable 接口,用于对象序列化
import java.io.Serializable;
/**
* <p>
*
* </p>
* 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; // 定义字段:版权信息
* <p>
*
* </p>
*
* @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;
}

@ -1,54 +1,53 @@
package com.yf.exam.modules.sys.config.entity; // 包名:表示该类属于 sys.config.entity 包
package com.yf.exam.modules.sys.config.entity;
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 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;
/**
* <p>
*
* </p>
* `sys_config`
*
* @
* @ 2020-04-17 09:12
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@TableName("sys_config") // MyBatis-Plus 注解,指定该实体类映射数据库表名为 `sys_config`
public class SysConfig extends Model<SysConfig> { // SysConfig 类继承自 MyBatis-Plus 的 Model 类,启用 ActiveRecord 模式
private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查
* <p>
*
* </p>
*
* @author
* @since 2020-04-17 09:12
*/
@Data
@TableName("sys_config")
public class SysConfig extends Model<SysConfig> {
private static final long serialVersionUID = 1L;
/**
* ID
*/
@TableId(value = "id", type = IdType.ASSIGN_ID) // MyBatis-Plus 注解,标识主键字段,并指定主键生成策略为分配 ID
private String id; // 定义字段:系统配置的唯一标识符
@TableId(value = "id", type = IdType.ASSIGN_ID)
private String id;
/**
*
*/
@TableField("site_name") // MyBatis-Plus 注解,指定该字段映射数据库中的 "site_name" 列
private String siteName; // 定义字段:系统名称
@TableField("site_name")
private String siteName;
/**
* LOGO
*/
@TableField("front_logo") // MyBatis-Plus 注解,指定该字段映射数据库中的 "front_logo" 列
private String frontLogo; // 定义字段:前端展示的 LOGO 图片地址
@TableField("front_logo")
private String frontLogo;
/**
* LOGO
*/
@TableField("back_logo") // MyBatis-Plus 注解,指定该字段映射数据库中的 "back_logo" 列
private String backLogo; // 定义字段:后台管理系统的 LOGO 图片地址
@TableField("back_logo")
private String backLogo;
/**
*
*/
@TableField("copy_right") // MyBatis-Plus 注解,指定该字段映射数据库中的 "copy_right" 列
private String copyRight; // 定义字段:版权信息
@TableField("copy_right")
private String copyRight;
}

@ -1,18 +1,16 @@
package com.yf.exam.modules.sys.config.mapper; // 包名:表示该类属于 sys.config.mapper 包
package com.yf.exam.modules.sys.config.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; // 导入 MyBatis-Plus 的 BaseMapper 接口,用于基本的数据库操作
import com.yf.exam.modules.sys.config.entity.SysConfig; // 导入 SysConfig 实体类,表示系统配置
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yf.exam.modules.sys.config.entity.SysConfig;
/**
* <p>
* Mapper
* </p>
* MyBatis-Plus BaseMapper
*
* @
* @ 2020-04-17 09:12
*/
public interface SysConfigMapper extends BaseMapper<SysConfig> { // SysConfigMapper 接口,继承自 MyBatis-Plus 的 BaseMapper
* <p>
* Mapper
* </p>
*
* @author
* @since 2020-04-17 09:12
*/
public interface SysConfigMapper extends BaseMapper<SysConfig> {
// 该接口继承了 BaseMapper<SysConfig>,因此自动具备了 CRUD 方法,无需手动实现
}

@ -1,23 +1,22 @@
package com.yf.exam.modules.sys.config.service; // 包名:表示该类属于 sys.config.service 包
package com.yf.exam.modules.sys.config.service;
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 实体类,表示系统配置
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;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-04-17 09:12
*/
public interface SysConfigService extends IService<SysConfig> { // SysConfigService 接口继承 MyBatis-Plus 的 IService 接口,提供 CRUD 操作
* <p>
*
* </p>
*
* @author
* @since 2020-04-17 09:12
*/
public interface SysConfigService extends IService<SysConfig> {
/**
*
* @return DTO
* @return
*/
SysConfigDTO find(); // 定义查找系统配置信息的方法,返回一个 SysConfigDTO 对象
SysConfigDTO find();
}

@ -1,44 +1,34 @@
package com.yf.exam.modules.sys.config.service.impl; // 包名:表示该类属于 sys.config.service.impl 包
package com.yf.exam.modules.sys.config.service.impl;
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 注解,用于标识该类为服务层组件
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;
/**
* <p>
*
* </p>
* SysConfigService
*
* @
* @ 2020-04-17 09:12
*/
@Service // Spring 注解,标识该类为服务层组件
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements SysConfigService { // 继承 MyBatis-Plus 的 ServiceImpl 类,简化数据库操作
* <p>
*
* </p>
*
* @author
* @since 2020-04-17 09:12
*/
@Service
public class SysConfigServiceImpl extends ServiceImpl<SysConfigMapper, SysConfig> implements SysConfigService {
/**
*
* @return DTO
*/
@Override
public SysConfigDTO find() {
// 创建 QueryWrapper 对象,用于构建查询条件
QueryWrapper<SysConfig> wrapper = new QueryWrapper<>();
wrapper.last(" LIMIT 1"); // 限制查询结果为一条记录
wrapper.last(" LIMIT 1");
// 使用 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
SysConfig entity = this.getOne(wrapper, false);
SysConfigDTO dto = new SysConfigDTO();
BeanMapper.copy(entity, dto);
return dto;
}
}

@ -1,136 +1,150 @@
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 控制器
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;
/**
* <p>
*
* </p>
*
*
* @
* @ 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提供通用功能
* <p>
*
* </p>
*
* @author
* @since 2020-09-02 17:25
*/
@Api(tags={"部门信息"})
@RestController
@RequestMapping("/exam/api/sys/depart")
public class SysDepartController extends BaseController {
@Autowired // 自动注入 SysDepartService 服务
@Autowired
private SysDepartService baseService;
/**
*
* @param reqDTO
* @return
*
* @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(); // 返回成功响应
@RequiresRoles("sa")
@ApiOperation(value = "添加或修改")
@RequestMapping(value = "/save", method = { RequestMethod.POST})
public ApiRest save(@RequestBody SysDepartDTO reqDTO) {
baseService.save(reqDTO);
return super.success();
}
/**
*
* @param reqDTO ID
* @return
*
* @param reqDTO
* @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(); // 返回成功响应
@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
*
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "查找详情") // Swagger 注解:定义接口操作说明为“查找详情”
@RequestMapping(value = "/detail", method = {RequestMethod.POST}) // 定义请求路径为 /detail方法为 POST
public ApiRest<SysDepartDTO> find(@RequestBody BaseIdReqDTO reqDTO) { // 查找部门详情的方法
SysDepart entity = baseService.getById(reqDTO.getId()); // 根据 ID 查找部门实体
SysDepartDTO dto = new SysDepartDTO(); // 创建部门数据传输对象
BeanUtils.copyProperties(entity, dto); // 将实体对象属性拷贝到 DTO 对象
return super.success(dto); // 返回成功响应,包含部门详情
@RequiresRoles("sa")
@ApiOperation(value = "查找详情")
@RequestMapping(value = "/detail", method = { RequestMethod.POST})
public ApiRest<SysDepartDTO> find(@RequestBody BaseIdReqDTO reqDTO) {
SysDepart entity = baseService.getById(reqDTO.getId());
SysDepartDTO dto = new SysDepartDTO();
BeanUtils.copyProperties(entity, dto);
return super.success(dto);
}
/**
*
* @param reqDTO
* @return
*
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "分页查找") // Swagger 注解:定义接口操作说明为“分页查找”
@RequestMapping(value = "/paging", method = {RequestMethod.POST}) // 定义请求路径为 /paging方法为 POST
public ApiRest<IPage<SysDepartTreeDTO>> paging(@RequestBody PagingReqDTO<SysDepartDTO> reqDTO) { // 分页查找部门的方法
IPage<SysDepartTreeDTO> page = baseService.paging(reqDTO); // 调用服务进行分页查询
return super.success(page); // 返回成功响应,包含分页数据
@RequiresRoles("sa")
@ApiOperation(value = "分页查找")
@RequestMapping(value = "/paging", method = { RequestMethod.POST})
public ApiRest<IPage<SysDepartTreeDTO>> paging(@RequestBody PagingReqDTO<SysDepartDTO> reqDTO) {
//分页查询并转换
IPage<SysDepartTreeDTO> page = baseService.paging(reqDTO);
return super.success(page);
}
/**
* 200
* @param reqDTO
* @return
* 200
* @param reqDTO
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "查找列表") // Swagger 注解:定义接口操作说明为“查找列表”
@RequestMapping(value = "/list", method = {RequestMethod.POST}) // 定义请求路径为 /list方法为 POST
public ApiRest<List<SysDepartDTO>> list(@RequestBody SysDepartDTO reqDTO) { // 查找部门列表的方法
QueryWrapper<SysDepart> wrapper = new QueryWrapper<>(); // 创建查询条件
List<SysDepart> list = baseService.list(wrapper); // 获取部门列表
List<SysDepartDTO> dtoList = BeanMapper.mapList(list, SysDepartDTO.class); // 将部门实体列表转换为 DTO 列表
return super.success(dtoList); // 返回成功响应,包含部门列表
@RequiresRoles("sa")
@ApiOperation(value = "查找列表")
@RequestMapping(value = "/list", method = { RequestMethod.POST})
public ApiRest<List<SysDepartDTO>> list(@RequestBody SysDepartDTO reqDTO) {
//分页查询并转换
QueryWrapper<SysDepart> wrapper = new QueryWrapper<>();
//转换并返回
List<SysDepart> list = baseService.list(wrapper);
//转换数据
List<SysDepartDTO> dtoList = BeanMapper.mapList(list, SysDepartDTO.class);
return super.success(dtoList);
}
/**
*
* @return
*
* @return
*/
@RequiresRoles("sa") // 权限控制:要求用户具有 "sa" 角色
@ApiOperation(value = "树列表") // Swagger 注解:定义接口操作说明为“树列表”
@RequestMapping(value = "/tree", method = {RequestMethod.POST}) // 定义请求路径为 /tree方法为 POST
public ApiRest<List<SysDepartTreeDTO>> tree() { // 查找部门树状结构的方法
List<SysDepartTreeDTO> dtoList = baseService.findTree(); // 获取部门树状结构
return super.success(dtoList); // 返回成功响应,包含部门树状结构
@RequiresRoles("sa")
@ApiOperation(value = "树列表")
@RequestMapping(value = "/tree", method = { RequestMethod.POST})
public ApiRest<List<SysDepartTreeDTO>> tree() {
List<SysDepartTreeDTO> dtoList = baseService.findTree();
return super.success(dtoList);
}
/**
*
* @param reqDTO
* @return
*
* @param reqDTO
* @return
*/
@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(); // 返回成功响应
@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();
}
}

@ -1,41 +1,42 @@
package com.yf.exam.modules.sys.depart.dto; // 包名:表示该类属于 sys.depart.dto 包
package com.yf.exam.modules.sys.depart.dto;
import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型
import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性
import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; // 导入 Serializable 接口,用于支持对象序列化
import java.io.Serializable;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-09-02 17:25
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@ApiModel(value = "部门信息", description = "部门信息") // Swagger 注解:定义该类的 API 模型名称和描述
public class SysDepartDTO implements Serializable { // 实现 Serializable 接口以支持序列化
* <p>
*
* </p>
*
* @author
* @since 2020-09-02 17:25
*/
@Data
@ApiModel(value="部门信息", description="部门信息")
public class SysDepartDTO implements 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 = "1公司2部门", required = true) // Swagger 注解描述该属性为“1公司2部门”并标记为必填
private Integer deptType; // 定义字段部门类型1 表示公司2 表示部门
@ApiModelProperty(value = "ID", required=true)
private String id;
@ApiModelProperty(value = "所属上级", required = true) // Swagger 注解:描述该属性为“所属上级”,并标记为必填
private String parentId; // 定义字段:上级部门的 ID
@ApiModelProperty(value = "1公司2部门", required=true)
private Integer deptType;
@ApiModelProperty(value = "部门名称", required = true) // Swagger 注解:描述该属性为“部门名称”,并标记为必填
private String deptName; // 定义字段:部门名称
@ApiModelProperty(value = "所属上级", required=true)
private String parentId;
@ApiModelProperty(value = "部门编码", required = true) // Swagger 注解:描述该属性为“部门编码”,并标记为必填
private String deptCode; // 定义字段:部门的唯一编码,用于标识部门
@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 Integer sort; // 定义字段:部门排序序号,用于定义显示顺序
}

@ -1,29 +1,28 @@
package com.yf.exam.modules.sys.depart.dto.request; // 包名:表示该类属于 sys.depart.dto.request 包
package com.yf.exam.modules.sys.depart.dto.request;
import io.swagger.annotations.ApiModel; // 导入 Swagger 注解,用于定义 API 模型
import io.swagger.annotations.ApiModelProperty; // 导入 Swagger 注解,用于描述 API 模型的属性
import lombok.Data; // 导入 Lombok 注解,用于自动生成 Getter、Setter、toString 等方法
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable; // 导入 Serializable 接口,用于对象序列化
import java.io.Serializable;
/**
* <p>
*
* </p>
*
*
* @
* @ 2020-03-14 10:37
*/
@Data // Lombok 注解,自动生成 Getter、Setter 和其他方法
@ApiModel(value = "部门排序请求类", description = "部门排序请求类") // Swagger 注解:定义该类的 API 模型名称和描述
public class DepartSortReqDTO implements Serializable { // 实现 Serializable 接口以支持序列化
* <p>
*
* </p>
*
* @author
* @since 2020-03-14 10:37
*/
@Data
@ApiModel(value="部门排序请求类", description="部门排序请求类")
public class DepartSortReqDTO implements Serializable {
private static final long serialVersionUID = 1L; // 序列化版本号,用于序列化和反序列化的一致性检查
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "分类ID") // Swagger 注解描述该属性为“分类ID”
private String id; // 定义字段:分类的唯一标识符
@ApiModelProperty(value = "分类ID")
private String id;
@ApiModelProperty(value = "排序0下降1上升") // Swagger 注解描述该属性为“排序”0 表示下降1 表示上升
private Integer sort; // 定义字段排序方式0 为下降排序1 为上升排序
@ApiModelProperty(value = "排序0下降1上升")
private Integer sort;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save