springboot 动态导出pdf

springboot 动态导出pdf

原理是通过freemarker插入数据到html模版里面,html你就叫前端帮你写好,他不写你就告诉你主管让他叫他写,你只管往预留的位置插入数据就行,然后通过itextpdf会将准备好html文件转成PDF。

1、准备依赖

        <!--下载pdf begin-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>4.0.3</version>
        </dependency>
        <!-- freemarker模版 -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        <!--下载pdf end-->

2、准备html模版

<html>
<head>
    <meta charset="UTF-8">

    <style>
        .main-container {
            font-family: SF-UI-Text-Regular;
            width: 21cm;
            margin: 0 auto;
            padding: 20px;
        }

        .float-left {
            float: left;
        }

        .float-right {
            float: right;
        }

        .padding-left-right {
            padding-left: 20px;
            padding-right: 20px;
        }

        .margin-left-right {
            margin-left: 20px;
            margin-right: 20px;
        }

        .section {
            /*border: 3px dashed #CCC;*/
            /*padding: 20px;*/
            border-Top: 2px dashed #D3D3D3;
            padding-Top: 13px;
            margin-bottom: 16px;
            margin-Top: 20px;
        }

        .section-details p {
            color: #126089;
            /*font-size: 16px;*/
        }

        .grouper {
            overflow: hidden;
        }

        .grid-50 {
            width: 50%;
        }

        @font-face {
            font-family: 'SF-UI-Text-Regular';
            src: url("https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/fonts/SF-UI-Text-Regular.otf");
            font-style: normal;
        }

        h1 {
            font-size: 22px;
            font-family: 'SF-UI-Text-Regular';
        }

        .h1-main {
            margin-top: 90px;
        }

        p {
            margin: 0 0 10px 0;
            font-family: 'SF-UI-Text-Regular';
            font-size: 12px;
        }

        .p-spec {
            color: #149a9a;
            font-weight: bold;
        }

        table, th, td {
            padding: 5px;
            border-collapse: collapse;
        }

        th, td {
            border: 1px solid #D3D3D3;
        }

        .margin-b-30 {
            margin-bottom: 30px;
        }

        .row:after {
            content: "";
            display: table;
            clear: both;
        }

        .column-4 {
            float: left;
            width: 33.33%;
            padding: 10px;
        }

        .column-8 {
            float: left;
            width: 66.66%;
            padding: 10px;
        }

        * {
            box-sizing: border-box;
            font-size: 12px;
        }
    </style>
</head>
<body>

