手把手教你用poi导入word试卷

相信点击来看文章的都是被公司业务折磨的小伙伴,某个风和日丽的下午,你的老大:“给我搞个word批量导入,这么简单你不会不会吧?,不是吧不是吧这年头居然有人不会做word批量导入…balabala~"。
哈哈,不开玩笑了,下面进入正题。
其实对文档进行读取有很多包可以解决,像Jacob,Docx4j,OpenOffice,PageOffice,FreeMarker等等,总之方式有很多种有精力的话可以去深度学习一下,这里说一下作者使用的是POI组件,原因是百度上有很多关于poi操作word、excel的博文(虽然有很多都是雷同文章),相比较其他的方式来说有参考性。

下面列举下一些常见包的优缺点:

  • Jacob是Java-COM Bridge的缩写,它在Java与微软的COM组件之间构建一座桥梁。通过Jacob实现了在Java平台上对微软Office的COM接口进行调用。

优点: 调用微软Office的COM接口,生成的word文件格式规范。
缺点: 服务器只能是windows平台,不支持unix和linux,且服务器上必须安装微软Office。

  • Apache POI包括一系列的API,它们可以操作基于MicroSoft OLE 2 Compound Document Format的各种格式文件,可以通过这些API在Java中读写Excel、Word等文件。

优点:跨平台支持windows、unix和linux。
缺点:相对与对word文件的处理来说,POI更适合excel处理,对于word实现一些简单文件的操作凑合,不能设置样式且生成的word文件格式不够规范。

  • FreeMarker生成word文档的功能是由XML+FreeMarker来实现的。先把word文件另存为xml,在xml文件中插入特殊的字符串占位符,将xml翻译为FreeMarker模板,最后用java来解析FreeMarker模板,编码调用FreeMarker实现文本替换并输出Doc。

优点:比Java2word功能强大,也是纯Java编程。
缺点:生成的文件本质上是xml,不是真正的word文件格式,有很多常用的word格式无法处理或表现怪异,比如:超链、换行、乱码、部分生成的文件打不开等。

  • PageOffice生成word文件。PageOffice封装了微软Office繁琐的vba接口,提供了简洁易用的Java编程对象,支持生成word文件,同时实现了在线编辑word文档和读取word文档内容。

优点:跨平台支持windows、unix和linux,生成word文件格式标准,支持文本、图片、表格、字体、段落、颜色、超链、页眉等各种格式的操作,支持多word合并,无需处理并发,不耗费服务器资源,运行稳定。
缺点:必须在客户端生成文件(可以不显示界面),不支持纯服务器端生成文件。

由于作者在公司负责的项目是运行在linux上的,加之也没有太多时间就选择了poi,按照大佬们的方式去完成了业务,起初对这个一点都不了解,做的让人头秃。好在后面完成了比较简单的功能实现,能满足基本的需求。
在这里插入图片描述

POI读取操作步骤

1.导入poi相关jar包

第一步当然是先上maven仓库找到poi的依赖了(什么?你的项目不用maven?那你要上去下载jar包呀),直接上去搜poi。下面是作者使用的jar包依赖:

 		<dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.3</version>
        </dependency>

读取的话只需要上面的就够了,下面是将字符写到word上需要的。关于版本,选择使用次数比较多的稳定版本就行,不需要追求高版本,作者这里是项目之前使用了excel导出,选择3.15是为了跟之前的保持一致。

2.得到文件的输入流

