Velocity模板与itextpdf联合生成pdf

pom

			
			
				org.apache.velocity
				velocity-engine-core
				2.3
			
		
			
				com.itextpdf
				html2pdf
				3.0.2
			
			
			
				com.itextpdf
				font-asian
				7.1.13
			

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.timetd>
                <td>$!pdf.refund.createBytd>
                <td>$!pdf.refund.counttd>
                <td>$!pdf.refund.refundFeetd>
                <td>$!pdf.refund.aliPayFeetd>
                <td>$!pdf.refund.weChatFeetd>
            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.cardNotd>
                <td>$!item.patNametd>
                <td>$!item.refundFeetd>
                <td>$!item.payTypetd>
                <td>$!item.createTimetd>
            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'
      })
    }

效果图

Velocity模板与itextpdf联合生成pdf_第1张图片

你可能感兴趣的:(java排坑之路,pdf,java,servlet)