pom jar
<!-- freemarker 读取html模板文件 -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<!-- xml 将html模板文件转换成pdf -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.0.9</version>
</dependency>
注意该版本和项目版本问题,
工具类
package com.lianzhan.report.config;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.stereotype.Service;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.util.Locale;
import java.util.Map;
/**
* @author yfy
* @create 2021-08-25-16-17
*/
public class PDFTemplateUtil {
/**
* 通过模板导出pdf文件
* @param data 数据
* @param templateFileName 模板文件名
* @throws Exception
*/
public static ByteArrayOutputStream createPDF(Map<String,Object> data, String templateFileName) throws Exception {
// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setClassForTemplateLoading(PDFTemplateUtil.class,"/template");
ITextRenderer renderer = new ITextRenderer();
OutputStream out = new ByteArrayOutputStream();
try {
// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
renderer.getFontResolver().addFont("/template/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, "UTF-8");
// 获取模板文件
Template template = cfg.getTemplate(templateFileName, "UTF-8");
StringWriter writer = new StringWriter();
// 将数据输出到html中
template.process(data, writer);
writer.flush();
String html = writer.toString();
// 把html代码传入渲染器中
renderer.setDocumentFromString(html);
// 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="images/xh.jpg"/>
// String url = PDFTemplateUtil.class.getClassLoader().getResource("images").toURI().toString();
// renderer.getSharedContext().setBaseURL(url);
renderer.layout();
renderer.createPDF(out, false);
renderer.finishPDF();
out.flush();
return (ByteArrayOutputStream)out;
} finally {
if(out != null){
out.close();
}
}
}
}
需要下载中文字体包:
simsun.ttc
ftl模板
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
font-family: SimSun;
font-size: 10px;
}
section{
display:block;
margin: 20px 10px;
}
.title{
text-align: center;
}
.preface p{
line-height: 30px;
}
.preface p.content{
text-indent: 2em;
}
section > table{
table-layout: fixed;
width: 100%;
margin: 20px 0px;
text-align:center;
word-wrap:break-word;
}
section table td{
padding:5px 0px;
}
</style>
</head>
<body>
<!-- �й��ƴ�һԺ�������������غ��ڷ������ͼ�� -->
<section class="title">
${title}
</section>
<!-- �������� -->
<section class="detail">
<h4>${DepartmentsRanking}</h4>
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${DepartmentsRanking1}</td>
<td width="15%">${DepartmentsRanking2}</td>
<td width="12%">${DepartmentsRanking3}</td>
</tr>
<#list DepartmentsRankingList as ad>
<tr>
<td>${ad_index+1}</td>
<td>${ad.fromDepName!}</td>
<td>${ad.count!}</td>
</tr>
<#if (ad_index>50) >
<#break>
</#if>
</#list>
</table>
</section>
<!-- ʵʱ������Ϣ -->
<section class="detail">
<h4>${transportTime}</h4>
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${transportTime1}</td>
<td width="15%">${transportTime12}</td>
<td width="12%">${transportTime13}</td>
<td width="12%">${transportTime14}</td>
</tr>
<#list transportTimeList as ad>
<tr>
<td>${ad_index+1}</td>
<td>${ad.allotUsers!}</td>
<td>${ad.remark!}</td>
<td>${ad.createTime ? string('yyyy-MM-dd HH:mm:ss')}</td>
</tr>
<#if (ad_index>50) >
<#break>
</#if>
</#list>
</table>
</section>
<!-- ����ʱ�������� -->
<section class="detail">
<h4>${TimeSpecific}</h4>
</section>
<!-- �������������(�����)�� -->
<section class="detail">
<h4>${Alltransport}</h4><!-- �������걾�±���-->
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${Alltransport1}</td>
<td width="15%">${Alltransport2}</td>
<td width="12%">${Alltransport3}</td>
<td width="15%">${Alltransport4}</td>
<td width="10%">${Alltransport5}</td>
</tr>
<#list AlltransportList as ad>
<tr>
<td>${ad.typeName!}</td>
<td>${ad.fromDepName!}</td>
<td>${ad.remark!}</td>
<td>${ad.createTime ? string('yyyy-MM-dd HH:mm:ss')}</td>
<td>${ad.orderStatusName!}</td>
</tr>
<#if (ad_index>50) >
<#break>
</#if>
</#list>
</table>
</section>
<!-- �������������� -->
<section class="detail">
<h4>${yearTransport}</h4><!-- -->
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${yearTransport1}</td>
<td width="15%">${yearTransport2}</td>
<td width="12%">${yearTransport3}</td>
<td width="12%">${yearTransport4}</td>
</tr>
<#list yearTransportList as ad>
<tr>
<td>${ad.jieDanNum!}</td>
<td>${ad.qiangDanNum!}</td>
<td>${ad.ordersshippedcomplete!}</td>
<td>${ad.monthday!}</td>
</tr>
<#if (ad_index>50) >
<#break>
</#if>
</#list>
</table>
</section>
<!-- ������Ա�������� -->
<section class="detail">
<h4>${monthEmptyRanking}</h4>
<#if monthEmptyRankingList?? >
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${monthEmptyRanking1}</td>
<td width="15%">${monthEmptyRanking2}</td>
<td width="12%">${monthEmptyRanking3}</td>
<td width="12%">${monthEmptyRanking4}</td>
</tr>
<#list monthEmptyRankingList as ad>
<tr>
<td>${ad_index+1}</td>
<td>${ad.allotUsers!}</td>
<td>${ad.count!}</td>
<td>${ad.orderScore!}</td>
</tr>
</#list>
</table>
<#else >
</#if >
</section>
<!-- ����������ͳ�ơ� -->
<section class="detail">
<h4>${wayStatistics}</h4>
<table border="1" cellspacing="0" cellpadding="0">
<tr>
<td width="10%">${wayStatistics1}</td>
<td width="15%">${wayStatistics2}</td>
<td width="12%">${wayStatistics3}</td>
</tr>
<#list wayStatisticsList as ad>
<tr>
<td>${ad_index+1}</td>
<td>${ad.typeName!}</td>
<td>${ad.count!}</td>
</tr>
</#list>
</table>
</section>
</body>
</html>
具体使用方法
@Override
public void pdfOut() throws Exception {
Map<String,Object> data = new HashMap<>();
ByteArrayOutputStream baos = null;
try {
//标题
data.put("title","标题");
//科室排名
data.put("DepartmentsRanking","内容");
data.put("DepartmentsRanking1","内容");
data.put("DepartmentsRanking2","内容");
data.put("DepartmentsRanking3","内容");
data.put("DepartmentsRankingList",this.selectDepList());
baos = createPDF(data, "Freemarker.ftl");
String yyyymmhh = new SimpleDateFormat("YYYYMMDDHHMMSSsss").format(new Date())+".pdf";
File file = new File("E:\\" + yyyymmhh);
FileOutputStream fileOutputStream = new FileOutputStream(file);
String pdf = this.ossService.uploadPdfStream((InputStream)new ByteArrayInputStream(baos.toByteArray()), "pdf");
// baos.writeTo(fileOutputStream);
baos.close();
}finally {
if(baos != null){
baos.close();
}
}
}
可以将ByteArrayOutputStream转换InputStream上传到oss阿里云
或者生成到本地
baos.writeTo(fileOutputStream);
本地图片写入
页面使用img标签<img src="imgse/000jpg"> resours下面的路径全部路径
网络图片写入
<section > <img src="${img}" style="height: 70px;width: 100%"></img> </section>
解决办法就是这样
后来又找了相关用法,总结如下:
data:,文本数据
data:text/plain,文本数据
data:text/html,HTML代码
data:text/html;base64,base64编码的HTML代码
data:text/css,CSS代码
data:text/css;base64,base64编码的CSS代码
data:text/javascript,Javascript代码
data:text/javascript;base64,base64编码的Javascript代码
data:image/gif;base64,base64编码的gif图片数据
data:image/png;base64,base64编码的png图片数据
data:image/jpeg;base64,base64编码的jpeg图片数据
data:image/x-icon;base64,base64编码的icon图片数据
但是这种方法不兼容IE6/7,使用时要注意!
data.put("img","data:image/jpeg;base64,"+getImgUrlToBase64("https://scpic.chinaz.net/files/pic/pic9/202108/apic34758.jpg"));
/**
* 将网络图片转换成Base64编码字符串
*
* @param imgUrl 网络图片Url
* @return
*/
public static String getImgUrlToBase64(String imgUrl) {
InputStream inputStream = null;
ByteArrayOutputStream outputStream = null;
byte[] buffer = null;
try {
// 创建URL
URL url = new URL(imgUrl);
// 创建链接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
inputStream = conn.getInputStream();
outputStream = new ByteArrayOutputStream();
// 将内容读取内存中
buffer = new byte[1024];
int len = -1;
while ((len = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, len);
}
buffer = outputStream.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
// 关闭inputStream流
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
// 关闭outputStream流
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 对字节数组Base64编码
return new BASE64Encoder().encode(buffer);
}