SpringBoot動態(tài)導(dǎo)出word文檔實整教程(復(fù)制即可使用)
背景
最近有一個需求是需要動態(tài)導(dǎo)出合同、訂單等信息,導(dǎo)出一個word文檔供客戶進行下載查看。
需要導(dǎo)出的word文件,主要可以分為兩種類型。
- 導(dǎo)出固定內(nèi)容和圖片的word文檔
- 導(dǎo)出表格內(nèi)容不固定的word文檔
經(jīng)過對比工具,我實踐過兩種實現(xiàn)方式。第一種是FreeMarker模板來進行填充;第二種就是文中介紹的POI-TL。
這里我推薦使用POI-TL。
介紹
POI-TL是word模板引擎,基于Apache POI,提供更友好的API。
目前最新的版本是1.12.X,POI對應(yīng)版本是5.2.2。
這里需要注意的是POI和POI-TL有一個對應(yīng)的關(guān)系。
準備工作
我使用的POI-TL版本是1.10.0
<dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.10.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.7</version> </dependency>
快速開始
流程:制作模板->提供數(shù)據(jù)->渲染模板->下載word
注意:需要填充的數(shù)據(jù)需要使用{{}}來表示。
1. 導(dǎo)出固定內(nèi)容和圖片的word文檔
準備模板
模板保存為docx格式,存放在resource目錄下
提供數(shù)據(jù)
private Map<String, Object> assertMap() { Map<String, Object> params = new HashMap<>(); params.put("name", "努力的螞蟻"); params.put("age", "18"); params.put("image", Pictures.ofUrl("http://deepoove.com/images/icecream.png").size(100, 100).create()); return params; }
工具方法
/** * 將項目中的模板文件拷貝到根目錄下 * @return */ private String copyTempFile(String templeFilePath) { InputStream inputStream = getClass().getClassLoader().getResourceAsStream(templeFilePath); String tempFileName = System.getProperty("user.home") + "/" + "1.docx"; File tempFile = new File(tempFileName); try { FileUtils.copyInputStreamToFile(inputStream, tempFile); } catch (IOException e) { throw new RuntimeException(e); } return tempFile.getPath(); }
private void down(HttpServletResponse response, String filePath, String realFileName) { String percentEncodedFileName = null; try { percentEncodedFileName = percentEncode(realFileName); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } StringBuilder contentDispositionValue = new StringBuilder(); contentDispositionValue.append("attachment; filename=").append(percentEncodedFileName).append(";").append("filename*=").append("utf-8''").append(percentEncodedFileName); response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename"); response.setHeader("Content-disposition", contentDispositionValue.toString()); response.setHeader("download-filename", percentEncodedFileName); try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath)); // 輸出流 BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());) { byte[] buff = new byte[1024]; int len = 0; while ((len = bis.read(buff)) > 0) { bos.write(buff, 0, len); } } catch (Exception e) { e.printStackTrace(); } }
/** * 百分號編碼工具方法 * @param s 需要百分號編碼的字符串 * @return 百分號編碼后的字符串 */ public static String percentEncode(String s) throws UnsupportedEncodingException { String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString()); return encode.replaceAll("\\+", "%20"); }
編寫接口
@RequestMapping("genera") public void genera(HttpServletResponse response) { //1.組裝數(shù)據(jù) Map<String, Object> params = assertMap(); //2.獲取根目錄,創(chuàng)建模板文件 String path = copyTempFile("word/1.docx"); String fileName = System.currentTimeMillis() + ".docx"; String tmpPath = "D:\\" + fileName; try { //3.將模板文件寫入到根目錄 //4.編譯模板,渲染數(shù)據(jù) XWPFTemplate template = XWPFTemplate.compile(path).render(params); //5.寫入到指定目錄位置 FileOutputStream fos = new FileOutputStream(tmpPath); template.write(fos); fos.flush(); fos.close(); template.close(); //6.提供前端下載 down(response, tmpPath, fileName); } catch (Exception e) { e.printStackTrace(); } finally { //7.刪除臨時文件 File file = new File(tmpPath); file.delete(); File copyFile = new File(path); copyFile.delete(); } }
對于圖片的格式,POI-TL也提供了幾種方式來提供支撐。
測試
請求接口:http://127.0.0.1:1000/file/genera
效果如下:
2. 導(dǎo)出表格內(nèi)容不固定的word文檔
表格動態(tài)內(nèi)容填充,POI-TL提供了3種方式。
- 表格行循環(huán)
- 表格列循環(huán)
- 動態(tài)表格。
第二種和第三種都可以實現(xiàn)表格填充,但我個人感覺第一種更方便一點,這里我只介紹【表格行循環(huán)】實現(xiàn)方式。
LoopRowTableRenderPolicy
是一個特定場景的插件,根據(jù)集合數(shù)據(jù)循環(huán)表格行。
注意:
- 模板中有兩個list,這兩個list需要置于循環(huán)行的上一行。
- 循環(huán)行設(shè)置要循環(huán)的標簽和內(nèi)容,注意此時的標簽應(yīng)該使用[]
準備模板
提供數(shù)據(jù)
學(xué)生實體類
public class Student { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
學(xué)生word類
public class StudentTable { private String title; private List<Student> studentList; private List<Student> studentList1; public List<Student> getStudentList1() { return studentList1; } public void setStudentList1(List<Student> studentList1) { this.studentList1 = studentList1; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public List<Student> getStudentList() { return studentList; } public void setStudentList(List<Student> studentList) { this.studentList = studentList; } }
表格數(shù)據(jù)
private StudentTable assertData() { StudentTable table = new StudentTable(); table.setTitle("我是標題"); List<Student> studentList = new ArrayList<>(); Student student = new Student(); student.setName("張三"); student.setAge("18"); studentList.add(student); Student student1 = new Student(); student1.setName("李四"); student1.setAge("20"); studentList.add(student1); Student student2 = new Student(); student2.setName("王五"); student2.setAge("21"); studentList.add(student2); Student student3 = new Student(); student3.setName("馬六"); student3.setAge("19"); studentList.add(student3); table.setStudentList(studentList); table.setStudentList1(studentList); return table; }
編寫接口
@RequestMapping("dynamicTable") public void dynamicTable(HttpServletResponse response) { //1.組裝數(shù)據(jù) StudentTable table = assertData(); //2.獲取根目錄,創(chuàng)建模板文件 String path = copyTempFile("word/2.docx"); //3.獲取臨時文件 String fileName = System.currentTimeMillis() + ".docx"; String tmpPath = "D:\\" + fileName; try { //4.編譯模板,渲染數(shù)據(jù) LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy(); Configure config = Configure.builder().bind("studentList", hackLoopTableRenderPolicy).bind("studentList1", hackLoopTableRenderPolicy).build(); XWPFTemplate template = XWPFTemplate.compile(path, config).render(table); //5.寫入到指定目錄位置 FileOutputStream fos = new FileOutputStream(tmpPath); template.write(fos); fos.flush(); fos.close(); template.close(); //6.提供下載 down(response, tmpPath, fileName); } catch (Exception e) { e.printStackTrace(); } finally { //7.刪除臨時文件 File file = new File(tmpPath); file.delete(); File copyFile = new File(path); copyFile.delete(); } }
測試
請求接口:http://127.0.0.1:1000/file/dynamicTable
效果如下:
總結(jié)
到此這篇關(guān)于SpringBoot動態(tài)導(dǎo)出word文檔實整教程的文章就介紹到這了,更多相關(guān)SpringBoot動態(tài)導(dǎo)出word文檔內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合Elasticsearch實現(xiàn)索引和文檔的操作方法
Elasticsearch 基于 Apache Lucene 構(gòu)建,采用 Java 編寫,并使用 Lucene 構(gòu)建索引、提供搜索功能,本文分步驟通過綜合案例給大家分享SpringBoot整合Elasticsearch的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧2021-05-05java httpclient設(shè)置超時時間和代理的方法
這篇文章主要介紹了java httpclient設(shè)置超時時間和代理的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02深入淺出重構(gòu)Mybatis與Spring集成的SqlSessionFactoryBean(上)
通常來講,重構(gòu)是指不改變功能的情況下優(yōu)化代碼,但本文所說的重構(gòu)也包括了添加功能。這篇文章主要介紹了重構(gòu)Mybatis與Spring集成的SqlSessionFactoryBean(上)的相關(guān)資料,需要的朋友可以參考下2016-11-11Java使用Jdbc連接Oracle執(zhí)行簡單查詢操作示例
這篇文章主要介紹了Java使用Jdbc連接Oracle執(zhí)行簡單查詢操作,結(jié)合實例形式詳細分析了java基于jdbc實現(xiàn)Oracle數(shù)據(jù)庫的連接與查詢相關(guān)操作技巧,需要的朋友可以參考下2019-09-09Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題示例
這篇文章主要介紹了Java基于二維數(shù)組實現(xiàn)的數(shù)獨問題,涉及java針對數(shù)組的遍歷、計算、轉(zhuǎn)換等相關(guān)操作技巧,需要的朋友可以參考下2018-01-01Java多線程批量數(shù)據(jù)導(dǎo)入的方法詳解
這篇文章主要介紹了Java多線程批量數(shù)據(jù)導(dǎo)入的方法,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,下面小編和大家來一起學(xué)習(xí)下吧2019-06-06springboot項目讀取resources目錄下的文件的9種方式
本文主要介紹了springboot項目讀取resources目錄下的文件的9種方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04