依赖导入后,那么就可以正式来读取word了,我的方式是采用表单对象获取文件输入流,再根据XWPFDocument对象获取文档内容。它的构造方法里是有输入流这中方式的。那我们直接使用MultipartFile对象的getInputStream方法来获取输入流。

 @PostMapping("templates/question/wordFileImport")
    public BaseResult wordFileImport(@RequestParam("word") MultipartFile file, UserInfoVO userInfoVO) {
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            XWPFDocument xDocument = new XWPFDocument(inputStream);

获取XWPFDocument对象我们就可以获取文档的段落和图片了,分别是getParagraphs()和getAllPictures()这两个方法。如下:

 //段落对象列表
 List<XWPFParagraph> paragraphs = xDocument.getParagraphs();
 //图片对象列表
 List<XWPFPictureData> pictures = xDocument.getAllPictures();

注意:poi中获取的图片都是没有直接获取位置的,只有一个索引值,我们需要根据索引值去确定位置。
我保存图片的方式是定义一个map去存储。如下:

 			Map<String, String> map = new HashMap<String, String>();
            for (XWPFPictureData picture : pictures) {
            	//索引值
                String id = picture.getParent().getRelationId(picture);
                //文件名
                String rawName = picture.getFileName();
                //获取图片的字节数据
                byte[] data = picture.getData();

				//这里是将获取的图片数据上传到阿里云,可以看我的另一篇文章
                OssUploadDTO dto = new OssUploadDTO(data,rawName,"-1", FileCategoryEnum.QUESTION.getValue());
                OssFileInfoDTO ossFileInfoDTO = aliyunOssFileManageService.uploadOnePicFile(dto);
                String cloudSrc = ossFileInfoDTO.getCloudSrc();
                //将索引值作为键 url链接作为值存入map
                map.put(id, cloudSrc);
            }

下面直接获取所有的段落,图片在原段落中是以特殊xml标签存储的,每一个标签都有上面说到的索引值,下面要利用索引值获取图片在段落中的位置,代码如下:

 			String text = "";
            for (XWPFParagraph paragraph : paragraphs) {
                //System.out.println(paragraph.getParagraphText());
                //段落分为多个XWPFRun对象
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //XWPFRun是POI对xml元素解析后生成的自己的属性,无法通过xml解析,需要先转化成CTR
                    boolean flag = false;
                    CTR ctr = run.getCTR();
                    //对子元素进行遍历
                    XmlCursor c = ctr.newCursor();
                    //这个就是拿到所有的子元素:
                    c.selectPath("./*");
                    while (c.toNextSelection()) {
                        XmlObject o = c.getObject();
                        //如果子元素是<w:drawing>这样的形式,使用的是CTDrawing保存图片
                        if (o instanceof CTDrawing) {
                            CTDrawing drawing = (CTDrawing) o;
                            CTInline[] ctInlines = drawing.getInlineArray();
                            for (CTInline ctInline : ctInlines) {
                                CTGraphicalObject graphic = ctInline.getGraphic();
                                XmlCursor cursor = graphic.getGraphicData().newCursor();
                                cursor.selectPath("./*");
                                while (cursor.toNextSelection()) {
                                    XmlObject xmlObject = cursor.getObject();
                                    if (xmlObject instanceof CTPicture) {
                                        org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) xmlObject;
                                        //拿到元素的属性 picture.getBlipFill().getBlip().getEmbed() 是获取索引值 
                                        String url = map.get(picture.getBlipFill().getBlip().getEmbed());
                                        //拼接
                                        text = text + url;
                                        flag = true;
                                    }
                                }
                            }     
                        } else if (o instanceof CTObject) {//另一种则是CTObject类型 类似于上面
                            CTObject object = (CTObject) o;
                            System.out.println(object);
                            XmlCursor w = object.newCursor();
                            w.selectPath("./*");
                            while (w.toNextSelection()) {
                                XmlObject xmlObject = w.getObject();
                                if (xmlObject instanceof CTShape) {
                                    CTShape shape = (CTShape) xmlObject;
                                    String url = map.get(shape.getImagedataArray()[0].getId());
                                    text = text + url;
                                    flag = true;
                                }
                            }
                        }
                    }
                    if (!flag) {
                        text = text + run;
                    }
                }
            }

