Velocity模板与itextpdf联合生成pdf

news2024/11/17 8:20:28

pom

			<!-- velocity模板引擎  -->
			<dependency>
				<groupId>org.apache.velocity</groupId>
				<artifactId>velocity-engine-core</artifactId>
				<version>2.3</version>
			</dependency>
		<!-- itext7html转pdf  -->
			<dependency>
				<groupId>com.itextpdf</groupId>
				<artifactId>html2pdf</artifactId>
				<version>3.0.2</version>
			</dependency>
			<!-- 中文字体支持 -->
			<dependency>
				<groupId>com.itextpdf</groupId>
				<artifactId>font-asian</artifactId>
				<version>7.1.13</version>
			</dependency>

PatRefundStatisticsVo 变量实体

@Data
@Accessors(chain = true)
@Builder
public class PatRefundPdf {

    private String userName;

    private String createTime;

    private String pdfTime;

    private HospitalRefundStatisticsVo refund;

    private List<PatRefundStatisticsVo> refundInfoList;

}

fileUtils

/***
 *
 * @author qb
 * @since 2023/5/22 11:33
 * @version 1.0
 */
public class FileUtils {



    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
    {
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
        String percentEncodedFileName = percentEncode(realFileName);

        StringBuilder contentDispositionValue = new StringBuilder();
        contentDispositionValue.append("attachment; filename=")
                .append(percentEncodedFileName)
                .append(";")
                .append("filename*=")
                .append("utf-8''")
                .append(percentEncodedFileName);

        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
        response.setHeader("Content-disposition", contentDispositionValue.toString());
        response.setHeader("download-filename", percentEncodedFileName);
    }


    /**
     * 百分号编码工具方法
     *
     * @param s 需要百分号编码的字符串
     * @return 百分号编码后的字符串
     */
    public static String percentEncode(String s) throws UnsupportedEncodingException
    {
        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
        return encode.replaceAll("\\+", "%20");
    }

}

VelocityUtils


public class VelocityUtils {


    /**
     * html转pdf
     */
    public static void convertToPdf(String fileName, StringWriter stringWriter, HttpServletResponse response) throws IOException {
        // 设置请求流
        FileUtils.setAttachmentResponseHeader(response,fileName);
        // 将获取到的velocity流放图输入流中
        InputStream inputStream = new ByteArrayInputStream(stringWriter.toString().getBytes(Charset.defaultCharset()));
        // 构建请求输出流
        PdfWriter pdfWriter = new PdfWriter(response.getOutputStream());
        // 构建pdf元素
        PdfDocument pdfDocument = new PdfDocument(pdfWriter);
        //设置为A4大小
        pdfDocument.setDefaultPageSize(PageSize.A4);
        //添加中文字体支持
        ConverterProperties properties = new ConverterProperties();
        FontProvider fontProvider = new FontProvider();
        PdfFont sysFont = PdfFontFactory.createFont("STSongStd-Light", "UniGB-UCS2-H", false);
        fontProvider.addFont(sysFont.getFontProgram(), "UniGB-UCS2-H");
        properties.setFontProvider(fontProvider);
        HtmlConverter.convertToPdf(inputStream, pdfDocument, properties);
        pdfWriter.close();
        pdfDocument.close();
    }

    /**
     * 获取html流
     * @param context   velocity变量
     * @param vmPath    路径
     * @return  流
     * @throws IOException /
     */
    public static StringWriter genHtml(VelocityContext context,String vmPath) throws IOException {
        VelocityUtils.initVelocity();
        Template tpl = Velocity.getTemplate(vmPath, "UTF-8");
        StringWriter sw = new StringWriter();
        // 5、合并数据到模板
        tpl.merge(context, sw);
        // 6、释放资源
        sw.close();
        return sw;
    }

