導出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模擬瀏覽器請求,將圖片地址解析出來,以文件流的形式存入文檔。