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

Java實現(xiàn)生成pdf并解決表格分割的問題

 更新時間:2023年11月30日 08:18:55   作者:苦瓜不苦077  
這篇文章主要為大家詳細(xì)介紹了如何利用Java實現(xiàn)生成pdf,并解決表格分割的問題,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

Maven依賴

<dependency>
    <groupId>org.freemarker</groupId>
    <artifactId>freemarker</artifactId>
    <version>2.3.31</version>
</dependency>

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf</artifactId>
    <version>9.1.16</version>
</dependency>

自定義ftl模板

該模板是由html頁面直接后綴而成,模版名稱定為template-01.ftl

注意事項

中文亂碼問題

需要在模板中添加font-family: SimSun, serif;標(biāo)簽,可解決中文亂碼問題

body {
    /*解決中文亂碼*/
    font-family: SimSun, serif;
    /*自動換行*/
    word-break: break-all;
}

頁眉和頁腳

其實頁眉和頁腳可以通過定義的ftl模板來實現(xiàn)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        /*頁眉的上下左右邊距*/
        @page {
            margin: 30mm 20mm 30mm 20mm;
        }
        @page {
            /*頁眉*/
            @top-center {
                content: element(header)
            }
            /*頁腳*/
            @bottom-center {
                content: element(footer)
            }
        }
        /*頁眉*/
        #header {
            position: running(header);
            margin-top: 10mm;
        }
        /*頁腳*/
        #footer {
            position: running(footer);
        }
        /*分頁*/
        #page-number:before {
            content: counter(page);
        }
        /*分頁*/
        #page-count:before {
            content: counter(pages);
        }
    </style>
</head>
<body>
<!--頁眉-->
<div id="header">
    深圳市xxx有限公司
    <hr/>
</div>
<!--頁腳-->
<div id="footer">
    頁碼<span id="page-number"></span>/<span id="page-count"></span>
</div>
</body>
</html>

完整ftl模板頁面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        /*頁眉的上下左右邊距*/
        @page {
            margin: 30mm 20mm 30mm 20mm;
        }
        @page {
            /*頁眉*/
            @top-center {
                content: element(header)
            }
            /*頁腳*/
            @bottom-center {
                content: element(footer)
            }
        }
        /*頁眉*/
        #header {
            position: running(header);
            margin-top: 10mm;
        }
        /*頁腳*/
        #footer {
            position: running(footer);
        }
        /*分頁*/
        #page-number:before {
            content: counter(page);
        }
        /*分頁*/
        #page-count:before {
            content: counter(pages);
        }
        * {
            padding: 0;
            margin: 0;
        }
        body {
            /*解決中文亂碼*/
            font-family: SimSun, serif;
            /*自動換行*/
            word-break: break-all;
        }
        .main {
            width: 100%;
            height: auto;
            margin: 0 auto;
            text-align: center;
        }
        table {
            width: 100%;
            border-collapse: collapse;
        }
        td, th {
            line-height: 20px;
            padding: 7px 5px;
            border: 1px solid #999999;
        }
    </style>
</head>
<body>
<!--頁眉-->
<div id="header">
    深圳市xxx有限公司
    <hr/>
</div>
<!--頁腳-->
<div id="footer">
    頁碼<span id="page-number"></span>/<span id="page-count"></span>
</div>
<div class="main">
    <h1>深圳市xxx有限公司</h1>
    <p style="margin: 30px 0 50px 0;text-align: left;">
        人在世俗的世界中行走著,在慢慢流逝的時間里靜靜等待著成年那一刻的全速奔跑??陕L的等待過后卻發(fā)現(xiàn),形形色色的欲望與世俗觀念像橡皮泥一樣粘在身上,越積越重,最后竟無限膨脹,束縛了我們的雙腿,減緩了我們的步伐。我們不能輕松上路,也不能全速奔跑。它們甚至遮蔽住我們的雙眼,遮掩住我們純真的心,讓我們的腳步開始凌亂,旋轉(zhuǎn)在燈紅酒綠的花花世界里……
    </p>
    <table>
        <thead>
        <tr>
            <th>姓名</th>
            <th>年齡</th>
            <th>性別</th>
        </tr>
        </thead>
        <tbody>
        <#if !data?? || (data?size==0)>
            <tr>
                <td colspan="3">無</td>
            </tr>
        <#else>
            <#list data as item>
                <tr>
                    <td>${item.name}</td>
                    <td>${item.age}</td>
                    <td>${item.sex}</td>
                </tr>
            </#list>
        </#if>
        </tbody>
    </table>
