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());
            servletOS.flush();
            servletOS.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
	}

生成效果

優缺點

  • 優點
    • 對於導出word文檔較為友好,段落設置比較方便。
  • 缺點
    • 導出的word文件會有原生自帶的警告信息,需要額外處理一下,以上用poi重新讀取后,操作,將警告消除。

拓展點

  • 在生成圖片時,用到了HttpClient模擬瀏覽器請求,將圖片地址解析出來,以文件流的形式存入文檔。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM