Java导出word文档(POI&Spire.Doc)

Java导出word文档(POI&Spire.Doc)

导出Word文档整理

前言

​ 业务需要将数据库中存的图片导出成word文档,并给这些图片按照文件名生成目录。以下为解决方案,通常在导出文件时,poi使用的频率较高,可以导出各类模板类的和非模板类的文件,但是在导出word,并生成目录的时候发现其解决问题方式相对来说比较复杂。所以,通过调查后发现Spire.Doc,可以实现当前业务需求。以下是本次问题解决整理。

Apache POI

添加依赖

<dependencies>
     <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.1</version>
        </dependency>
</dependencies>

示例代码

public static void main(String[] args) throws IOException{
        XWPFDocument document= new XWPFDocument();
        FileOutputStream out = new FileOutputStream(new File("F:\\Sources\\test.docx"));
        //添加标题
        XWPFParagraph titleParagraph = document.createParagraph();
        //设置段落居中
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun titleParagraphRun = titleParagraph.createRun();
        titleParagraphRun.setText("Java PoI");
        titleParagraphRun.setColor("000000");
        titleParagraphRun.setFontSize(20);
        XWPFParagraph firstParagraph = document.createParagraph();
        XWPFRun run = firstParagraph.createRun();
        run.setText("Java POI 生成word文件。");
        run.setColor("696969");
        run.setFontSize(16);
        //设置段落背景颜色
        CTShd cTShd = run.getCTR().addNewRPr().addNewShd();
        cTShd.setVal(STShd.CLEAR);
        cTShd.setFill("97FFFF");
        XWPFParagraph paragraph1 = document.createParagraph();
        XWPFRun paragraphRun1 = paragraph1.createRun();
        paragraphRun1.setText("\r");
        //基本信息表格
        XWPFTable infoTable = document.createTable();
        //去表格边框
        infoTable.getCTTbl().getTblPr().unsetTblBorders();
        //列宽自动分割
        CTTblWidth infoTableWidth = infoTable.getCTTbl().addNewTblPr().addNewTblW();
        infoTableWidth.setType(STTblWidth.DXA);
        infoTableWidth.setW(BigInteger.valueOf(9072));
        //表格第一行
        XWPFTableRow infoTableRowOne = infoTable.getRow(0);
        infoTableRowOne.getCell(0).setText("职位");
        infoTableRowOne.addNewTableCell().setText(": Java 开发工程师");
        //表格第二行
        XWPFTableRow infoTableRowTwo = infoTable.createRow();
        infoTableRowTwo.getCell(0).setText("姓名");
        infoTableRowTwo.getCell(1).setText(": seawater");
        //表格第三行
        XWPFTableRow infoTableRowThree = infoTable.createRow();
        infoTableRowThree.getCell(0).setText("生日");
        infoTableRowThree.getCell(1).setText(": xxx-xx-xx");
        //表格第四行
        XWPFTableRow infoTableRowFour = infoTable.createRow();
        infoTableRowFour.getCell(0).setText("性别");
        infoTableRowFour.getCell(1).setText(": 男");
        //表格第五行
        XWPFTableRow infoTableRowFive = infoTable.createRow();
        infoTableRowFive.getCell(0).setText("现居地");
        infoTableRowFive.getCell(1).setText(": xx");
        CTSectPr sectPr = document.getDocument().getBody().addNewSectPr();
        XWPFHeaderFooterPolicy policy = new XWPFHeaderFooterPolicy(document, sectPr);
        XWPFParagraph pic = document.createParagraph();
        pic.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun picRun = pic.createRun();
        List<String> filePath = new ArrayList<String>();
        filePath.add("D:\\Pictures\\20170314171319_TP2nY.jpeg");
        filePath.add("D:\\Pictures\\20161213154536_AGv84.jpg");
        filePath.add("D:\\Pictures\\20151212225934_VhQcM.jpeg");
        filePath.add("D:\\Pictures\\20150926115124_fYZ4U.jpeg");
        for (String str:filePath) {
            picRun.setText(str);
            picRun.addPicture(
                    new FileInputStream(str),XWPFDocument.PICTURE_TYPE_JPEG,
                    str,
                    Units.toEMU(450),
                    Units.toEMU(300)
        //添加页眉
        CTP ctpHeader = CTP.Factory.newInstance();
        CTR ctrHeader = ctpHeader.addNewR();
        CTText ctHeader = ctrHeader.addNewT();
        String headerText = "ctpHeader";
        ctHeader.setStringValue(headerText);
        XWPFParagraph headerParagraph = new XWPFParagraph(ctpHeader, document);
        //设置为右对齐
        headerParagraph.setAlignment(ParagraphAlignment.RIGHT);
        XWPFParagraph[] parsHeader = new XWPFParagraph[1];
        parsHeader[0] = headerParagraph;
        policy.createHeader(XWPFHeaderFooterPolicy.DEFAULT, parsHeader);
        //添加页脚
        CTP ctpFooter = CTP.Factory.newInstance();
        CTR ctrFooter = ctpFooter.addNewR();
        CTText ctFooter = ctrFooter.addNewT();
        String footerText = "ctpFooter";
        ctFooter.setStringValue(footerText);
        XWPFParagraph footerParagraph = new XWPFParagraph(ctpFooter, document);
        headerParagraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFParagraph[] parsFooter = new XWPFParagraph[1];
        parsFooter[0] = footerParagraph;
        policy.createFooter(XWPFHeaderFooterPolicy.DEFAULT, parsFooter);
        document.write(out);
        out.close();
}

生成效果

优缺点

  • 优点
  • 通常较为常用的导入导出文件。比较稳定
  • 缺点
  • 导出word文件在生成目录的时候,处理较为复杂

Sprie.Doc for JAVA

添加 Free Spire.PDF for Java 依赖

第一种方式:通过官网 下载jar 文件包。下载后,解压文件,将lib文件夹下的Spire.Pdf.jar文件导入Java程序。

第二种方式:通过 maven仓库安装导入

<repositories>
        <repository>
            <id>com.e-iceblue</id>
            <name>e-iceblue</name>
            <url>http://repo.e-iceblue.com/nexus/content/groups/public/</url>
        </repository>
</repositories>
<dependencies>
     <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.doc</artifactId>
            <version>3.3</version>
        </dependency>
</dependencies>

示例代码

/**
     * 导出文件
     * @param condition
     * @return
    @PostMapping(value = "/exportInfoToWord")
    public void exportInfoToWord(@RequestBody HashMap<String,String> condition, HttpServletResponse response) throws IOException {
        //创建Word文档
        Document doc = new Document();
        //添加一个目录的section
        Section section = doc.addSection();
        Paragraph para = section.addParagraph();
        TextRange tr = para.appendText("目 录");
        //设置字体大小和颜色
        tr.getCharacterFormat().setTextColor(Color.black);
        tr.getCharacterFormat().setFontName("宋体");
        tr.getCharacterFormat().setFontSize(20);
        para.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
        //设置段后间距
        para.getFormat().setAfterSpacing(10);
        //添加段落
        para = section.addParagraph();
        //通过指定最低的Heading级别1和最高的Heading级别3,创建包含Heading 1、2、3,制表符前导符和右对齐页码的默认样式的Word目录。标题级别范围必须介于1到9之间
        para.appendTOC(1, 3);
        // 获取http客户端
        CloseableHttpClient client = HttpClients.createDefault();
        List<String> fileAddress = new ArrayList<String>();
        fileAddress.add("http://114.116.236.37:9000/image/file/676faf54-105a-4f36-8efe-3e73729eb69f.jpg");
        fileAddress.add("http://114.116.236.37:9000/image/file/962d7ea0-1222-418a-9297-9eee48d6bc85.jpeg");
        fileAddress.add("http://114.116.236.37:9000/image/file/a5c6f1c6-ba1e-4178-a791-eb539afb4042.jpeg");
        for (String address : fileAddress) {
            //添加一个section
            section = doc.addSection();
            //添加一个段落
            para = section.addParagraph();
            para.appendText(address);
            //应用Heading 1样式到段落
            para.applyStyle(BuiltinStyle.Heading_1);
            section.addParagraph();
            // 通过httpget方式来实现我们的get请求
            HttpGet httpGet = new HttpGet(address);
            //设置请求头信息
            httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36");
            // 通过client调用execute方法,得到我们的执行结果就是一个response,所有的数据都封装在response里面了
            CloseableHttpResponse httpResponse = client.execute(httpGet);
            // HttpEntity 是一个中间的桥梁,在httpClient里面,是连接我们的请求与响应的一个中间桥梁,所有的请求参数都是通过HttpEntity携带过去的
            // 所有的响应的数据,也全部都是封装在HttpEntity里面
            HttpEntity entity = httpResponse.getEntity();
            InputStream in = entity.getContent();
            //添加图片段落
            Paragraph paraPicture = section.addParagraph();
            DocPicture picture = paraPicture.appendPicture(in);
            //设置图片宽度
            picture.setWidth(490f);
            //设置图片高度
            picture.setHeight(400f);
            //添加第一个段落
            Paragraph paraText = section.addParagraph();
            //给第一个段落和第二个段落设置水平居中对齐方式
            paraPicture.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
            paraText.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
            //设置第一个段落的段后间距
            paraPicture.getFormat().setAfterSpacing(15f);
            //释放资源
            EntityUtils.consume(entity);
        //获取第一个节中的页脚
        HeaderFooter footer = doc.getSections().get(0).getHeadersFooters().getFooter();
        //添加段落到页脚
        Paragraph footerParagraph = footer.addParagraph();
        //添加文字、页码域和总页数域到段落
        footerParagraph.appendText("第");
        footerParagraph.appendField("page number", FieldType.Field_Page);
        footerParagraph.appendText("页");
        footerParagraph.getFormat().setHorizontalAlignment(HorizontalAlignment.Center);
        //设置目录页码数字格式为罗马数字
        doc.getSections().get(0).getPageSetup().setPageNumberStyle(PageNumberStyle.Roman_Lower);
        //设置内容页码数字格式为阿拉伯数字
        doc.getSections().get(1).getPageSetup().setPageNumberStyle(PageNumberStyle.Arabic);
        //设置第二节页码从新开始编码,并设置起始页码数字
        doc.getSections().get(1).getPageSetup().setRestartPageNumbering(true);
        doc.getSections().get(1).getPageSetup().setPageStartingNumber(1);
        //更新目录
        doc.updateTableOfContents();
        //保存到临时固定地址
        String path = "F:\\tempDocFiles";
        File dir = new File(path);
        if (!dir.exists()) {
            dir.mkdir();
        //临时文件路径
        String filePath = path + File.separator + UUID.randomUUID();
        doc.saveToFile(filePath + ".docx", FileFormat.Docx);
        //重新读取文档,进行操作
        InputStream is = new FileInputStream(filePath + ".docx");
        XWPFDocument document = new XWPFDocument(is);
        //以上Spire.Doc 生成的文件会自带警告信息,这里来删除Spire.Doc 的警告
        document.removeBodyElement(0);
        //输出word内容文件流,提供下载
        response.reset();
        response.setContentType("application/x-msdownload");
        String fileName = "" + System.currentTimeMillis() + ".docx";
        response.addHeader("Content-Disposition", "attachment; filename=" + fileName);
        delFile(dir);
        ByteArrayOutputStream ostream = new ByteArrayOutputStream();
        OutputStream servletOS = null;
        try {
            servletOS = response.getOutputStream();
            document.write(ostream);
            servletOS.write(ostream.toByteArray());