考试题库通过excel导入试题

发布时间 2023-11-16 14:22:30作者: 不是代屿

ps:最近在做的考试试题导入,留个痕

本人有点菜,实现方式有些简单,各位有什么优化也可以拿去改,0.0;

这个方法可以获取对象试题字段的字段值 和字段名 并且可以根据字段上的注解判断字段是否要处理 有类似的业务还是可以用用的

一.demo测试代码:


public static void main(String[] args) {
AssetsApply assetsApply = new AssetsApply();
Class<?> clazz = assetsApply.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String fieldName = field.getName();
if (field.isAnnotationPresent(ApiModelProperty.class) && fieldName.contains("ageName")) {
field.setAccessible(true);
try {
String fieldValue = (String) field.get(assetsApply);
//字段值不为空
if (StringUtils.isNotBlank(fieldName)) {
System.out.println("fieldName = " + fieldName);
System.out.println("fieldValue = " + fieldValue);
String last = fieldName.substring(fieldName.length() - 1);
System.out.println("last = " + last);
ArrayList<String> strList = new ArrayList<>();
strList.add("a");
System.out.println("strList.contains(last) = " + strList.contains(last));
strList.add("b");
System.out.println("strList.contains(last) = " + strList.contains(last));
strList.add("e");
System.out.println("strList.contains(last) = " + strList.contains(last));
strList.add("c");
System.out.println("strList.contains(last) = " + strList.contains(last));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
























二.业务逻辑代码
我个人主要是使用的easyExcel加上hutu和ruoyi的工具类直接做的比较方便
1.service代码
/**
* 模板导入试题
* @param file 导入excel文件
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean importQuestions(MultipartFile file, String repoId) {
Assert.isTrue(!file.isEmpty(), "导入数据为空");
importQuestionsListener.setQuestions(new LinkedList<>());
importQuestionsListener.setRepoId(repoId);
String filename = file.getOriginalFilename();
// 判断文件类型
Assert.isTrue(StringUtils.endsWith(filename, "xlsx") || StringUtils.endsWith(filename, "xls"),
"只支持.xlsx或者.xls类型文件导入");
try {
EasyExcel.read(file.getInputStream(), ExamQuestionDto.class, importQuestionsListener)
.sheet().doRead();
return true;
} catch (IOException e) {
return false;
}
}













2.easyExcel的监听器



package com.zy.learn.exam.listener;

import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.zy.common.dto.learn.exam.ExamQuestionDto;
import com.zy.common.entity.learn.exam.ExamAnswer;
import com.zy.common.entity.learn.exam.ExamQuestion;
import com.zy.common.enums.learn.exam.ExamQuestionCategoryEnum;
import com.zy.common.utils.StringUtils;
import com.zy.learn.exam.service.ExamAnswerService;
import com.zy.learn.exam.service.ExamQuestionService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 导入试题监听器
*
* @Name ImportQuestionslistener
* @Author hhx
* @Date 2023-11-15 10:28
*/
@Slf4j
@Component
@Scope("prototype")
@RequiredArgsConstructor
public class ImportQuestionsListener extends AnalysisEventListener<ExamQuestionDto> {

private final ExamQuestionService questionService;

private final ExamAnswerService answerService;

private List<ExamQuestion> questions;
private String repoId;

public void setQuestions(List<ExamQuestion> questions) {
this.questions = questions;
}

public List<ExamQuestion> getQuestions() {
return questions;
}

public void setRepoId(String repoId) {
this.repoId = repoId;
}

public String getRepoId() {
return repoId;
}

public static Map<String, Object> map = new HashMap<>();


/**
* 读取
*
* @param questionDto
* @param analysisContext
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void invoke(ExamQuestionDto questionDto, AnalysisContext analysisContext) {
ExamQuestion question = new ExamQuestion();
//处理读取到的答案
List<ExamAnswer> answers = handAnswers(questionDto);
//先都不给问题和答案id
question.setCategory(ExamQuestionCategoryEnum.getByValue(questionDto.getCategory()).getCategory())
.setText(questionDto.getQuestionText())
.setRemark(questionDto.getRemark())
.setAnswers(answers)
.setRepoId(getRepoId());
this.questions.add(question);
}


/**
* 执行完毕
* 保存试卷
*
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
//1.准备答案集合
ArrayList<ExamAnswer> examAnswers = new ArrayList<>();
//2.处理问题/答案 完善实体
questions.stream().forEach(question -> {
String questionId = IdUtil.getSnowflakeNextIdStr();
question.setQuestionId(questionId);
List<ExamAnswer> answers = question.getAnswers();
if (answers.size() > 0) {
answers.stream().forEach(answer -> {
answer.setAnswerId(IdUtil.getSnowflakeNextIdStr())
.setQuestionId(questionId);
});
examAnswers.addAll(answers);
}

});

//3.保存
//保存试题
questionService.saveBatch(questions);
//保存答案
answerService.saveBatch(examAnswers);


//执行完毕后,清空数据
setQuestions(null);
setRepoId(null);

log.info("试题导入成功");
}

/**
* 根据读取数据生成答案list
*
* @param questionDto
* @return
*/
private List<ExamAnswer> handAnswers(ExamQuestionDto questionDto) {
//1.准备答案集合
ArrayList<ExamAnswer> examAnswers = new ArrayList<>();
//正确答案集合
String correctOption = questionDto.getCorrectOption();
//2.通过反射获取对象字段相关信息
Class<?> clazz = questionDto.getClass();
Field[] fields = clazz.getDeclaredFields();

for (Field field : fields) {
ExamAnswer answer = new ExamAnswer();
String filedName = field.getName();
//3.读取字段中带option 且有easyExcel注解的
if (field.isAnnotationPresent(ExcelProperty.class) && filedName.contains("option")) {
//4.满足上述条件修改字段为可操作
field.setAccessible(true);
try {
String fieldValue = (String) field.get(questionDto);
//5.字段值不为空
if (StringUtils.isNotBlank(fieldValue)) {
//6.封装实体对象
//获取选项是A,B,C.....中的哪个 我的字段名optionABC....
String option = filedName.substring(filedName.length() - 1);
//6.1选项ABC字段
answer.setAbc(option);
//6.2 是否正确答案 选项ABC在正确答案集合correctOption内为正确答案
if (correctOption.contains(option)) {
answer.setIsRight(1);
}
//6.3 答案文本
answer.setText(fieldValue);
examAnswers.add(answer);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
return examAnswers;
}


}































































































































3.导入的模板和实体

 

 @Data
public class ExamQuestionDto {

@ExcelProperty(value = "题干", index = 1)
private String questionText;

@ExcelProperty(value = "试题类型", index = 2)
private String category;

@ExcelProperty(value = "正确答案", index = 3)
private String correctOption;

@ExcelProperty(value = "题解", index = 4)
private String remark;

@ExcelProperty(value = "选项A", index = 5)
private String optionA;

@ExcelProperty(value = "选项B", index = 6)
private String optionB;

@ExcelProperty(value = "选项C", index = 7)
private String optionC;

@ExcelProperty(value = "选项D", index = 8)
private String optionD;

@ExcelProperty(value = "选项E", index = 9)
private String optionE;

@ExcelProperty(value = "选项F", index = 10)
private String optionF;

@ExcelProperty(value = "选项G", index = 11)
private String optionG;

@ExcelProperty(value = "选项H", index = 12)
private String optionH;

@ExcelProperty(value = "选项I", index = 13)
private String optionI;

@ExcelProperty(value = "选项J", index = 14)
private String optionJ;

@ExcelProperty(value = "选项K", index = 15)
private String optionK;

@ExcelProperty(value = "选项L", index = 16)
private String optionL;

@ExcelProperty(value = "选项M", index = 17)
private String optionM;

@ExcelProperty(value = "选项N", index = 18)
private String optionN;

@ExcelProperty(value = "选项O", index = 19)
private String optionO;


}
















































4.数据库表实体
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_learn_exam_answer")
@ApiModel(value="ExamAnswer对象", description="学习考试答案表")
public class ExamAnswer extends BaseEntity {

private static final long serialVersionUID = 1L;

@ApiModelProperty(value = "答案id")
@TableId(value = "answer_id", type = IdType.ASSIGN_ID)
private String answerId;

@ApiModelProperty(value = "答案内容")
@TableField("text")
private String text;

@ApiModelProperty(value = "是否是正确答案(0/1是)")
@TableField("is_right")
private Integer isRight;

@ApiModelProperty(value = "问题id")
@TableField("question_id")
private String questionId;

@ApiModelProperty(value = "选项(A,B,C....")
@TableField("abc")
private String abc;

@ApiModelProperty(value = "答案图片url")
@TableField("url")
private String url;

@ApiModelProperty(value = "删除标志(0/1)")
@TableField("del_flag")
private Integer delFlag;

@ApiModelProperty(value = "所属公司(备用字段)")
@TableField("company")
private String company;
}
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("t_learn_exam_question")
@ApiModel(value="ExamQuestion对象", description="学习考试试题表")
public class ExamQuestion extends BaseEntity {

private static final long serialVersionUID = 1L;

@ApiModelProperty(value = "试题id")
@TableId(value = "question_id", type = IdType.ASSIGN_ID)
private String questionId;

@ApiModelProperty(value = "题库id")
@TableField("repo_id")
@NotBlank
private String repoId;

@ApiModelProperty(value = "题干")
@TableField("text")
@NotBlank
private String text;

@ApiModelProperty(value = "试题类型(0单选题/1多选题/2判断题)")
@TableField("category")
private Integer category;

@ApiModelProperty(value = "答案要点")
@TableField("remark")
private String remark;

@ApiModelProperty(value = "试题图片附件url")
@TableField("url")
private String url;

@ApiModelProperty(value = "删除标志(0未删除/1已删除)")
@TableField("del_flag")
private Integer delFlag;

@ApiModelProperty(value = "所属公司(备用字段)")
@TableField("company")
private String company;

@ApiModelProperty(value = "答案集合")
@TableField(exist = false)
private List<ExamAnswer> answers;

@ApiModelProperty(value = "正确答案")
@TableField(exist = false)
private String correctOption;

@ApiModelProperty(value = "题库名称")
@TableField(exist = false)
private String repoName;


}