Java 下载成PDF格式

Java 下载成PDF格式

1、maven配置 

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

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.11</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf.tool</groupId>
            <artifactId>xmlworker</artifactId>
            <version>5.5.11</version>
        </dependency>

        <dependency>
            <groupId>org.xhtmlrenderer</groupId>
            <artifactId>core-renderer</artifactId>
            <version>R8</version>
        </dependency>

2、工具类

package com.jx.platform.util;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.*;
import java.net.MalformedURLException;
import java.nio.charset.Charset;
import java.util.Map;

public class ReportToPdfUtil {
    /**
     *
     * @param data 封装好的数据
     * @param HTMLTempleFileName html模板文件名称
     * @param HTMLTempleFileFloder 生成的pdf文件的目录
     * @param pdfFile 生成的pdf文件
     */
    public static void createPdf(Map<String,Object> data, String HTMLTempleFileName, String HTMLTempleFileFloder, String pdfFile) throws IOException, DocumentException, com.lowagie.text.DocumentException{
        Configuration freemarkerCfg =new Configuration(Configuration.VERSION_2_3_28);
        //freemarker的模板目录
        freemarkerCfg.setDirectoryForTemplateLoading(new File(HTMLTempleFileFloder));
        String content = freeMarkerRender(freemarkerCfg, data, HTMLTempleFileName);
        createPdf(content, HTMLTempleFileFloder, pdfFile);
    }

    /**
     * freemarker渲染html
     */
    private static String freeMarkerRender( Configuration freemarkerCfg, Map<String, Object> data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            template.setEncoding("UTF-8");
            // 合并数据模型与模板
            template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

    private static void createPdf(String content,String imageFloder, String dest) throws IOException, DocumentException, com.lowagie.text.DocumentException {
        Document document = new Document();
        OutputStream os = new FileOutputStream(dest);
        PdfWriter writer = PdfWriter.getInstance(document, os);
        // document.setMargins(10, 10, 30, 30);
        BaseFont bfChinese = getChineseBaseFont();

        document.open();
        // 为报告添加页眉,事件的发生是在生成报告之后,写入到硬盘之前
        addHeader(document, writer, imageFloder, bfChinese);
        addFooter(document, writer, bfChinese);
        XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
        worker.parseXHtml(writer, document, new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), new ChineseFontProvider(bfChinese));
        document.close();
        writer.close();
    }

    /**
     * 给pdf文件添加页眉
     * @param document
     * @param writer
     * @param imageFloder
     * @throws IOException
     * @throws DocumentException
     */
    private static void addHeader(Document document, PdfWriter writer, String imageFloder, BaseFont bfChinese) throws IOException, DocumentException{
        PdfPTable pdfPTable = new PdfPTable(1);
        Header headerTable = new Header(pdfPTable);
        Font chineseFont = new Font(bfChinese, 10f, Font.NORMAL, BaseColor.GRAY);
        headerTable.setTableHeader(writer, imageFloder, "logo.png", chineseFont);
        // document.add(pdfPTable);
    }

    private static void addFooter(Document document, PdfWriter writer, BaseFont bfChinese) throws IOException, DocumentException{
        Font chineseFont = new Font(bfChinese, 10f, Font.NORMAL, BaseColor.GRAY);
        Footer footer = new Footer(chineseFont);
        // Footer.setTableFooter(writer, chineseFont);
        // document.add(footer);
        writer.setPageEvent(footer);
    }