下面放出完整代码:

 /**
     * Word(图片)导入题目到题库
     *
     * @return
     */
    @PostMapping("templates/question/wordFileImport")
    public BaseResult wordFileImport(@RequestParam("word") MultipartFile file, UserInfoVO userInfoVO) {
        InputStream inputStream = null;
        try {
            inputStream = file.getInputStream();
            XWPFDocument xDocument = new XWPFDocument(inputStream);
            List<XWPFParagraph> paragraphs = xDocument.getParagraphs();
            List<XWPFPictureData> pictures = xDocument.getAllPictures();
            Map<String, String> map = new HashMap<String, String>();
            for (XWPFPictureData picture : pictures) {

                String id = picture.getParent().getRelationId(picture);
                String rawName = picture.getFileName();
                byte[] data = picture.getData();

                OssUploadDTO dto = new OssUploadDTO(data,rawName,"-1", FileCategoryEnum.QUESTION.getValue());
                OssFileInfoDTO ossFileInfoDTO = aliyunOssFileManageService.uploadOnePicFile(dto);
                String cloudSrc = ossFileInfoDTO.getCloudSrc();
                map.put(id, cloudSrc);
            }
            String text = "";
            for (XWPFParagraph paragraph : paragraphs) {
                //System.out.println(paragraph.getParagraphText());
                List<XWPFRun> runs = paragraph.getRuns();
                for (XWPFRun run : runs) {
                    //XWPFRun是POI对xml元素解析后生成的自己的属性,无法通过xml解析,需要先转化成CTR
                    boolean flag = false;
                    CTR ctr = run.getCTR();
                    //对子元素进行遍历
                    XmlCursor c = ctr.newCursor();
                    //这个就是拿到所有的子元素:
                    c.selectPath("./*");
                    while (c.toNextSelection()) {
                        XmlObject o = c.getObject();
                        //如果子元素是<w:drawing>这样的形式,使用CTDrawing保存图片
                        if (o instanceof CTDrawing) {
                            CTDrawing drawing = (CTDrawing) o;
                            CTInline[] ctInlines = drawing.getInlineArray();
                            for (CTInline ctInline : ctInlines) {
                                CTGraphicalObject graphic = ctInline.getGraphic();
                                XmlCursor cursor = graphic.getGraphicData().newCursor();
                                cursor.selectPath("./*");
                                while (cursor.toNextSelection()) {
                                    XmlObject xmlObject = cursor.getObject();
                                    if (xmlObject instanceof CTPicture) {
                                        org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture picture = (org.openxmlformats.schemas.drawingml.x2006.picture.CTPicture) xmlObject;
                                        //拿到元素的属性
                                        String url = map.get(picture.getBlipFill().getBlip().getEmbed());
                                        text = text + url;
                                        flag = true;
                                    }
                                }
                            }
                        } else if (o instanceof CTObject) {
                            CTObject object = (CTObject) o;
                            System.out.println(object);
                            XmlCursor w = object.newCursor();
                            w.selectPath("./*");
                            while (w.toNextSelection()) {
                                XmlObject xmlObject = w.getObject();
                                if (xmlObject instanceof CTShape) {
                                    CTShape shape = (CTShape) xmlObject;
                                    String url = map.get(shape.getImagedataArray()[0].getId());
                                    text = text + url;
                                    flag = true;
                                }
                            }
                        }
                    }
                    if (!flag) {
                        text = text + run;
                    }
                }
            }
            questionWordManageService.wordImportQuestion(text, userInfoVO.getUserId());
        } catch (IOException e) {
            LOG.error("WORD导入获取流异常:" + e.getMessage());
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    LOG.error("WORD导入关闭流异常:" + e.getMessage());
                }
            }
        }
        return BaseResult.getSuccessResult();
    }

3.对处理好的字符串进行操作

经过上面的操作就可以将获取的内容转成字符串格式了,接下来就是对字符进行操作,根据自己需要的方式去截取需要的内容即可,这样就大功告成了。是不是很简单呢?当然这只是比较简单的,而且图片的获取也不是100%能截取到,不过只要用户不是用奇奇怪怪的图片格式就行,反正我的项目没出现过什么奇怪问题。