<div class="main-container">
    <div style="background-color: #fff">
        <div class="grouper main-header grouper padding-left-right" style="padding-top: 20px">

            <div class="margin-b-30 row">
                <div class="column-4">
                    <img style="max-width:90%"
                         src="https://s3-ap-southeast-1.amazonaws.com/content.staging.whitecoat.global/PDF/Templates/Images/WhiteCoat_Tax_Invoice.png">
                </div>
                <div class="column-4">
                    WhiteCoat Holdings Pte Ltd. <br/>
                    Clinic Licence No.: 18M0119/01/182 <br/>
                    201 Henderson Road #05-11/12 <br/>
                    Apex @ Henderson <br/>
                    Singapore 159545 <br/>
                </div>
                <div class="column-4">
                    GST Reg. No: 201610235E <br/>
                    T: +65 6909 6909 <br/>
                    F: +65 6909 6909 <br/>
                    E: contactus@whitecoat.com.sg <br/>
                    <a style="text-decoration: none;" href="https://whitecoat.com.sg/">whitecoat.com.sg</a>
                </div>
            </div>
        </div>

        <div class="main-body">
            <div class="grouper">
                <div class="grouper margin-left-right row" style="border-Top: 1px solid #D3D3D3;padding-top:20px;">
                    <div class="column-4">
                        Name: <br/>
                        ${data.name!} <br/><br/>
                        NRIC/FIN/Passport No: <br/>
                        ${data.idNo!}
                    </div>
                    <div class="column-8">
                        Invoice No.: <br/>
                        ${data.invoiceNo!} <br/><br/>
                        Invoice Date: <br/>
                        ${data.invoiceDateStr!} <br/><br/>
                        <i>This is a computer generated invoice. No signature is required.</i>

                    </div>
                </div>

                <div class="grouper margin-left-right" style="border-Top: 1px solid #D3D3D3;padding-top:20px;">
                    <table>
                        <tr>
                            <th>S/N</th>
                            <th colspan="2">Description</th>
                            <th style="border:1px solid #D3D3D3;">Amount</th>
                        </tr>
                        <tr>
                            <td style="width:30px;text-align:center;">1</td>
                            <td style="width:550px; border-right: none">
                                Medication <br/>
                                <#list data.medicationList as item>
                                    ${item.productName!} <br/>
                                </#list>
                                <i><br/>Subtotal</i>
                            </td>
                            <td style="text-align:right; border-left: none">
                                Quantity <br/>
                                <#list data.medicationList as item>
                                    ${item.quantity!} <br/>
                                </#list>
                                <i style="color:#fff"><br/>Subtotal</i>
                            </td>
                            <td style="width:200px;text-align:right">
                                <br/>
                                <#list data.medicationList as item>
                                    $${item.amount!} <br/>
                                </#list>
                                <br/><i>${data.subtotal!}</i>
                            </td>
                        </tr>
                        <tr>
                            <td style="text-align:center;">2</td>
                            <td colspan="2">Administrative charges</td>
                            <td style="text-align:right">$${data.adminCharge!}</td>
                        </tr>
                        <tr>
                            <td colspan="3" style="text-align:right; border-bottom: none; border-left: none">
                                Subtotal(Excluding GST)
                            </td>
                            <td style="text-align:right">$${data.subtotalExcludingGST!}</td>
                        </tr>
                        <tr>
                            <td colspan="3"
                                style="text-align:right; ; border-bottom: none; border-top: none; border-left: none">
                                GST(${data.tax!}%)
                            </td>
                            <td style="text-align:right">$${data.GST!}</td>
                        </tr>
                        <tr>
                            <td colspan="3"
                                style="text-align:right; border-top: none; border-left: none; border-bottom: none">
                                Total(Including GST)
                            </td>
                            <td style="text-align:right">$${data.totalIncludingGST!}</td>
                        </tr>
                    </table>

                </div>

                <div class="grouper margin-left-right float-left" style="padding-bottom :20px;padding-top :20px">
                        <span>
                            Bank remittance details for payment by Bank Telegraphic <br/>
                            Transfer in Singapore Dollars to:<br/>
                            Name of Bank: United Overseas Bank Ltd. Holland Branch<br/>
                            Account Name: Whitecoat Holdings Pte Ltd.<br/>
                            Account No: 341-308-316-6<br/>
                            Bank Code: 7375<br/>
                            Branch Code: 020<br/>
                            Bank Swift Code: UOVBSGSG
                        </span>
                </div>

            </div>
        </div>

    </div>

</body>
</html>

3、下载代码

    @ApiOperation(value = "下载pdf")
    @GetMapping("downloadPDF/staffPurchase")
    public ResponseResult download(String id, HttpServletResponse response) throws Exception {

        StaffPurchasePDFVo data = staffPurchaseMapper.getStaffPurchasePDFData(id);
        HashMap<String, Object> mapData = Maps.newHashMap();
        mapData.put("data", data);
        long timeMillis = System.currentTimeMillis();
        String templateContent = HtmlUtils.getTemplateContent("Staff_Purchase_Receipt.ftl", mapData);
        HtmlUtils.html2Pdf(response, templateContent, timeMillis + "");
        return ResponseResult.success();
    }

4、htmlutils代码

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.layout.font.FontProvider;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.Objects;

@Slf4j
public class HtmlUtils {

    /**
     * @return
     * @throws Exception
     */
    public static String getTemplateDirectory() {
        ClassLoader classLoader = HtmlUtils.class.getClassLoader();
        URL resource = classLoader.getResource("templates");
        try {
            return Objects.requireNonNull(resource).toURI().getPath();
        } catch (URISyntaxException e) {
            log.error("获取模板文件夹失败,{}", e);
        }
        return null;
    }

