最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot如何根據(jù)docx填充生成word文件并導(dǎo)出pdf

 更新時(shí)間:2024年08月15日 10:18:02   作者:專注寫(xiě)bug  
這篇文章主要介紹了Springboot如何根據(jù)docx填充生成word文件并導(dǎo)出pdf問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

在項(xiàng)目中碰見(jiàn)一個(gè)需求,需要將.doc的合同,轉(zhuǎn)換為pdf實(shí)現(xiàn)打印與預(yù)覽功能。

將docx模板填充數(shù)據(jù)生成doc文件

1、依賴引入

填充docx模板,只需要引入一個(gè)pom依賴即可實(shí)現(xiàn)。

<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.5.0</version>
</dependency>

2、doc文件轉(zhuǎn)換docx,并標(biāo)注別名

用office或者wps,創(chuàng)建一個(gè)001.doc文件,繪制表格,保存。

更改后綴為.docx,確定后,在指定的位置,表示數(shù)據(jù)接受變量名稱。

如下圖所示:

3、編寫(xiě)java代碼實(shí)現(xiàn)數(shù)據(jù)填充

import com.deepoove.poi.XWPFTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * word 填充測(cè)試
 */
public class TestWord {
    public static void main(String[] args) throws IOException {
        Map<String, Object> params = new HashMap<>();
        params.put("username","xiangjiao1");
        params.put("password","******");
        params.put("age",22);
        params.put("email","專注寫(xiě)bug測(cè)試中文");
        Resource resource = new ClassPathResource("templates_report/001.docx");
        File file = resource.getFile();
        // 數(shù)據(jù)填充
        XWPFTemplate template = XWPFTemplate.compile(file).render(params);

        String docOutPath = System.getProperty("user.dir")+File.separator+"springboot-poi"+File.separator+"pdf"+File.separator+ "1.doc";
        OutputStream outputStream = new FileOutputStream(docOutPath);
        template.write(outputStream);

    }
}

運(yùn)行程序,查看結(jié)果。

測(cè)試項(xiàng)目結(jié)構(gòu)如下:

docx文件填充數(shù)據(jù)導(dǎo)出pdf(web)

1、依賴引入

docx模板中填充數(shù)據(jù),并導(dǎo)出pdf類(lèi)型的文件,除了上面的pom依賴之外,還需要引入其他的依賴信息,完整依賴如下所示:

<!-- docx 數(shù)據(jù)填充生成 doc文件  這個(gè)是主要 -->
<dependency>
    <groupId>com.deepoove</groupId>
    <artifactId>poi-tl</artifactId>
    <version>1.5.0</version>
</dependency>
<!-- doc 轉(zhuǎn) pdf -->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<!-- docx4j docx2pdf -->
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j</artifactId>
    <version>6.1.2</version>
</dependency>
<dependency>
    <groupId>org.docx4j</groupId>
    <artifactId>docx4j-export-fo</artifactId>
    <version>6.0.0</version>
</dependency>

2、字體文件

src\main\resources下創(chuàng)建一個(gè)font文件夾,其中放入simsun.ttc字體文件。

3、編寫(xiě)工具類(lèi)

思想很簡(jiǎn)單

  • 1、先使用上面的docx模板填充數(shù)據(jù)生成臨時(shí)doc文件,
  • 2、再將doc文件轉(zhuǎn)換為pdf文件
  • 3、刪除臨時(shí)文件

【注意:】

為了避免出現(xiàn)多人同時(shí)操作,導(dǎo)致文件誤刪的問(wèn)題,需要盡可能地保證臨時(shí)文件名稱的唯一性。

import com.deepoove.poi.XWPFTemplate;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.docx4j.Docx4J;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipOutputStream;
 
/**
 * pdf 導(dǎo)出工具類(lèi)
 */
@Component
@Slf4j
public final class FreeMarkUtils {
 