注意:上传的文档不要包含重复图片,貌似是poi自动对图片文件的md5进行处理了,会过滤掉重复的图片。Word本质也是一个压缩包嘛,图片都是存储在包下的某个路径的,感兴趣的可以自己试试。

最后运行速度就看你的字符处理得不得当了,听说新版本的java有很多高效的字符处理方法。

下面讲一下word导出的形式:

操作POI导出字符到word

1.获取HttpServletResponse

作者的导出是在后台对数据操作然后进行导出的,所以使用了HttpServletResponse对象将最后的文件流输出。

2.重写XWPFDocument的方法

直接拷贝下面的代码到自己项目中,建议类名跟我保持一致,方便排查。

package com.yijiupi.himalaya.word;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author LiJunJie
 * @Descripiton:
 * @create 2020-08-20 16:30
 */
public class CustomXWPFDocument extends XWPFDocument {
    public CustomXWPFDocument() {
        super();
    }

    public CustomXWPFDocument(OPCPackage opcPackage) throws IOException {
        super(opcPackage);
    }

    public CustomXWPFDocument(InputStream in) throws IOException {
        super(in);
    }

    public void createPicture(String blipId, int id, int width, int height) {
        final int EMU = 9525;
        width *= EMU;
        height *= EMU;
        //String blipId = getAllPictures().get(id).getPackageRelationship().getId();


        CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline();

        String picXml = "" +
                "<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +
                " <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                " <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +
                " <pic:nvPicPr>" +
                " <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +
                " <pic:cNvPicPr/>" +
                " </pic:nvPicPr>" +
                " <pic:blipFill>" +
                " <a:blip r:embed=\"" + blipId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +
                " <a:stretch>" +
                " <a:fillRect/>" +
                " </a:stretch>" +
                " </pic:blipFill>" +
                " <pic:spPr>" +
                " <a:xfrm>" +
                " <a:off x=\"0\" y=\"0\"/>" +
                " <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +
                " </a:xfrm>" +
                " <a:prstGeom prst=\"rect\">" +
                " <a:avLst/>" +
                " </a:prstGeom>" +
                " </pic:spPr>" +
                " </pic:pic>" +
                " </a:graphicData>" +
                "</a:graphic>";

        //CTGraphicalObjectData graphicData = inline.addNewGraphic().addNewGraphicData();
        XmlToken xmlToken = null;
        try {
            xmlToken = XmlToken.Factory.parse(picXml);
        } catch (XmlException xe) {
            xe.printStackTrace();
        }
        inline.set(xmlToken);
        //graphicData.set(xmlToken);

        inline.setDistT(0);
        inline.setDistB(0);
        inline.setDistL(0);
        inline.setDistR(0);

        CTPositiveSize2D extent = inline.addNewExtent();
        extent.setCx(width);
        extent.setCy(height);

        CTNonVisualDrawingProps docPr = inline.addNewDocPr();
        docPr.setId(id);
        docPr.setName("Picture " + id);
        docPr.setDescr("Generated");
    }
}

在需要使用的地方创建刚刚写的CustomXWPFDocument对象,由于作者是做的业务功能是导出试卷,所以对文档操作比较少,详细的格式大家可以百度下,下面放出我的格式:

private static void setDefaultStyle(XWPFRun run) {
        run.setTextPosition(3);//设置行间距
        run.setBold(false);//加粗
        run.setColor("000000");//设置颜色--十六进制
        run.setFontFamily("宋体");//字体
        run.setFontSize(12);//字体大小
    }
    
private static void setOtherStyle(XWPFRun run) {
        run.setTextPosition(3);//设置行间距
        run.setBold(false);//加粗
        run.setColor("000000");//设置颜色--十六进制
        run.setFontFamily("宋体");//字体
        run.setFontSize(10);//字体大小
    }

