springboot 动态导出pdf

springboot 动态导出pdf

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

### 1、准备依赖

        
        <dependency>
            <groupId>com.itextpdfgroupId>
            <artifactId>html2pdfartifactId>
            <version>4.0.3version>
        dependency>
        
        <dependency>
            <groupId>org.freemarkergroupId>
            <artifactId>freemarkerartifactId>
            <version>2.3.30version>
        dependency>
        

### 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: [email protected] <br/>
                    <a style="text-decoration: none;" href="https://whitecoat.com.sg/">whitecoat.com.sga>
                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/Nth>
                            <th colspan="2">Descriptionth>
                            <th style="border:1px solid #D3D3D3;">Amountth>
                        tr>
                        <tr>
                            <td style="width:30px;text-align:center;">1td>
                            <td style="width:550px; border-right: none">
                                Medication <br/>
                                <#list data.medicationList as item>
                                    ${item.productName!} <br/>
                                #list>
                                <i><br/>Subtotali>
                            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/>Subtotali>
                            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;">2td>
                            <td colspan="2">Administrative chargestd>
                            <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

你可能感兴趣的:(spring,boot,pdf,后端)