    /**
     * 根據(jù)docx模板填充數(shù)據(jù)  并生成pdf文件
     *
     * @param dataMap      數(shù)據(jù)源
     * @param docxFile     docx模板的文件名
     * @return 生成的文件路徑
     */
    public static byte[] createDocx2Pdf(Map<String, Object> dataMap, String docxFile) {
        //輸出word文件路徑和名稱 (臨時(shí)文件名,本次為測(cè)試,最好使用雪花算法生成,或者用uuid)
        String fileName = UUID.randomUUID().toString() + ".docx";

        // word 數(shù)據(jù)填充
        // 生成docx臨時(shí)文件
        final File tempPath = new File(fileName);
        final File docxTempFile = getTempFile(docxFile);
        XWPFTemplate template = XWPFTemplate.compile(docxTempFile).render(dataMap);
        try {
            template.write(new FileOutputStream(tempPath));
        } catch (IOException e) {
            e.printStackTrace();
        }

        // word轉(zhuǎn)pdf
        final String pdfFile = convertDocx2Pdf(fileName);
        return getFileOutputStream(new File(pdfFile)).toByteArray();
    }
 
    /**
     * word(doc)轉(zhuǎn)pdf
     *
     * @param wordPath doc 生成的臨時(shí)文件路徑
     * @return 生成的帶水印的pdf路徑
     */
    public static String convertDocx2Pdf(String wordPath) {
        OutputStream os = null;
        InputStream is = null;
        //輸出pdf文件路徑和名稱  (臨時(shí)文件  盡可能保證文件名稱的唯一性)
        final String fileName = UUID.randomUUID().toString() + ".pdf";
        try {
            is = new FileInputStream(wordPath);
            WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(is);
            Mapper fontMapper = new IdentityPlusMapper();
            fontMapper.put("隸書(shū)", PhysicalFonts.get("LiSu"));
            fontMapper.put("宋體", PhysicalFonts.get("SimSun"));
            fontMapper.put("微軟雅黑", PhysicalFonts.get("Microsoft Yahei"));
            fontMapper.put("黑體", PhysicalFonts.get("SimHei"));
            fontMapper.put("楷體", PhysicalFonts.get("KaiTi"));
            fontMapper.put("新宋體", PhysicalFonts.get("NSimSun"));
            fontMapper.put("華文行楷", PhysicalFonts.get("STXingkai"));
            fontMapper.put("華文仿宋", PhysicalFonts.get("STFangsong"));
            fontMapper.put("宋體擴(kuò)展", PhysicalFonts.get("simsun-extB"));
            fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));
            fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
            fontMapper.put("幼圓", PhysicalFonts.get("YouYuan"));
            fontMapper.put("華文宋體", PhysicalFonts.get("STSong"));
            fontMapper.put("華文中宋", PhysicalFonts.get("STZhongsong"));
            //解決宋體(正文)和宋體(標(biāo)題)的亂碼問(wèn)題
            PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
            PhysicalFonts.put("新細(xì)明體", PhysicalFonts.get("SimSun"));
            // 字體文件
            PhysicalFonts.addPhysicalFonts("SimSun", WordUtils.class.getResource("/font/simsun.ttc"));
 
            mlPackage.setFontMapper(fontMapper);
            os = new FileOutputStream(fileName);
 
