最近有一个项目需要将一个word文档中的试题数据导入,并存储到数据库中。试题类型包括:单选题、多选题、判断题、填空题、简答题。支持图片导入(我的这篇是借鉴JAVA实现Excel、Word模板导入 - JAVA - 华仔部落,java poi 解析上传word试卷(题库管理系统) - 爱码网)这两位大神的。
废话不多说,进入正题,直接上代码。
一、word模板
要求:
1)、题目间隔:上一题与下一题之间必须换行,开始下一题;
2)、试题编辑的样式:[单选题][答案][章][节][考点][难度] [解析]是固定样式,不能删除。 如果试题无[解析],无[章][节][考点][难度],可以不填。
二、代码:
1、引入依赖
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.1</version>
</dependency>
2、创建VO对象TestQuestionsImportVo和TestQuestionsImportWordVo
/**
* 试题导入对应字段
*/
@Data
public class TestQuestionsImportVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 试题类型1=单选2=多选3=判断4=填空5=简答,6=不定项,7=材料题
*/
private Integer type;
/**
* 题目名称
*/
private String name;
/**
* 答案
*/
private String answer;
/**
* 选项A
*/
private String optionA;
/**
* 选项B
*/
private String optionB;
/**
* 选项C
*/
private String optionC;
/**
* 选项D
*/
private String optionD;
/**
* 选项E
*/
private String optionE;
/**
* 选项F
*/
private String optionF;
/**
* 选项G
*/
private String optionG;
/**
* 选项H
*/
private String optionH;
/**
* 选项I
*/
private String optionI;
/**
* 选项J
*/
private String optionJ;
/**
* 选项K
*/
private String optionK;
/**
* 选项L
*/
private String optionL;
/**
* 文字解析
*/
private String analysis;
/**
* 难度,1=简单,2=一般,3=困难
*/
private String difficulty;
/**
* 题库章名称
*/
private String qbChapName;
/**
* 题库节名称
*/
private String qbNodeName;
/**
* 题库考点名称
*/
private String qbExsiName;
}
/**
* 试题导入对应字段
*/
@Data
public class TestQuestionsImportWordVo extends TestQuestionsImportVo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 材料题字试题
*/
private List<TestQuestionsImportWordVo> children;
/**
* 题目名称图片
*/
private List<XWPFPicture> questionNameXwpfPicture;
/**
* 选项A图片
*/
private List<XWPFPicture> optionXwpfPictureA;
/**
* 选项B图片
*/
private List<XWPFPicture> optionXwpfPictureB;
/**
* 选项C图片
*/
private List<XWPFPicture> optionXwpfPictureC;
/**
* 选项D图片
*/
private List<XWPFPicture> optionXwpfPictureD;
/**
* 选项E图片
*/
private List<XWPFPicture> optionXwpfPictureE;
/**
* 选项F图片
*/
private List<XWPFPicture> optionXwpfPictureF;
/**
* 选项G图片
*/
private List<XWPFPicture> optionXwpfPictureG;
/**
* 选项H图片
*/
private List<XWPFPicture> optionXwpfPictureH;
/**
* 选项I图片
*/
private List<XWPFPicture> optionXwpfPictureI;
/**
* 选项J图片
*/
private List<XWPFPicture> optionXwpfPictureJ;
/**
* 选项K图片
*/
private List<XWPFPicture> optionXwpfPictureK;
/**
* 选项L图片
*/
private List<XWPFPicture> optionXwpfPictureL;
}
3、word解析试题核心代码
/**
* word导入处理
*/
public class ImportWordParagraphHandleUtil {
// 该正则用来匹配一个大题(例如:二、多选题)
private static String bigQuestionRegex = "([一|二|三|四|五|六|七|八|九|十]{1,3})([、.]{1})([\\u4E00-\\u9FA5\\s]+题)";
// 该正则用来匹配一个选项(例如:A\B\C\D)
private static String optionRegex = "([A|B|C|D|E|F|G|H|I|J|K|L]{1,3})";
/**
* 解析导入题目word模板
*
* @param file
*/
public static List<TestQuestionsImportWordVo> analysisImportQuestionSubjectWord(MultipartFile file) throws IOException {
List<TestQuestionsImportWordVo> questionsImportWordVoList = new ArrayList<>();
// 获取文件流
InputStream fileInputStream = file.getInputStream();
// 解析文档
XWPFDocument xd = new XWPFDocument(fileInputStream);
// 获取全部的文本段落
List<XWPFParagraph> xwPfParagraphList = xd.getParagraphs();
// 过滤掉 大题(例如:二、多选题) 开头的段落
xwPfParagraphList = xwPfParagraphList.stream().filter(xwpfParagraph -> !Pattern.compile(bigQuestionRegex).matcher(getObjectValue(xwpfParagraph.getText())).find()).collect(Collectors.toList());
// 题目段落列表
List<List<XWPFParagraph>> subjectParagraphList = generateSubjectParagraphList(xwPfParagraphList);
if (CollectionUtil.isEmpty(subjectParagraphList)) {
return questionsImportWordVoList;
}
for (List<XWPFParagraph> xwpfParagraphs : subjectParagraphList) {
// 解析考试题目保存对象根据段落列表
TestQuestionsImportWordVo testQuestionsImportWordVo = analysisQuestionsSubjectByParagraph(xwpfParagraphs);
questionsImportWordVoList.add(testQuestionsImportWordVo);
}
return questionsImportWordVoList;
}
/**
* 按照题目生成 段落列表
* 每个题目一个段落列表
*
* @param xwPfParagraphLis
* @return
*/
private static List<List<XWPFParagraph>> generateSubjectParagraphList(List<XWPFParagraph> xwPfParagraphLis) {
List<List<XWPFParagraph>> list = new ArrayList<>();
if (CollectionUtil.isEmpty(xwPfParagraphLis)) {
return list;
}
boolean isStart = false;
list.add(new ArrayList<XWPFParagraph>());
for (int i = 9; i < xwPfParagraphLis.size(); i++) {
// 当前项
XWPFParagraph xwPfParagraphLi = xwPfParagraphLis.get(i);
// 获取文本内容
String text = xwPfParagraphLi.getText();
//获取图片内容
List<XWPFPicture> pictures = StrUtil.isEmpty(text) ? CollectionUtil.isNotEmpty(xwPfParagraphLi.getRuns()) ? xwPfParagraphLi