0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

SpringBoot實現(xiàn)動態(tài)導出word文檔

冬至子 ? 來源:ssw在路上的螞蟻 ? 作者:努力的螞蟻 ? 2023-06-05 17:25 ? 次閱讀

背景

最近有一個需求是需要動態(tài)導出合同、訂單等信息,導出一個word文檔供客戶進行下載查看。

需要導出的word文件,主要可以分為兩種類型。

  1. 導出固定內容和圖片的word文檔
  2. 導出表格內容不固定的word文檔

經過對比工具,我實踐過兩種實現(xiàn)方式。第一種是FreeMarker模板來進行填充;第二種就是文中介紹的POI-TL。

這里我推薦使用POI-TL 。

介紹

POI-TL是word模板引擎,基于Apache POI,提供更友好的API

目前最新的版本是1.12.X,POI對應版本是5.2.2。

這里需要注意的是POI和POI-TL有一個對應的關系。

圖片

準備工作

我使用的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 >

快速開始

流程:制作模板->提供數據->渲染模板->下載word

注意:需要填充的數據需要使用{{}}來表示。

1. 導出固定內容和圖片的word文檔

準備模板

圖片

模板保存為docx格式,存放在resource目錄下

圖片

提供數據

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.組裝數據
        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.編譯模板,渲染數據
            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也提供了幾種方式來提供支撐。

圖片

測試

效果如下:

圖片

2. 導出表格內容不固定的word文檔

表格動態(tài)內容填充,POI-TL提供了3種方式。

  1. 表格行循環(huán)
  2. 表格列循環(huán)
  3. 動態(tài)表格。

第二種和第三種都可以實現(xiàn)表格填充,但我個人感覺第一種更方便一點,這里我只介紹【表格行循環(huán)】實現(xiàn)方式。

LoopRowTableRenderPolicy 是一個特定場景的插件,根據集合數據循環(huán)表格行。

注意:

  1. 模板中有兩個list,這兩個list需要置于循環(huán)行的上一行。
  2. 循環(huán)行設置要循環(huán)的標簽和內容,注意此時的標簽應該使用[]

準備模板

圖片

提供數據

學生實體類

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;
    }
}

學生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;
    }
}

表格數據

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.組裝數據
        StudentTable table = assertData();
        //2.獲取根目錄,創(chuàng)建模板文件
        String path = copyTempFile("word/2.docx");
        //3.獲取臨時文件
        String fileName = System.currentTimeMillis() + ".docx";
        String tmpPath = "D:\\\" + fileName;
        try {
            //4.編譯模板,渲染數據
            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();
        }
    }

測試

效果如下:

圖片

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • POI
    POI
    +關注

    關注

    0

    文章

    8

    瀏覽量

    6998
  • API接口
    +關注

    關注

    1

    文章

    82

    瀏覽量

    10420
  • SpringBoot
    +關注

    關注

    0

    文章

    173

    瀏覽量

    161