利用CustomXWPFDocument对象创建段落:

CustomXWPFDocument document = new CustomXWPFDocument();
//创建段落对象
XWPFParagraph paragraph = document.createParagraph();
//设置对齐方式
paragraph.setAlignment(ParagraphAlignment.LEFT);//对齐方式为左对齐
//段落中创建 XWPFRun 对象
XWPFRun runHead = paragraph.createRun();
//设置格式
setDefaultStyle(runHead);
//获取你要导出的内容
String content = "放入你需要导出的内容";
//内容设置
runHead.setText(questionHeader);

以上是普通字符内容创建的方式,下面说一下图片的创建方式:

				//获取图片链接
				String imageUrl = dto.getImageUrl();
                if (StringUtils.hasText(imageUrl)) {
                	//图片类型数字获取 poi只支持部分图片格式 
                    int fileType = getFileType(imageUrl.substring(imageUrl.lastIndexOf(".")));
                    if (fileType < 2) {
                        continue;
                    }
                    //获取图片的字节数组
                    byte[] imageByteArr = uFileService.getImageByteArr(imageUrl);
                    if (imageByteArr != null) {
                    	//转化成ByteArrayInputStream
                        in = new ByteArrayInputStream(imageByteArr);
                        //读取图片 方便获取图片尺寸
                        BufferedImage buff = ImageIO.read(in);
                        if (buff != null) {
                        	//获取图片宽度
                            int width = buff.getWidth();
                            //这里是客户对尺寸有要求 可自行处理
                            if (width > 556) {
                                width = 556;
                            }
                            int height = buff.getHeight();
                            //加入图片
                            String picId1 = document.addPictureData(imageByteArr, fileType);
                            document.createPicture(picId1, document.getNextPicNameNumber(fileType), width, height);
                        } else {
                        //如果读取图片读取不了就采用固定样式
                            String picId1 = document.addPictureData(imageByteArr, fileType);
                            document.createPicture(picId1, document.getNextPicNameNumber(fileType), 556, 200);
                        }

                    }
                }
                
   

图片类型数字获取:

   private static int getFileType(String suffix) {
        int fileType = 1;
        if (StringUtils.hasText(suffix)) {
            switch (suffix) {
                case ".emf":
                    fileType = 2;
                    break;
                case ".wmf":
                    fileType = 3;
                    break;
                case ".pict":
                    fileType = 4;
                    break;
                case ".jpeg":
                    fileType = 5;
                    break;
                case ".png":
                    fileType = 6;
                    break;
                case ".dib":
                    fileType = 7;
                    break;
                case ".gif":
                    fileType = 8;
                    break;
            }
        }
        return fileType;
    }