</div>
</body>
</html>

PDF工具類

字體包SimSun.ttc、ArialUni.ttf自行下載

package org.example;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Locale;
/**
 * @author 苦瓜不苦
 * @date 2023/11/28 18:33
 **/
public class PDFUtil {
    /**
     * 模板生成器
     *
     * @param createFile 生成文件的路徑
     * @param ftlName    模板名稱
     * @param object     數(shù)據(jù)
     */
    public static void processTemplate(String createFile, String ftlName, Object object) {
        Configuration configuration = null;
        StringWriter writer = null;
        ByteArrayOutputStream outputStream = null;
        try {
            // 初始化模版
            configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            writer = new StringWriter();
            outputStream = new ByteArrayOutputStream();
            // 加載模板目錄
            configuration.setClassForTemplateLoading(MainApi.class, "/module");
            configuration.setClassicCompatible(true);
            ITextRenderer renderer = new ITextRenderer();
            // 設(shè)置字體
            ITextFontResolver fontResolver = renderer.getFontResolver();
            fontResolver.addFont("fonts/SimSun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            fontResolver.addFont("fonts/ArialUni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
            configuration.setEncoding(Locale.CHINA, "UTF-8");
            // 讀取模板文件
            Template template = configuration.getTemplate(ftlName, "UTF-8");
            // 寫入數(shù)據(jù)到模板中
            template.process(object, writer);
            writer.flush();
            // 獲取填充好數(shù)據(jù)的html頁面
            String html = writer.toString();
            renderer.setDocumentFromString(html);
            renderer.layout();
            // 通過html頁面字符串轉(zhuǎn)換成pdf文件
            renderer.createPDF(outputStream);
            renderer.finishPDF();
            return outputStream.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (Objects.nonNull(outputStream)) {
                    outputStream.close();
                }
                if (Objects.nonNull(writer)) {
                    writer.close();
                }
                if (Objects.nonNull(configuration)) {
                    configuration.clone();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

調(diào)用測試

public class Main {
    public static void main(String[] args) {
        String fromFile = "./" + System.currentTimeMillis() + ".pdf";
        String toFile = "template-01.ftl";
        List<JSONObject> data = new ArrayList<>();
        for (int i = 0; i < 60; i++) {
            JSONObject object = new JSONObject();
            object.set("name", "張三");
            object.set("sex", "男");
            object.set("age", "18");
            data.add(object);
        }
        JSONObject object = new JSONObject();
        object.set("data", data);
        byte[] bytes = PDFUtil.processTemplate(toFile, object);
        File file = FileUtil.writeBytes(bytes, fromFile);
        System.err.println(file);
    }
}

擴(kuò)展情況

以上代碼即可生成好一份PDF文檔了,但是會存在一些問題,

表格的形式會被自動切割,出現(xiàn)以下情況

按照不同的需求,可以使用不同的方式來處理。

一是,當(dāng)被分頁時,每頁都需要一個標(biāo)題的存在。

二是,分頁的頭部和尾部需要閉合起來

還有擴(kuò)展于圖片水印或者文字水印的需求

圖片水印方法

/**
 * 添加圖片水印
 *
 * @param bytes pdf字節(jié)
 * @return
 */
public static byte[] appendImageWatermark(byte[] bytes) {
    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
        PdfReader reader = new PdfReader(bytes);
        PdfStamper stamper = new PdfStamper(reader, byteArrayOutputStream);
        // 加載水印圖片
        URL url = PDFUtil.class.getClassLoader().getResource("fonts/bg.png");
        Image image = Image.getInstance(url);
        // 設(shè)置等比縮放 圖片大小
        image.scalePercent(20);
        // 自定義大小
        // image.scaleAbsolute(200,100);
        // 設(shè)置旋轉(zhuǎn)弧度
        image.setRotation(0);
        // 設(shè)置旋轉(zhuǎn)角度
        image.setRotationDegrees(0);
        // 創(chuàng)建PdfGState對象并設(shè)置透明度
        PdfGState gState = new PdfGState();
        // 填充透明度
        gState.setFillOpacity(0.3f);
        // 描邊透明度
        gState.setStrokeOpacity(0.3f);
        // PDF總頁數(shù)
        int total = reader.getNumberOfPages() + 1;
        for (int i = 1; i < total; i++) {
            Rectangle pageRect = reader.getPageSizeWithRotation(i);
            PdfContentByte content = stamper.getOverContent(i);
            content.saveState();
            content.setGState(gState);
            // 設(shè)置圖片水印
            // 獲取pdf每頁的長寬
            float width = pageRect.getWidth();
            float top = pageRect.getTop();
            // 獲取縮放之后水印圖片的長寬
            float scaledWidth = image.getScaledWidth();
            float scaledHeight = image.getScaledHeight();
            // 通過計算將水印添加到中間
            float x = (width - scaledWidth) / 2;
            float y = (top - scaledHeight) / 2;
            content.addImage(image, scaledWidth, 60, 0, scaledHeight, x, y);
            content.restoreState();
        }
        stamper.close();
        reader.close();
        return byteArrayOutputStream.toByteArray();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

文字水印方法

/**
 * 添加文字水印
 *
 * @param bytes pdf字節(jié)
 * @param text  水印文字
 * @param size  文字大小
 * @return
 */
public static byte[] appendTextWatermark(byte[] bytes, String text, Integer size) {
    try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
        PdfReader reader = new PdfReader(bytes);
        PdfStamper stamper = new PdfStamper(reader, byteArrayOutputStream);
        // 創(chuàng)建PdfGState對象并設(shè)置透明度
        PdfGState gState = new PdfGState();
        // 填充透明度
        gState.setFillOpacity(0.3f);
        // 描邊透明度
        gState.setStrokeOpacity(0.3f);
        // 加載字體
        BaseFont baseFont = BaseFont.createFont("fonts/ArialUni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
        // PDF總頁數(shù)
        int total = reader.getNumberOfPages() + 1;
        for (int i = 1; i < total; i++) {
            Rectangle pageRect = reader.getPageSizeWithRotation(i);
            PdfContentByte content = stamper.getOverContent(i);
            content.saveState();
            // 獲取pdf每頁的長寬
            float width = pageRect.getWidth();
            float top = pageRect.getTop();
            // 通過計算將水印添加到中間
            float x = (width - (size * text.length())) / 2;
            float y = (top - size) / 2;
            // 設(shè)置字體水印
            content.beginText();
            content.setGState(gState);
            // 字體
            content.setFontAndSize(baseFont, size);
            // 顏色
            content.setColorFill(Color.BLACK);
            // 水印位置
            content.showTextAligned(Element.ALIGN_LEFT, text, x, y, 30);
            content.endText();
            content.restoreState();
        }
        stamper.close();
        reader.close();
        return byteArrayOutputStream.toByteArray();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

表格分頁被切割問題-方式一

在ftl模板中的style標(biāo)簽中添加css樣式

tr {
    page-break-inside: avoid;
    page-break-after: auto;
}

同一個表格在分頁時,會被自動添加上下邊框

表格分頁被切割問題-方式二

在ftl模板中的style標(biāo)簽中添加css樣式,需要注意的是表格的標(biāo)題需要使用thead標(biāo)簽包裹,表格其他行用tbody標(biāo)簽包裹

<style>
table {
    page-break-inside: auto;
    -fs-table-paginate: paginate;
    border-spacing: 0;
}
tr {
    page-break-inside: avoid;
    page-break-after: auto;
}
</style>
<body>
<table>
    <thead>
    <tr>
        <th>姓名</th>
        <th>年齡</th>
        <th>性別</th>
    </tr>
    </thead>
    <tbody>
    <#if !data?? || (data?size==0)>
        <tr>
            <td colspan="3">無</td>
        </tr>
    <#else>
        <#list data as item>
            <tr>
                <td>${item.name}</td>
                <td>${item.age}</td>
                <td>${item.sex}</td>
            </tr>
        </#list>
    </#if>
    </tbody>
</table>
</body>

被分頁時,表格的標(biāo)題也會攜帶下來

以上就是Java實現(xiàn)生成pdf并解決表格分割的問題的詳細(xì)內(nèi)容,更多關(guān)于Java生成pdf的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Java實現(xiàn)簡單的郵件群發(fā)功能

    基于Java實現(xiàn)簡單的郵件群發(fā)功能

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言編寫一個簡單的工具類,可以實現(xiàn)郵件群發(fā)功能。文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-05-05
  • 一文帶你搞懂Redis分布式鎖

    一文帶你搞懂Redis分布式鎖

    本篇文章主要來介紹一下如何Redis實現(xiàn)分布式鎖的演進(jìn)過程,以及為什么不能直接用Setnx實現(xiàn)分布式鎖,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2022-09-09
  • java通過cglib動態(tài)生成實體bean的操作

    java通過cglib動態(tài)生成實體bean的操作

    這篇文章主要介紹了java通過cglib動態(tài)生成實體bean的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • Java虛擬機(jī)的核心原理與工作機(jī)制解讀

    Java虛擬機(jī)的核心原理與工作機(jī)制解讀

    這篇文章主要介紹了Java虛擬機(jī)的核心原理與工作機(jī)制,將深入探討JVM的核心概念、架構(gòu)、內(nèi)存模型、垃圾回收機(jī)制等內(nèi)容,幫助你全面掌握J(rèn)VM的知識
    2025-05-05
  • Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json)

    Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json)

    本文主要介紹了Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • 使用log4j MDC實現(xiàn)日志追蹤

    使用log4j MDC實現(xiàn)日志追蹤

    這篇文章主要介紹了使用log4j MDC實現(xiàn)日志追蹤方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • xxl-job對比ElasticJob使用示例詳解

    xxl-job對比ElasticJob使用示例詳解

    這篇文章主要為大家介紹了xxl-job對比ElasticJob使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Java并發(fā)之AQS與自旋鎖詳解

    Java并發(fā)之AQS與自旋鎖詳解

    這篇文章主要介紹了Java并發(fā)之AQS與自旋鎖詳解,類如其名,抽象的隊列式的同步器,AQS定義了一套多線程訪問共享資源的同步器框架,許多同步類實現(xiàn)都依賴于它,如常用的ReentrantLock/Semaphore/CountDownLatch,需要的朋友可以參考下
    2023-10-10
  • java實現(xiàn)登錄驗證碼功能

    java實現(xiàn)登錄驗證碼功能

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)登錄驗證碼功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • Java面試必考之如何在項目中優(yōu)雅的拋出異常

    Java面試必考之如何在項目中優(yōu)雅的拋出異常

    這篇文章主要為大家詳細(xì)介紹了Java中的幾種異常關(guān)鍵字和異常類相關(guān)知識,本文比較適合剛?cè)肟覬ava的小白以及準(zhǔn)備秋招的大佬閱讀,需要的可以收藏一下
    2023-06-06

最新評論

鄢陵县| 招远市| 东阿县| 墨竹工卡县| 合水县| 琼中| 临洮县| 平遥县| 南靖县| 威远县| 治多县| 奉贤区| 万全县| 保亭| 从江县| 威信县| 广西| 阳城县| 二手房| 苗栗县| 司法| 大方县| 广州市| 封开县| 襄樊市| 静安区| 阿合奇县| 五家渠市| 华安县| 长宁县| 积石山| 镇平县| 农安县| 山阳县| 常熟市| 潍坊市| 邻水| 楚雄市| 南平市| 西平县| 高州市|