    private static BaseFont getChineseBaseFont() {
        BaseFont bfChinese = null;
        try {
            bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bfChinese;
    }

    static class ChineseFontProvider extends XMLWorkerFontProvider {
        private BaseFont bfChinese;
        public ChineseFontProvider(BaseFont bfChinese) {
            this.bfChinese = bfChinese;
        }
        public Font getFont(String fontName, String encoding, boolean embedded, float size, int style, BaseColor color, boolean cached){
            Font font = new Font(bfChinese, size, style, color);
            font.setColor(color);
            return font;
        }
    }

    //页眉事件
    private static class Header extends PdfPageEventHelper {
        public static PdfPTable pdfPTable;

        public Header(PdfPTable pdfPTable) {
            Header.pdfPTable = pdfPTable;
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            //把页眉表格定位
            pdfPTable.writeSelectedRows(0, -1, 36, 840, writer.getDirectContent());
        }

        /**
         * 设置页眉
         * @param writer
         * @throws MalformedURLException
         * @throws IOException
         * @throws DocumentException
         */
        public void setTableHeader(PdfWriter writer, String imageFloder, String imgFileName, Font font) throws MalformedURLException, IOException, DocumentException {
            PdfPTable table = new PdfPTable(4);
            float[] columnWidth={0.1f, 0.1f, 0.1f, 0.1f};
            table.setWidths(columnWidth);
            table.setTotalWidth(520f);
            table.setSpacingBefore(10f); // 前间距
            table.setSpacingAfter(10f); // 后间距

            PdfPCell paragraphCell = new PdfPCell();
            paragraphCell.setColspan(3);
            paragraphCell.setBorderWidthTop(0);
            paragraphCell.setBorderWidthLeft(0);
            paragraphCell.setBorderWidthRight(0);
            paragraphCell.setBorderWidthBottom(1);
            paragraphCell.setPaddingTop(10f);
            paragraphCell.setPaddingLeft(20f);
            String string = "久心医疗设备巡检报告";
            Paragraph p = new Paragraph(string, font);
            paragraphCell.addElement(p);
            table.addCell(paragraphCell);

            Image logoImage = Image.getInstance(imageFloder + imgFileName); //图片自己传
            logoImage.scaleAbsolute(204f, 54f);
            logoImage.setWidthPercentage(90);
            PdfPCell imgCell = new PdfPCell();
            imgCell.setColspan(1);
            imgCell.setBorderWidthTop(0);
            imgCell.setBorderWidthLeft(0);
            imgCell.setBorderWidthRight(0);
            imgCell.setBorderWidthBottom(1);
            imgCell.setPaddingTop(0f);
            imgCell.setPaddingLeft(0f);
            imgCell.addElement(logoImage);
            table.addCell(imgCell);
            Header event = new Header(table);
            writer.setPageEvent(event);
        }
    }

    //页脚事件
    private static class Footer extends PdfPageEventHelper {
        private  Font chineseFont;

        @SuppressWarnings("static-access")
        public Footer(Font font) {
            this.chineseFont = font;
        }

        @Override
        public void onEndPage(PdfWriter writer, Document document) {
            PdfPTable pdfPTable = new PdfPTable(1);
            pdfPTable.setTotalWidth(520f);
            setTableFooter(pdfPTable, writer, document);
            //把页脚表格定位
            pdfPTable.writeSelectedRows(0, -1, 36, 25, writer.getDirectContent());
        }
        /**
         * 页脚是文字
         * @param writer
         */
        public  void setTableFooter(PdfPTable pdfPTable, PdfWriter writer, Document document) {
            PdfPCell cell = new PdfPCell();
            cell.setBorderWidthTop(1);
            cell.setBorderWidthLeft(0);
            cell.setBorderWidthRight(0);
            cell.setBorderWidthBottom(0);
            // PdfContentByte cb = writer.getDirectContent().beginText();
            int pageNumber = writer.getPageNumber();
            String string = "Copyright 2012-2019 Jousing Medical Co.,Ltd. 久心医疗版权所有      网址:www.jousing.com     电话:021-62995391   第" + pageNumber + "页";
            Paragraph p = new Paragraph(string, chineseFont);
            cell.setPaddingLeft(0f);
            cell.setPaddingTop(0f);
            cell.addElement(p);
            pdfPTable.addCell(cell);
        }

        public void onCloseDocument(PdfWriter writer, Document document) {
            // setTableFooter(writer, document);
        }
    }
}

3、html模板

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family: STSongStd-Light;
            font-size: 18px;
            line-height: 1.42857143;
            color: #000000;
            background-color: rgba(255, 255, 255, 0);
            border: 1px solid red;
            /*background-color:#c8edcc;*/
        }
        *{box-sizing: border-box;}
        a {text-decoration:none}

        .table-bordered {
            border: 1px solid #000000;
        }

        .table {
            width: 100%;
            max-width: 100%;
            /* margin-bottom: 18px; */
            table-layout: fixed;
        }

        table {
            background-color: transparent;
            border-collapse: collapse;
            border-spacing: 1px;
        }

        .table-condensed > thead > tr > th {
            padding-top: 10px;
            padding-bottom: 8px;
            font-weight: bold;
        }
        .table > thead:first-child > tr:first-child > td {
            border-top: 0;
        }

        .table-condensed > tbody > tr > td, .table-condensed > tfoot > tr > td {
            padding: 5px 8px;
        }

        /*#secondPage tr td {
            padding: 10px 8px;
        }*/

        .table > thead > tr > th {
            border-bottom-width: 2px;
            font-weight: 700;
        }

        .table-bordered > thead > tr > th, .table-bordered > tbody > tr > th, .table-bordered > tfoot > tr > th, .table-bordered > thead > tr > td, .table-bordered > tbody > tr > td, .table-bordered > tfoot > tr > td {
           /* border: 1px solid #dddddd;*/
            border: 1px solid #000000;
        }

        thead {
            display: table-header-group;
            vertical-align: middle;
            border-color: inherit;
        }

        tr {
            display: table-row;
            vertical-align: inherit;
            border-color: inherit;
        }

        td {
            padding-top: 1px;
            padding-bottom: 2px;
        }

        .text-center {
            text-align: center;
        }
        .text-left {
            text-align: left;
        }

        .table > tbody > tr > td {
            font-weight: 400;
            vertical-align: middle;
            word-wrap: break-word;
        }

        .label-warning {
            color: #f6c163;
        }

        .label-success {
            color: #37b358;
        }

        .label-primary {
            color: #5f99f5;
        }

        .label-default {
            color: #ffffff;
        }

        .attribute{
            width:35%;
            font-size:16px;
            font-weight: 700;
            color:#000000;
            font-weight: bold;
            text-align: left;
            /*padding: 4px 2px;*/
            /*border: 1px solid #dddddd;*/
            /*border: 1px solid #000000;*/
        }

        .attributeValue{
            width:65%;
            /*font-weight: bold;*/
            text-align: center;
            font-size:16px;
            color: #000000;
            /*padding: 4px 1px;*/
        }

        .font28{
            font-size: 28px;
            font-weight: 900;
        }

        .font24{
            font-size: 24px;
            font-weight: 600;
        }

        .font20 {
            font-size:20px;
            font-weight: 700;
        }

        .font18 {
            font-size: 18px;
            font-weight: 700;
        }

        .font14 {
            font-size: 14px;
            font-weight: 700;
        }

        .verticalPadding10{
            padding-top:10px;
            padding-bottom: 10px;
        }

        .verticalPadding5{
            padding-top:5px;
            padding-bottom: 5px;
        }

        .PaddingLeft10 {
            padding-left: 10px;
        }

        .titleBackgroudColor{
            /*background-color: #707070;*/
            background-color: #eeeeee;
        }

        .textUnderLine {
            text-decoration:underline
        }

        .topBorderColorBlack{
            border-top-color: #000000;
        }
        .tableBorder {
            border: 1px solid #000000;
        }

        .tdBorderBottom {
            border-bottom: 1px solid #000000;
        }

        #secendPageTable td {
            border-bottom: 1px solid #000000;
            border-right: 1px solid #000000;
        }

        #secendPageTable th {
            border-right: 1px solid #000000;
        }

        .borderRightNone {
            border-right: 0px;
        }
        .backgroudpurple {
            background-color: #3f1d5a;
        }
        .fontColorWhite {
            color: #FFFFFF;
        }

        .fontColorOrange {
            color: #f3642c;
        }

        .fontColorPurple {
            color: #272063;
        }

        .fontColorpurpled {
            color:#3f1d5a;
        }

        .table-border,.table-border tr th, .table-border tr td { border:1px solid #000000; }
        .table-border { border-collapse: collapse;}
        .table-border tr td {padding-left: 5px;padding-top:5px;padding-bottom: 5px;}
        .table-titled{
            font-size: 18px;
            font-weight: 700;
            color:#000000;
        }
    </style>
</head>
<body>

<div style="height: 100%;width: 100%;">
    <table style="width: 100%">
        <tr>
            <td height="300"></td>
        </tr>

        <tr>
            <td class="font28 verticalPadding10 text-center">${institution.name}</td>
        </tr>

        <tr>
            <td  class="font28 verticalPadding10 text-center">AED设备巡检报告</td>
        </tr>

        <tr>
            <td style="height: 320px"></td>
        </tr>

        <tr class="backgroudpurple">
            <td class="font18 fontColorWhite verticalPadding10 text-center">报告出具方:久心医疗</td>
        </tr>

        <tr class="backgroudpurple">
            <td class="font18 fontColorWhite verticalPadding10 text-center">出具时间:${year}年${month}月${day}日</td>
        </tr>

        <tr class="backgroudpurple">

            <td class="font18 fontColorWhite verticalPadding10 text-center">
                频率:
                  <#if period == "DAILY"> 每天</#if>
            </td>
        </tr>
    </table>

    <table style="width: 100%; margin-top: 50px;">
        <tr>
            <td><img src="${bottomPath}"/></td>
        </tr>
    </table>
</div>

<div style="height: 100%;width: 100%;">
    <P class="font28 fontColorOrange">巡检概要</P>

    <P class="font20 fontColorPurple">客户信息</P>
    <table class="table-border" style="width: 100%">
        <tr>
            <td class="attribute verticalPadding5" >机构名称</td>
            <td class="attributeValue verticalPadding5">${institution.name}</td>
        </tr>
        <tr>
            <td class="attribute verticalPadding5" >巡检区域</td>
            <#if institution.address??>
            <td class="attributeValue verticalPadding5">${institution.address!}</td>
            </#if>
        </tr>
        <tr>
            <td class="attribute verticalPadding5" >联系人</td>
            <td class="attributeValue verticalPadding5">${institution.contact}</td>
        </tr>
        <tr>
            <td class="attribute verticalPadding5" >联系方式</td>
            <td class="attributeValue verticalPadding5">${institution.phoneNumber}</td>
        </tr>
    </table>

    <P class="font20 fontColorPurple">巡检结果</P>
    <table class="table-border" style="width: 100%">
    <tr class="table-titled">
        <td style="width: 14% ">设备ID</td>
        <td style="width: 22%">布防地点</td>
        <td style="width: 20%">设备状态</td>
        <td style="width: 22%">是否有抢救记录</td>
    </tr>

    <#list deviceList as device>
        <tr style="height: 80px">
            <td>${device.serialNumber}</td>
            <td>${device.address}</td>

            <td>
                <#if device.deviceRunningState == "ABNORMAL">
                    <span style="color:#df3033;font-weight: 700">异常</span> <#if device.stateDetail??>(${device.stateDetail})</#if>
                </#if>
                <#if device.deviceRunningState == "NORMAL">
                    <span style="color:#29c287;font-weight: 700">正常</span>
                </#if>

                <#if device.deviceRunningState == "WARNING">
                    <span style="color:#df3033;font-weight: 700">预警</span><#if device.stateDetail??>(${device.stateDetail})</#if>
                </#if>
                <#if device.deviceRunningState == "UNKNOWN">
                     <span style="color:#df3033;font-weight: 700">未知</span>
                </#if>
            </td>
            <td>
                <#if device.hasRescueData ==true>
                     <span style="color:#df3033;font-weight: 700">有</span>
                </#if>
                <#if device.hasRescueData ==false>
                     <span style="color:#29c287;font-weight: 700">无</span>
                </#if>

            </td>
        </tr>
    </#list>

    </table>

    <P class="font28 fontColorOrange">巡检详情</P>
    <P class="font20 fontColorPurple">使用记录</P>
    <#list needConcernedRecordAlarmList as needConcernedRecordAlarm>
    <table class="table-border" style="width: 100%;margin-bottom: 20px">
        <tr class="table-titled">
            <td style="width: 15% ">设备ID</td>
            <td style="width: 85%">布防地点</td>
        </tr>

        <tr>
            <td>${needConcernedRecordAlarm.serialNumber}</td>
            <td>${needConcernedRecordAlarm.address}</td>
        </tr>
        <tr class="table-titled">
            <td colspan="2">记录详情</td>
        </tr>
        <#list needConcernedRecordAlarm.eventList as alarmRecord>
        <tr>
            <td colspan="2" style="font-size: 14px;">${alarmRecord.occurDate} ${alarmRecord.content}</td>
        </tr>
        </#list>
    </table>
    </#list>

    <P class="font28 fontColorOrange">管理人员信息</P>
    <table class="table-border" style="width: 100%">
        <tr class="table-titled">
            <td style="width: 20% ">管理员类型</td>
            <td style="width: 25%">姓名</td>
            <td style="width: 25%">手机号</td>
            <td style="width: 30%">管理设备</td>
        </tr>
        <#list institutionAdminList as institutionAdmin>
        <tr style="">
            <td>组织管理员</td>
            <td>${institutionAdmin.name}</td>
            <td>${institutionAdmin.phoneNumber}</td>
            <td>全部</td>
        </tr>
        </#list>

        <#list deviceAdminList as deviceAdmin>
        <tr style="">
            <td>设备管理员</td>
            <td>${deviceAdmin.admin.name}</td>
            <td>${deviceAdmin.admin.phoneNumber}</td>
            <td>${deviceAdmin.deviceStr}</td>
        </tr>
        </#list>
    </table>

    <#if deviceBatteryStateAbnormal != 0 || deviceElectrodesToFail != 0 || deviceAbnormal != 0 || deviceIsOutSide != 0>
    <P class="font28 fontColorOrange">处理建议</P>

    <table style="width: 100%; border: 1px solid #000000;" class="font18">
        <#if deviceBatteryStateAbnormal != 0>
        <tr>
            <td class="verticalPadding5">xxxxxxxx。</td>
        </tr>
        </#if>
        <#if deviceElectrodesToFail != 0>
        <tr>
            <td class="verticalPadding5">xxxxxxxx。</td>
        </tr>
        </#if>

        <#if deviceAbnormal != 0>
        <tr>
            <td class="verticalPadding5">xxxxxxxx</td>
        </tr>
        </#if>

        <#if deviceIsOutSide != 0>
        <tr>
            <td class="verticalPadding5">xxxxx</td>
        </tr>
        </#if>
    </table>
    </#if>
</div>

<div style="height: 100%;width: 100%;">
    <P class="font28 fontColorOrange">管理系统</P>
    <P class="font18">登录平台查看更多设备信息</P>
    <table style="width: 100%;border: 1px solid #000000;" >
        <tr>
            <td class="font18 fontColorPurple verticalPadding10 text-center" style="border-right: 1px solid #000000;width: 50%">xxx管理系统</td>
            <td class="font18 fontColorPurple verticalPadding10 text-center" style="width: 50%">微信小程序</td>
        </tr>
        <tr>
            <td class="font18  verticalPadding10 text-center" style="border-right: 1px solid #000000;"><img src="${websitePath}" width="250px" height="70px"/></td>
            <td class="font18  verticalPadding10 text-center"><img src="${miniProgramQRCodePath}" width="130px" height="130px"/></td>
        </tr>
    </table>

    <div style="height: 280px"></div>
    <P class="font28 fontColorOrange">联系我们</P>
    <table style="width: 100%;padding-left: 5px" >
    <tr>
        <td class="font18 verticalPadding10 text-left" >电话:</td>
        <td class="verticalPadding10 text-left" >${telephone}</td>
        <td class="verticalPadding10 text-left" rowspan="4"><img src="${aedPath}" width="130px" height="130px"/></td>
    </tr>
    <tr>
        <td class="font18 verticalPadding10 text-left" >邮箱:</td>
        <td class="verticalPadding10 text-left" >${telephone}</td>
    </tr>
    <tr>
        <td class="font18 verticalPadding10 text-left" >苏州总部:</td>
        <td class="verticalPadding10 text-left" >${addressSuzhou}</td>
    </tr>
    <tr>
        <td class="font18 verticalPadding10 text-left" >上海分部:</td>
        <td class="verticalPadding10 text-left" >${addressShanghai}</td>
    </tr>
    </table>

    <table style="width: 100%;margin-top: 20px">
        <tr class="backgroudpurple">
            <td class="font18 fontColorWhite verticalPadding10 text-center" style="height: 100px;">xxxxxxxxx</td>
        </tr>
    </table>
</div>

</body>
</html>

 4、数据封装

 public Map<String, Object> prapareDataForCustomer(String rootPath, List<DeviceReportVM> deviceList, InstitutionReportVM institution) {
        Map<String, Object> data = new HashMap();
        LocalDateTime localDateTime = LocalDateTime.now();
        data.put("year", String.valueOf(localDateTime.getYear()));
        data.put("month", String.valueOf(localDateTime.getMonthValue()));
        data.put("day", String.valueOf(localDateTime.getDayOfMonth()));

        data.put("period", getCustomerReportPeriod(institution.getId()));


        data.put("deviceList", deviceList);
        data.put("institution", institution);

        setDeviceProblemCount(deviceList, data);
        //需关心事件列表
        data.put("needConcernedRecordAlarmList", getEntityEvent(deviceList));
        data.put("institutionAdminList", getInstitutionAdminList(institution.getId())); //机构管理员列表
        data.put("deviceAdminList", getDeviceAdminList(institution.getId())); //设备管理员


        data.put("logoPath", rootPath + "report/logo.png");
        data.put("miniProgramQRCodePath", rootPath + "report/miniProgramQRCode.png"); //微信小程序二维码图片地址
        data.put("websitePath", rootPath + "report/website.png"); //平台地址图片地址
        data.put("aedPath", rootPath + "report/aed.png"); //aed图片地址
        data.put("bottomPath", rootPath + "report/bottom.png"); //首页底部图片地址
        data.put("address", "xxxxx");
        data.put("addressSuzhou", "xxxxx");
        data.put("addressShanghai", "xxxxxx");
        data.put("telephone", "xxxxx");
        data.put("email", "xxxxx");
        data.put("website", "xxxxx");
        return data;
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

工程师小A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值