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
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);
}
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 {
public static void convertToPdf(String fileName, StringWriter stringWriter, HttpServletResponse response) throws IOException {
FileUtils.setAttachmentResponseHeader(response,fileName);
InputStream inputStream = new ByteArrayInputStream(stringWriter.toString().getBytes(Charset.defaultCharset()));
PdfWriter pdfWriter = new PdfWriter(response.getOutputStream());
PdfDocument pdfDocument = new PdfDocument(pdfWriter);
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();
}
public static StringWriter genHtml(VelocityContext context,String vmPath) throws IOException {
VelocityUtils.initVelocity();
Template tpl = Velocity.getTemplate(vmPath, "UTF-8");
StringWriter sw = new StringWriter();
tpl.merge(context, sw);
sw.close();
return sw;
}
public static void initVelocity()
{
Properties p = new Properties();
try
{
p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
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'
})
}
效果图