Velocity模板与itextpdf联合生成pdf

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'
      })
    }

效果图

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43861630/article/details/130807152