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
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.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'
})
}
效果图