            //docx4j  docx轉(zhuǎn)pdf
            FOSettings foSettings = Docx4J.createFOSettings();
            foSettings.setWmlPackage(mlPackage);
            Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);
            is.close();//關(guān)閉輸入流
            os.close();//關(guān)閉輸出流
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 刪除docx 臨時(shí)文件
            File file = new File(wordPath);
            if (file != null && file.isFile() && file.exists()) {
                file.delete();
            }
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        return fileName;
    }
 
    /**
     * 文件轉(zhuǎn)字節(jié)輸出流
     *
     * @param outFile 文件
     * @return
     */
    public static ByteArrayOutputStream getFileOutputStream(File outFile) {
        // 獲取生成臨時(shí)文件的輸出流
        InputStream input = null;
        ByteArrayOutputStream bytestream = null;
        try {
            input = new FileInputStream(outFile);
            bytestream = new ByteArrayOutputStream();
            int ch;
            while ((ch = input.read()) != -1) {
                bytestream.write(ch);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bytestream.close();
                input.close();
                log.info("刪除臨時(shí)文件");
                if (outFile.exists()) {
                    outFile.delete();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return bytestream;
    }
 
    /**
     * 獲取資源文件的臨時(shí)文件
     * 資源文件打jar包后,不能直接獲取,需要通過(guò)流獲取生成臨時(shí)文件
     *
     * @param fileName 文件路徑 templates/xxx.docx
     * @return
     */
    public static File getTempFile(String fileName) {
        final File tempFile = new File(fileName);
        InputStream fontTempStream = null;
        try {
            fontTempStream = FreeMarkUtils.class.getClassLoader().getResourceAsStream(fileName);
            FileUtils.copyInputStreamToFile(fontTempStream, tempFile);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fontTempStream != null) {
                    fontTempStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return tempFile;
    }
 
 
    /**
     * 插入圖片水印
     * @param srcByte 已生成PDF的字節(jié)數(shù)組(流轉(zhuǎn)字節(jié))
     * @param destFile 生成有水印的臨時(shí)文件 temp.pdf
     * @return
     */
    public static FileOutputStream addWaterMark(byte[] srcByte, String destFile) {
        // 待加水印的文件
        PdfReader reader = null;
        // 加完水印的文件
        PdfStamper stamper = null;
        FileOutputStream fileOutputStream = null;
        try {
            reader = new PdfReader(srcByte);
            fileOutputStream = new FileOutputStream(destFile);
            stamper = new PdfStamper(reader, fileOutputStream);
            int total = reader.getNumberOfPages() + 1;
            PdfContentByte content;
            // 設(shè)置字體
            //BaseFont font = BaseFont.createFont();
            // 循環(huán)對(duì)每頁(yè)插入水印
            for (int i = 1; i < total; i++) {
                final PdfGState gs = new PdfGState();
                // 水印的起始
                content = stamper.getUnderContent(i);
                // 開(kāi)始
                content.beginText();
                // 設(shè)置顏色 默認(rèn)為藍(lán)色
                //content.setColorFill(BaseColor.BLUE);
                // content.setColorFill(Color.GRAY);
                // 設(shè)置字體及字號(hào)
                //content.setFontAndSize(font, 38);
                // 設(shè)置起始位置
                // content.setTextMatrix(400, 880);
                //content.setTextMatrix(textWidth, textHeight);
                // 開(kāi)始寫(xiě)入水印
                //content.showTextAligned(Element.ALIGN_LEFT, text, textWidth, textHeight, 45);
 
                // 設(shè)置水印透明度
                // 設(shè)置筆觸字體不透明度為0.4f
                gs.setStrokeOpacity(0f);
                Image image = null;
                image = Image.getInstance("url");
                // 設(shè)置坐標(biāo) 絕對(duì)位置 X Y 這個(gè)位置大約在 A4紙 右上角展示LOGO
                image.setAbsolutePosition(472, 785);
                // 設(shè)置旋轉(zhuǎn)弧度
                image.setRotation(0);// 旋轉(zhuǎn) 弧度
                // 設(shè)置旋轉(zhuǎn)角度
                image.setRotationDegrees(0);// 旋轉(zhuǎn) 角度
                // 設(shè)置等比縮放 圖片大小
                image.scalePercent(4);// 依照比例縮放
                // image.scaleAbsolute(200,100);//自定義大小
                // 設(shè)置透明度
                content.setGState(gs);
                // 添加水印圖片
                content.addImage(image);
                // 設(shè)置透明度
                content.setGState(gs);
                //結(jié)束設(shè)置
                content.endText();
                content.stroke();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } finally {
            try {
                stamper.close();
                fileOutputStream.close();
                reader.close();
            } catch (DocumentException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileOutputStream;
    }
}

4、編寫(xiě)測(cè)試接口

import cn.xj.util.FreeMarkUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@RestController
@RequestMapping("/report")
public class ReportController {

    @GetMapping("/doc2pdf")
    public void doc2pdf(HttpServletResponse response) {
        Map<String, Object> params = new HashMap<>();
        params.put("username","xiangjiao1");
        params.put("password","******");
        params.put("age",22);
        params.put("email","專注寫(xiě)bug測(cè)試中文");

        final byte[] data = FreeMarkUtils.createDocx2Pdf(params, "templates_report/001.docx");
        String fileName = UUID.randomUUID().toString() + "_001_test.pdf";
        generateFile(response, data, fileName);
    }

    /**
     * 下載文件
     * @param response 相應(yīng)
     * @param data 數(shù)據(jù)
     * @param fileName 文件名
     */
    private void generateFile(HttpServletResponse response, byte[] data, String fileName) {
        response.setHeader("content-Type", "application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        try {
            response.getOutputStream().write(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                response.getOutputStream().close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

請(qǐng)求測(cè)試

http://localhost/report/doc2pdf

docx4j 復(fù)雜docx文件轉(zhuǎn)pdf碰見(jiàn)的坑總結(jié)

轉(zhuǎn)pdf出現(xiàn)空格壓縮、中文縮減等問(wèn)題,可以考慮將半角替換成全角,將模板中的空格使用全角空格替換。

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java super關(guān)鍵字的使用方法詳解

    Java super關(guān)鍵字的使用方法詳解

    這篇文章主要介紹了Java super關(guān)鍵字的使用方法詳解的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家對(duì)super關(guān)鍵字徹底掌握,需要的朋友可以參考下
    2017-10-10
  • java直接插入排序示例

    java直接插入排序示例

    這篇文章主要介紹了java直接插入排序示例,插入排序的比較次數(shù)仍然是n的平方,但在一般情況下,它要比冒泡排序快一倍,比選擇排序還要快一點(diǎn)。它常常被用在復(fù)雜排序算法的最后階段,比如快速排序。
    2014-05-05
  • Java字符串拼接效率測(cè)試過(guò)程解析

    Java字符串拼接效率測(cè)試過(guò)程解析

    這篇文章主要介紹了Java字符串拼接效率測(cè)試過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-05-05
  • SpringMVC配置多個(gè)properties文件之通配符解析

    SpringMVC配置多個(gè)properties文件之通配符解析

    這篇文章主要介紹了SpringMVC配置多個(gè)properties文件之通配符解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot實(shí)現(xiàn)自定義事件的方法詳解

    SpringBoot實(shí)現(xiàn)自定義事件的方法詳解

    這篇文章將用實(shí)例來(lái)和大家介紹一下如何在SpringBoot中自定義事件來(lái)使用觀察者模式。文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)SpringBoot有一定的幫助,需要的可以參考一下
    2022-06-06
  • 詳解Java常用工具類(lèi)—泛型

    詳解Java常用工具類(lèi)—泛型

    這篇文章主要介紹了Java常用工具類(lèi)—泛型,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • java中的Consumer、Supply如何實(shí)現(xiàn)多參數(shù)?

    java中的Consumer、Supply如何實(shí)現(xiàn)多參數(shù)?

    Java的Consumer接口只能接受一個(gè)參數(shù),但可以通過(guò)自定義接口、使用Tuple或嵌套結(jié)構(gòu)來(lái)實(shí)現(xiàn)對(duì)多個(gè)參數(shù)的處理,對(duì)于Supplier接口,它不能接受參數(shù),但可以通過(guò)自定義BiSupplier、結(jié)合Function或封裝參數(shù)為對(duì)象來(lái)實(shí)現(xiàn)對(duì)兩個(gè)參數(shù)并返回一個(gè)值的功能
    2024-11-11
  • JAVA 獲取系統(tǒng)當(dāng)前時(shí)間實(shí)例代碼

    JAVA 獲取系統(tǒng)當(dāng)前時(shí)間實(shí)例代碼

    這篇文章主要介紹了JAVA 獲取系統(tǒng)當(dāng)前時(shí)間實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • springboot?整合?clickhouse的實(shí)現(xiàn)示例

    springboot?整合?clickhouse的實(shí)現(xiàn)示例

    本文主要介紹了springboot?整合?clickhouse的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • springmvc視圖解析流程代碼實(shí)例

    springmvc視圖解析流程代碼實(shí)例

    這篇文章主要介紹了springmvc視圖解析流程代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-01-01

最新評(píng)論

遵义县| 云梦县| 濮阳县| 宜宾市| 凤城市| 溧水县| 克东县| 津市市| 霍城县| 利川市| 二手房| 原阳县| 洛南县| 广汉市| 通渭县| 珲春市| 汨罗市| 龙岩市| 湛江市| 罗源县| 越西县| 台南县| 和田县| 安西县| 锦屏县| 祥云县| 中山市| 宜城市| 中牟县| 开原市| 贵港市| 扬州市| 乌审旗| 上林县| 离岛区| 三台县| 沧源| 延津县| 两当县| 左权县| 舒城县|