    /**
     * 初始化vm方法
     */
    public static void initVelocity()
    {
        Properties p = new Properties();
        try
        {
            // 加载classpath目录下的vm文件
            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
            // 定义字符集
            p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
            // 初始化Velocity引擎,指定配置Properties
            Velocity.init(p);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

}

.vm 模板

<html>
<head>
    <meta htp-equiv="Content-Type" content="text/html;charset=UTF-8"/>
</head>
<style>
    .top{
        padding: 10px;
        border-bottom: 1px solid #e8e8e8;
    }
    .aColor > a {
        color: rgba(0, 0, 0, 0.65);
    }
    .tableCla{
        width: 100%;
        border: 1px solid rgba(0, 0, 0, 0.65);
        border-collapse: collapse;
    }
    .theadCla > tr > th{
        padding: 10px;
        color: rgba(0, 0, 0, 0.85);
        border:  1px solid #e8e8e8;
        background: #fafafa;
        font-weight: normal;
    }
    tbody > tr > td{
        text-align: center;
        font-weight: normal;
        color:  rgba(0, 0, 0, 0.65);
        padding: 15px 10px;
        border: 1px solid #e8e8e8;
    }
    .border-s{
        background: none;
        border-color: #e8e8e8;
        border-style: dashed;
        border-width: 1px 0 0;
        display: block;
        clear: both;
        width: 100%;
        min-width: 100%;
        height: 1px;
        margin: 24px 0;
    }
</style>
<body>
<div>
    <div class="top">
        线上交易明细
    </div>
    <div style="display: block;text-align: center">
        <h2>线上交易明细单</h2>
    </div>
    <div class="aColor" style="margin-bottom: 30px">
        <a style="margin-right: 10px">操作人:${pdf.userName}</a>
        <a>操作时间:${pdf.createTime}</a>
    </div>
    <table class="tableCla" style="margin-bottom: 20px">
        <thead class="theadCla">
            <tr>
                <th>日期</th>
                <th>操作员</th>
                <th>数量</th>
                <th>退款总额</th>
                <th>支付宝</th>
                <th>微信</th>
            </tr>
        </thead>
        <tbody>
            <tr >
                <td>$!pdf.refund.time</td>
                <td>$!pdf.refund.createBy</td>
                <td>$!pdf.refund.count</td>
                <td>$!pdf.refund.refundFee</td>
                <td>$!pdf.refund.aliPayFee</td>
                <td>$!pdf.refund.weChatFee</td>
            </tr>
        </tbody>
    </table>
    <span class="border-s"/>
    <table class="tableCla" style="margin-top: 20px;margin-bottom: 20px">
        <thead class="theadCla">
            <tr >
                <th>住院号</th>
                <th>姓名</th>
                <th>退款金额</th>
                <th>退款方式</th>
                <th>退款时间</th>
            </tr>
        </thead>
        <tbody>
            #foreach ($item in $pdf.refundInfoList)
            <tr >
                <td>$!item.cardNo</td>
                <td>$!item.patName</td>
                <td>$!item.refundFee</td>
                <td>$!item.payType</td>
                <td>$!item.createTime</td>
            </tr>
            #end
        </tbody>
    </table>
    <span class="border-s"/>
    <div class="aColor" style="margin-top: 20px">
        <a style="margin-right: 10px">打印日期:${pdf.pdfTime}</a>
        <a>操作员签字:</a>
    </div>
</div>
</body>
</html>

使用

    public void genPdf(String createBy, String createTime, HttpServletResponse response) throws IOException {

        HospitalRefundStatisticsVo hospitalRefundStatisticsVo = baseMapper.hospitalRefundStatisticsByUserAndTime(createBy, createTime);
        PatRefundPdf pdf = PatRefundPdf.builder()
                .createTime(hospitalRefundStatisticsVo.getTime())
                .userName(hospitalRefundStatisticsVo.getUserName())
                .pdfTime(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
                .refundInfoList(baseMapper.patRefundStatistics(createBy, createTime))
                .refund(hospitalRefundStatisticsVo)
                .build();
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("pdf",pdf);
        VelocityUtils.convertToPdf("明细",VelocityUtils.genHtml(velocityContext,"vm/refund.vm"),response);
    }

前台请求

export function exportConsultFile (data) {
  return axios.post('/bill/info/api/order/patRefundPdf', data, { responseType: 'blob' })
}

exportFile () {
      this.exportTitle = '导出中...'
      exportConsultFile({ createBy: this.info.createBy, createTime: this.info.time }).then(res => {
        const url = window.URL.createObjectURL(new Blob([ res ]))
        const link = document.createElement('a')
        link.style.display = 'none'
        link.href = url
        const fileName = '退款记录统计.pdf'
        link.setAttribute('download', fileName)
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
        this.$message.success('下载成功')
      }).catch(err => {
          console.log(err)
        this.$message.error('导出失败!')
      }).finally(() => {
        this.exportTitle = '导出为PDF'
      })
    }

效果图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/555049.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode刷题(ACM模式)-01数组

参考引用&#xff1a;代码随想录 注&#xff1a;每道 LeetCode 题目都使用 ACM 代码模式&#xff0c;可直接在本地运行&#xff0c;蓝色字体为题目超链接 0. 数组理论基础 数组&#xff08;array&#xff09;是存放在连续内存空间上的相同类型数据的集合&#xff0c;是一种复合…

【哪些人不适合学习云计算?看看有没有你!】

云计算作为是互联网技术革命的重要一员&#xff0c;也是区别于一般IT职业的。作为高级技工&#xff0c;不是谁都能学会&#xff0c;也不是谁都适合这个技术。优秀的云计算工程师能让技术成为炫耀的资本&#xff0c;玩得神乎其技&#xff0c;引得众人追捧。我想这也是大部分热爱…

Cam APP-HAL流程追踪之demo梳理

一、基础知识 1、Google官网的Cam流程如下图1 2、Cam的预览、拍照、录像是分开的 Cam的预览、拍照、录像是各自独立的-换句话说可以不开启预览拍照或者录像–后面代码会详细介绍&#xff1b;市场上的成品Cam应用&#xff0c;打开Cam后直接打开了预览&#xff0c;然后可以拍照…

【数据结构】线性表之栈、队列

前言 前面两篇文章讲述了关于线性表中的顺序表与链表&#xff0c;这篇文章继续讲述线性表中的栈和队列。 这里讲述的两种线性表与前面的线性表不同&#xff0c;只允许在一端入数据&#xff0c;一段出数据&#xff0c;详细内容请看下面的文章。 顺序表与链表两篇文章的链接&…

最新社区论坛小程序源码 含流量主功能+前后端+部署搭建教程

分享一个社区论坛小程序源码&#xff0c;含完整前后端代码包和详细的部署搭建教程&#xff0c;做地方运营很适合&#xff0c;集成了流量主功能&#xff0c;一键轻松开启。 系统功能一览&#xff1a; 广场管理&#xff1a;广场列表&#xff0c;圈子列表&#xff0c;圈子审核 帖…

CE作业(4)

一、准备前提 服务端 客户端 ; 关闭防火墙systemctl stop firewalld 关闭selinux setenforce 0 提供DNS服务的软件叫bind&#xff0c;服务名是named 一、正向解析&#xff1a; 1.装包 yum install bind -y 2.配置服务 vim /etc/named.conf #监听53号端口 #访问的是本…

​数据库原理及应用上机(实验三 SQL数据查询)

✨作者&#xff1a;命运之光 ✨专栏&#xff1a;数据库原理及应用上机实验 ​ 目录 ✨一、实验目的和要求 ✨二、实验内容及步骤 ✨三、实验结果 ✨四、附加练习 ✨五、实验总结 &#x1f353;&#x1f353;前言&#xff1a; 数据库原理及应用上机实验报告的一个简单整理…

用别人的钱创咖啡的业,戴威与陆正耀殊途同归?

文 | 新熔财经 作者 | 和花 近四年来&#xff0c;ofo退押一事没有出现任何明显的转机&#xff0c;但ofo创始人戴威却已经在海外大张旗鼓地开启了名为About Time Coffee的新创业项目。 当“ofo创始人戴威再次创业”的消息登上微博热搜&#xff0c;收获的几乎都是“还钱”的征…

字符串按规则生成字典

带数字的字符串以数字为key倒序生成字典&#xff0c;字符串列表按其元素索引为key倒序生成字典。 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是基础那么简…

实验室云检验信息系统(云LIS源码)

一、区域云LIS系统概述&#xff1a; 区域云LIS平台源码&#xff0c;系统完全采用B/S架构模式&#xff0c;扩展性强。整个系统的运行基于WEB层面&#xff0c;只需要在对应的工作台安装一个浏览器软件有外网即可访问。 云LIS系统为实验室服务对象提供检验申请、采集标本、结果查…

【IDEA使用码云教程】

IDEA使用码云教程 一、下载、安装git二、配置Gitee插件三、克隆项目四、上传项目五、推送项目六、更新项目 一、下载、安装git 1.打开git官网&#xff0c;选择你的操作系统 官网下载地址&#xff1a;https://git-scm.com/downloads 2.根据你的系统位数选择相应的版本下载 系统…

frp+nginx+xposed搭建xp模块集群

frpcnginxxposed搭建xp模块集群 前言实现逻辑配置内网穿透实现负载均衡 前言 为了能够稳定的采集一些app的详情页数据&#xff0c;就得借助xposed&#xff0c;xposed跟NanoHTTPD配合使用就可以在手机端开启接口服务&#xff0c;直接调用手机端的接口就能获取我们想要的数据&am…

【机器学习】线性模型

文章目录 第三章&#xff1a;线性模型一、线性回归模型1.1、线性回归模型1.2、求解线性回归模型&#xff08;时刻要分清维度&#xff09;1.3、多输出线性回归模型 二、线性分类模型2.1、判别函数2.2、概率判别模型2.3、概率生成模型 第三章&#xff1a;线性模型 一、线性回归模…

怎么把视频压缩到500m以下?

如何把视频压缩到500m以下&#xff1f;视频文件通常是非常大的&#xff0c;特别是高清视频或超高清视频&#xff0c;因此压缩可以帮助将视频文件大小减小&#xff0c;在有限的存储空间中存储更多的视频文件。较大的视频文件在上传和下载时需要较长时间&#xff0c;而压缩视频文…

Flink学习——Flink中的时间语义和窗口

一、时间语义 1.1 为什么会出现时间语义&#xff1f; flink是一个大数据处理引擎&#xff0c;它的最大特点就是分布式。每一个机器都有自己的时间&#xff0c;那么集群当中的时间应该以什么为准呢&#xff1f; 比如&#xff1a;我们希望统计8-9点的数据时&#xff0c;对并行任…

使用RSD从DEM数据创建用户高程数据层

李国春 SRTM90和Aster DEM的V2/V3是比较常用的免费共享高程数据。用户下载好以后应用到自己的项目时&#xff0c;经常会需要进行拼接合成和投影重采样等。RSD提供了一种创建自己项目的高程数据的方法。 一. 高程图像生成方法 在自己的项目中&#xff0c;选择图1的菜单。 图1…

使用LabVIEW AI视觉工具包快速实现SIFT特征检测(含源码)

‍‍&#x1f3e1;博客主页&#xff1a; virobotics的CSDN博客&#xff1a;LabVIEW深度学习、人工智能博主 &#x1f384;所属专栏&#xff1a;『LabVIEW深度学习实战』 &#x1f37b;上期文章&#xff1a; 使用LabVIEW AI视觉工具包快速实现霍夫圆和霍夫直线检测&#xff08;含…

Jmeter事务控制器聚合报告

Jmeter 事务控制器。 在Jmeter中&#xff0c;默认一个取样器就是一个事务事务控制器控制其子集取样器&#xff0c;合并为一个事务 添加&#xff1a;逻辑控制器/Logic Controller -> 事务控制器/Transaction Controller TPS: 服务器每秒处理的事务数在事务控制器下添加多个…

海康威视iVMS综合安防系统任意文件上传漏洞复现(0day)

0x01 产品简介 海康威视iVMS集中监控应用管理平台&#xff0c;是以安全防范业务应用为导向&#xff0c;以视频图像应用为基础手段&#xff0c;综合视频监控、联网报警、智能分析、运维管理等多种安全防范应用系统&#xff0c;构建的多业务应用综合管理平台。 0x02 漏洞概述 海…

利用CX-ONE搭建omron PLC仿真环境

目录 1 安装参考 2 CX-Simulator 2.1 打开软件 2.2 选择PLC配置文件存放位置 2.3 选择PLC类型 2.4 PLC Unit全部选择 2.5 设置FINS通讯 2.6 设置串口通讯 2.7 建立连接 3 CX-Programmer 3.1 新建工程 3.2 设置PLC型号 3.3 设置网络类型 3.4 设置串口通讯 3.5 设…