收藏 人收藏

    評論

    相關推薦

    如何實現(xiàn)圖片轉Word文檔

    在職場中,有些工作職員經常會受到一些照片,這是令人頭疼,發(fā)照片很簡單,但是要把照片里的信息轉移到Word文檔里面就很麻煩了,現(xiàn)在科技快速發(fā)展,難道你還使用手動輸入嗎?要是這樣的話,說明你和世界已經
    發(fā)表于 04-19 15:05

    基于SpringBoot mybatis方式的增刪改查實現(xiàn)

    SpringBoot mybatis方式實現(xiàn)增刪改查
    發(fā)表于 06-18 16:56

    基于多種技術的Word設計文檔自動生成平臺

    闡述Word設計文檔自動生成平臺的框架結構,提出了結合VBA、ADO和ASP等技術的設計思路,并詳細介紹了文檔自動生成平臺軟件的具體實現(xiàn),包括建立
    發(fā)表于 05-11 20:20 ?30次下載

    一種基于Word文檔的數字密寫設計與實現(xiàn)

    提出了一種新的基于 Word 文檔的數字密寫設計與實現(xiàn)方法,介紹了應用程序的實現(xiàn)方案,給出了系統(tǒng)組成方框圖。實驗結果表明,算法很好地實現(xiàn)了文
    發(fā)表于 08-04 09:40 ?20次下載

    《微機原理及應用》課程教程 (word文檔)

     《微機原理及應用》課程教案目    錄 下載WORD文檔前    言 下載WORD文檔第一章 51系列單片機概述
    發(fā)表于 09-16 11:17 ?202次下載

    一種快速Word編程接口的設計與實現(xiàn)

    本文在分析MS Word文檔存儲格式的基礎上,研究了讀取Word文檔二進制數據流并將其恢復成可讀信息的方法,設計實現(xiàn)了一種快速
    發(fā)表于 02-21 15:58 ?23次下載

    一種快速Word編程接口的設計與實現(xiàn)

    本文在分析MS Word文檔存儲格式的基礎上,研究了讀取Word文檔二進制數據流并將其恢復成可讀信息的方法,設計實現(xiàn)了一種快速
    發(fā)表于 07-22 17:39 ?16次下載

    如何在Word文檔中嵌入PROTEL原理圖

    如何在Word文檔中嵌入PROTEL原理圖 一、Protel 99文件管理器中導入Word文檔:在Protel 99的Documents窗口,執(zhí)行File/New菜單命令,選擇Doc
    發(fā)表于 04-15 00:18 ?1536次閱讀

    VC上機指導WORD文檔

    VC上機指導WORD文檔
    發(fā)表于 03-04 17:48 ?2次下載

    word文檔如何解密

    word文檔 如何解密,Kubernetes pod 啟動時會拉取用戶指定的鏡像,一旦這個過程耗時太久就會導致 pod 長時間處于 pending 的狀態(tài),從而無法快速提供服務。
    的頭像 發(fā)表于 03-14 09:10 ?1658次閱讀

    用于損壞的Microsoft Word文檔的數據恢復軟件

    Recoveryfor Word 旨在從損壞的MicrosoftWord 文檔中進行有效的數據恢復。使用Word恢復可以避免丟失重要信息。如今,MicrosoftWord 文本處理器是創(chuàng)建任何類型
    的頭像 發(fā)表于 08-19 15:27 ?1611次閱讀

    SpringBoot實現(xiàn)多線程

    SpringBoot實現(xiàn)多線程
    的頭像 發(fā)表于 01-12 16:59 ?1786次閱讀
    <b class='flag-5'>SpringBoot</b><b class='flag-5'>實現(xiàn)</b>多線程

    求一種SpringBoot定時任務動態(tài)管理通用解決方案

    SpringBoot的定時任務的加強工具,實現(xiàn)SpringBoot原生的定時任務進行動態(tài)管理,完全兼容原生@Scheduled注解,無需對原本的定時任務進行修改
    的頭像 發(fā)表于 02-03 09:49 ?743次閱讀

    如何提取Word文檔表格保存到Excel

    據提取到Excel表中。例如,提取word文檔中的財務數據、考勤數據等,將數據存儲到 Excel表中,本次項目我們專門針對word文檔中的表格數據進行解析與提取。
    的頭像 發(fā)表于 02-24 16:00 ?2651次閱讀
    如何提取<b class='flag-5'>Word</b><b class='flag-5'>文檔</b>表格保存到Excel

    SpringBoot實現(xiàn)動態(tài)切換數據源

    最近在做業(yè)務需求時,需要從不同的數據庫中獲取數據然后寫入到當前數據庫中,因此涉及到切換數據源問題。本來想著使用Mybatis-plus中提供的動態(tài)數據源SpringBoot的starter:dynamic-datasource-spring-boot-starter來
    的頭像 發(fā)表于 12-08 10:53 ?964次閱讀
    <b class='flag-5'>SpringBoot</b><b class='flag-5'>實現(xiàn)</b><b class='flag-5'>動態(tài)</b>切換數據源