到这里就差不多了,剩下的就是按照自己的需求修改部分代码,最后我们需要将文件流返回:

		BufferedOutputStream out = null;
        CustomXWPFDocument document = new CustomXWPFDocument();
        InputStream in = null;
        
		//具体操作。。。。。
	
		 // 设置文件名
        response.reset();
        response.setContentType("application/msword");
        response.setHeader("Content-Disposition", "attachment;filename="
                .concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
        out = new BufferedOutputStream(response.getOutputStream());
        document.write(out);
        out.flush();

下面附上我自己的完整代码:
控制器:

/**
     * 导出题目信息
     * @param userInfoVO
     * @param response
     * @return
     */
    @PostMapping(value = "/templates/question/exportQuestion")
    public BaseResult exportByCourseSignUpId(@RequestBody QuestionLibraryQuery query, UserInfoVO userInfoVO, HttpServletResponse response) {
        List<QuestionDTO> list = questionLibraryQueryService.listQuestion(query).getDataList();
        AssertUtils.notEmpty(list, "暂无数据,无法导出");
        AuditInfoDTO auditInfoDTO = new AuditInfoDTO();
        auditInfoDTO.setContent("导出题目信息");
        auditInfoDTO.setFunction("题库管理");
        auditInfoDTO.setCreateTime(new Date());
        auditInfoDTO.setUserId(userInfoVO.getUserId());
        auditInfoDTO.setUserName(userInfoVO.getUserName());
        try {
            questionWordExportHandleApiService.export(list, "题目信息列表", response);
            auditInfoDTO.setResult(AuditResultEnum.SUCCESS.ordinal());
        } catch (Exception ex) {
            auditInfoDTO.setResult(AuditResultEnum.FAIL.ordinal());
            LOG.error("Word导出异常:", ex);
            throw new RuntimeException("导出Word失败,服务器错误!");
        } finally {
            auditInfoService.insert(auditInfoDTO);
        }
        return BaseResult.getSuccessResult();
    }
package com.yijiupi.himalaya.apiservice.boaomath.word;

import com.alibaba.dubbo.config.annotation.Reference;
import com.yijiupi.himalaya.boaomath.activity.dto.question.QuestionDTO;
import com.yijiupi.himalaya.boaomath.activity.dto.question.SelectOptionDTO;
import com.yijiupi.himalaya.boaomath.activity.enums.QuestionTypeEnum;
import com.yijiupi.himalaya.boaomath.basic.service.ufile.UFileService;
import com.yijiupi.himalaya.word.CustomXWPFDocument;
import org.apache.poi.xwpf.usermodel.ParagraphAlignment;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;
import java.util.Objects;

/**
 * @author LiJunJie
 * @Descripiton:题目word导出处理服务
 * @create 2020-08-19 15:48
 */
@Service
public class QuestionWordExportHandleApiService {

    private static final Logger LOG = LoggerFactory.getLogger(QuestionWordExportHandleApiService.class);

    @Reference
    private UFileService uFileService;

    public void export(List<QuestionDTO> list, String filename, HttpServletResponse response) {
        BufferedOutputStream out = null;
        CustomXWPFDocument document = new CustomXWPFDocument();
        InputStream in = null;

        try {
            for (int i = 0; i < list.size(); i++) {
                QuestionDTO dto = list.get(i);
                Integer questionType = dto.getQuestionType();
                XWPFParagraph paragraph = document.createParagraph();
                paragraph.setAlignment(ParagraphAlignment.LEFT);//对齐方式
                XWPFRun runHead = paragraph.createRun();
                setDefaultStyle(runHead);
                String question = dto.getQuestion() != null ? dto.getQuestion() : "";
                String questionHeader = "";
                if (Objects.equals(questionType, QuestionTypeEnum.JUDGMENT_QUESTION.getValue()) || Objects.equals(questionType, QuestionTypeEnum.CHOICE_QUESTION.getValue())) {
                    questionHeader = (i + 1) + ".[" + QuestionTypeEnum.values()[dto.getQuestionType()].getDescription() + "]   (     )";
                } else {
                    questionHeader = (i + 1) + ".[" + QuestionTypeEnum.values()[dto.getQuestionType()].getDescription() + "] ";
                }
                runHead.setText(questionHeader);
                XWPFParagraph paragraphBody = document.createParagraph();
                XWPFRun runQuestion = paragraphBody.createRun();
                setDefaultStyle(runQuestion);
                String questionBody = "题目:" + question;

                runQuestion.setText(questionBody);

                String imageUrl = dto.getImageUrl();
                if (StringUtils.hasText(imageUrl)) {
                    int fileType = getFileType(imageUrl.substring(imageUrl.lastIndexOf(".")));
                    if (fileType < 2) {
                        continue;
                    }
                    byte[] imageByteArr = uFileService.getImageByteArr(imageUrl);
                    if (imageByteArr != null) {
                        in = new ByteArrayInputStream(imageByteArr);
                        BufferedImage buff = ImageIO.read(in);
                        if (buff != null) {
                            int width = buff.getWidth();
                            if (width > 556) {
                                width = 556;
                            }
                            int height = buff.getHeight();
                            String picId1 = document.addPictureData(imageByteArr, fileType);
                            document.createPicture(picId1, document.getNextPicNameNumber(fileType), width, height);
                        } else {
                            String picId1 = document.addPictureData(imageByteArr, fileType);
                            document.createPicture(picId1, document.getNextPicNameNumber(fileType), 556, 200);
                        }

                    }
                }


                if (Objects.equals(questionType, QuestionTypeEnum.CHOICE_QUESTION.getValue())) {
                    List<SelectOptionDTO> selectOptionDTOList = dto.getSelectOptionDTOList();
                    for (int j = 0; j < selectOptionDTOList.size(); j++) {
                        SelectOptionDTO selectOptionDTO = selectOptionDTOList.get(j);
                        XWPFParagraph selectOption = document.createParagraph();
                        XWPFRun selectOptionRun = selectOption.createRun();
                        setOtherStyle(selectOptionRun);
                        String select = selectOptionDTO.getOptionName() + ". " + selectOptionDTO.getOptionContent() + "\t";
                        selectOptionRun.setText(select);
                    }
                }

                if (Objects.equals(questionType, QuestionTypeEnum.SOLVE_QUESTION.getValue())) {
                    for (int j = 0; j < 3; j++) {
                        XWPFParagraph selectOption = document.createParagraph();
                        XWPFRun selectOptionRun = selectOption.createRun();
                        setOtherStyle(selectOptionRun);
                        String select = "\t\t";
                        selectOptionRun.setText(select);
                    }
                }
                XWPFParagraph blankOne = document.createParagraph();
                XWPFRun blankRun = blankOne.createRun();
                setOtherStyle(blankRun);
                String select = "\t\t";
                blankRun.setText(select);
                XWPFParagraph blankTwo = document.createParagraph();
                XWPFRun blankRunTwo = blankTwo.createRun();
                setOtherStyle(blankRunTwo);
                blankRunTwo.setText(select);
            }

            // 设置文件名
            response.reset();
            response.setContentType("application/msword");
            response.setHeader("Content-Disposition", "attachment;filename="
                    .concat(String.valueOf(URLEncoder.encode(filename, "UTF-8"))));
            out = new BufferedOutputStream(response.getOutputStream());
            document.write(out);
            out.flush();

        } catch (Exception ex) {
            LOG.error("Word导出异常:", ex);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void setDefaultStyle(XWPFRun run) {
        run.setTextPosition(3);//设置行间距
        run.setBold(false);//加粗
        run.setColor("000000");//设置颜色--十六进制
        run.setFontFamily("宋体");//字体
        run.setFontSize(12);//字体大小
    }

    private static void setOtherStyle(XWPFRun run) {
        run.setTextPosition(3);//设置行间距
        run.setBold(false);//加粗
        run.setColor("000000");//设置颜色--十六进制
        run.setFontFamily("宋体");//字体
        run.setFontSize(10);//字体大小
    }



    private static int getFileType(String suffix) {
        int fileType = 1;
        if (StringUtils.hasText(suffix)) {
            switch (suffix) {
                case ".emf":
                    fileType = 2;
                    break;
                case ".wmf":
                    fileType = 3;
                    break;
                case ".pict":
                    fileType = 4;
                    break;
                case ".jpeg":
                    fileType = 5;
                    break;
                case ".png":
                    fileType = 6;
                    break;
                case ".dib":
                    fileType = 7;
                    break;
                case ".gif":
                    fileType = 8;
                    break;
            }
        }
        return fileType;
    }
}

最后导出效果是这样的,纯文字要好看些,好吧我承认,我弄的太丑了,哈哈~
在这里插入图片描述

ok,大功告成~
最后要说的是可能有地方说的不对,欢迎指正,请不要喷我,哈哈。

我是李三岁,一个朝着目标匍匐前进的小攻城狮,加油!

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值