    /**
     * 获取模板内容
     *
     * @param templateName 模板文件名
     * @param paramMap     模板参数
     * @return
     * @throws Exception
     */
    public static String getTemplateContent(String templateName, Map<String, Object> paramMap) throws Exception {
        Configuration config = ApplicationContextUtil.getBean(FreeMarkerConfigurer.class).getConfiguration();
        config.setDefaultEncoding("UTF-8");
        Template template = config.getTemplate(templateName, "UTF-8");
        return FreeMarkerTemplateUtils.processTemplateIntoString(template, paramMap);
    }
    /**
     * HTML 转 PDF
     *
     * @param content html内容
     * @param outPath 输出pdf路径
     * @return 是否创建成功
     */
    public static boolean html2Pdf(String content, String outPath) {
        try {
            ConverterProperties converterProperties = new ConverterProperties();
            converterProperties.setCharset("UTF-8");
            FontProvider fontProvider = new FontProvider();
            fontProvider.addSystemFonts();
            converterProperties.setFontProvider(fontProvider);
            HtmlConverter.convertToPdf(content, new FileOutputStream(outPath), converterProperties);
        } catch (Exception e) {
            log.error("生成模板内容失败,{}", e);
            return false;
        }
        return true;
    }

    /**
     * HTML 转 PDF
     *
     * @param content html内容
     * @return PDF字节数组
     */
    public static void html2Pdf(HttpServletResponse response, String content,String filename) throws IOException {
        response.setHeader("Content-Type", "application/octet-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename="+filename+".pdf");
        try (ServletOutputStream outputStream = response.getOutputStream()) {
            ConverterProperties converterProperties = new ConverterProperties();
            converterProperties.setCharset("UTF-8");
            FontProvider fontProvider = new FontProvider();
            fontProvider.addSystemFonts();
            converterProperties.setFontProvider(fontProvider);
            HtmlConverter.convertToPdf(content, outputStream, converterProperties);
        } catch (Exception e) {
            log.error("生成 PDF 失败,{}", e);
        }
    }
} 

ApplicationContextUtil代码、

import org.springframework.beans.BeansException;
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

@Configuration
@AutoConfigureOrder(-1)
public class ApplicationContextUtil implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    public static Object getBeanByName(String beanName) {
        if (applicationContext == null) {
            return null;
        }
        return applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> type) {
        return applicationContext.getBean(type);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }


}

5、freemarker的基本语法

https://developer.aliyun.com/article/942606

6、注意

如果css写了具体的大小比如width: 21cm;,那么下载出来的pdf会因为超出边界被截取,别写。

  • 16
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot导出PDF文件可以使用一些开源的Java库,例如Apache PDFBox或iText。下面是一个简单的示例代码来演示如何使用Apache PDFBox导出PDF文件: 1. 首先,确保你的Spring Boot项目中引入了Apache PDFBox的依赖。可以在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.26</version> </dependency> ``` 2. 创建一个控制器或服务类,编写导出PDF的方法: ```java import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDType1Font; import org.springframework.stereotype.Service; @Service public class PdfExportService { public void exportPdf() { try (PDDocument document = new PDDocument()) { PDPage page = new PDPage(); document.addPage(page); try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) { contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12); contentStream.beginText(); contentStream.newLineAtOffset(100, 700); contentStream.showText("Hello, PDFBox!"); contentStream.endText(); } document.save("path/to/exported.pdf"); } catch (IOException e) { e.printStackTrace(); } } } ``` 3. 在你的控制器或服务中调用导出PDF的方法: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class PdfExportController { @Autowired private PdfExportService pdfExportService; @GetMapping("/export-pdf") public String exportPdf() { pdfExportService.exportPdf(); return "PDF exported successfully!"; } } ``` 当你访问`/export-pdf`路径时,将会触发导出PDF的方法,生成一个名为"exported.pdf"的文件。你可以根据自己的需求修改导出的内容和文件路径。记得在实际应用中添加合适的异常处理和错误处理机制。希望这个简单的示例能对你有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值