思路如下:
1、制作模板(建议写静态HTML,样式会好看些):按照导出的格式弄一个word文件,然后通过转换工具转成HTML,但是一般转换的会有一些问题,需要删除一些样式字体等
推荐一个在线转换(百度随便搜一下):在线WORD转HTMLhttps://cn.office-converter.com/Word-to-HTML-Converter
在样式中添加字体样式(重要),这是不乱码的关键一步
body { font-family: "simsun"; }
2、准备字体:simsun.tcc,在windows目录也有拷一个就行:C:WindowsFonts
3、在项目中导入相关的依赖,主要是Freemarker、itextpdf
9.1.16 5.5.13 org.springframework.boot spring-boot-starter-freemarkerorg.xhtmlrenderer flying-saucer-pdf${flying-saucer-pdf.version} com.itextpdf itextpdf${itextpdf.version} > com.itextpdf.tool xmlworker${itextpdf.version}
此处为核心:maven打包会压缩字体,需要排除一下
下面贴一下核心代码:org.apache.maven.plugins maven-resources-plugin2.7 ttc html org.apache.maven.shared maven-filtering1.3
渲染模板、渲染PDF
package com.yx.exportpdfdemo.utils;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.document;
import com.itextpdf.text.documentException;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Template;
import org.springframework.core.io.ClassPathResource;
import java.io.*;
import java.nio.charset.Charset;
import java.util.Map;
public class PDFUtil {
private static String FONT_CACHE_DIR = null;
public static String freeMarkerRender(Map data, Template template) {
Writer out = new StringWriter();
try {
template.setOutputEncoding("UTF-8");
// 合并数据模型与模板
//将合并后的数据和模板写入到流中,这里使用的字符流
template.process(data, out);
out.flush();
return out.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
return null;
}
public static void createPdf(String content, String tempDir, String font) throws IOException, documentException {
document document = new document(PageSize.A4, 36.0F, 36.0F, 60.0F, 36.0F);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(tempDir));
document.open();
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
if (StrUtil.isBlankOrUndefined(FONT_CACHE_DIR)) {
File fontTemp = new File(System.getProperty("java.io.tmpdir") + File.separator + "simsun.ttc");
if (!fontTemp.exists()) {
fontTemp.createNewFile();
}
ClassPathResource simResource = new ClassPathResource(font);
FileUtil.writeFromStream(simResource.getInputStream(), fontTemp);
FONT_CACHE_DIR = fontTemp.getPath();
}
fontImp.register(FONT_CACHE_DIR);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,
new ByteArrayInputStream(content.getBytes()), null, Charset.forName("UTF-8"), fontImp);
document.close();
writer.close();
}
}
Controller:
package com.yx.exportpdfdemo.controller;
import cn.hutool.json.JSONUtil;
import com.yx.exportpdfdemo.config.PDFExportConfig;
import com.yx.exportpdfdemo.utils.PDFUtil;
import freemarker.template.Template;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
@RestController
@AllArgsConstructor
public class UserController {
private final FreeMarkerConfigurer freeMarkerConfigurer;
private final PDFExportConfig pdfExportConfig;
private static String EXPORT_NAME = "export";
private static String EXPORT_SUFFIX = "pdf";
@SneakyThrows
@GetMapping(value = "/export")
public void domesticViolenceSee(HttpServletResponse response) {
//添加测试数据
Map data = new HashMap();
data.put("username", "法外狂徒张三");
data.put("age", "24");
//根据配置类拿到模板名称,再通过FreeMarkerConfigurer获取Template对象
Template template = freeMarkerConfigurer.getConfiguration().getTemplate(pdfExportConfig.getUserFtl());
String content = PDFUtil.freeMarkerRender(data, template);
File exportFile = File.createTempFile(EXPORT_NAME, EXPORT_SUFFIX);
PDFUtil.createPdf(content, exportFile.getPath(), pdfExportConfig.getFont());
FileInputStream fin;
try {
fin = new FileInputStream(exportFile);
OutputStream output = response.getOutputStream();
byte[] buf = new byte[1024];
int r;
response.setContentType("application/pdf;charset=GB2312");
while ((r = fin.read(buf, 0, buf.length)) != -1) {
output.write(buf, 0, r);
}
fin.close();
output.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
exportFile.delete();
}
}
}
配置类:
package com.yx.exportpdfdemo.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
@Configuration
@Data
public class PDFExportConfig {
@Value("${font}")
private String font;
@Value("${user-ftl}")
private String userFtl;
}
HTML模板:
body {
font-family: "simsun";
}
table {
border-collapse: collapse;
border-spacing: 0;
empxy-cells: show
}
td, th {
vertical-align: top;
font-size: 12px;
}
h1, h2, h3, h4, h5, h6 {
clear: both;
}
ol, ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
margin: 0;
padding: 0;
}
li span. {
clear: both;
line-height: 0;
width: 0;
height: 0;
margin: 0;
padding: 0;
}
span.footnodeNumber {
padding-right: 1em;
}
span.annotation_style_by_filter {
font-size: 95%;
background-color: #fff000;
margin: 0;
border: 0;
padding: 0;
}
span.heading_numbering {
margin-right: 0.8rem;
}
* {
margin: 0;
}
.P1 {
font-size: 10.5px;
margin-bottom: 0in;
margin-top: 0in;
text-align: justify ! important;
writing-mode: horizontal-tb;
direction: ltr;
}
.Standard {
font-size: 10.5px;
writing-mode: horizontal-tb;
direction: ltr;
margin-top: 0in;
margin-bottom: 0in;
text-align: justify ! important;
}
.Table1 {
width: 5.7611in;
margin-left: 0.0035in;
margin-top: 0in;
margin-bottom: 0in;
margin-right: auto;
writing-mode: horizontal-tb;
direction: ltr;
}
.Table1_A1 {
padding-left: 0.075in;
padding-right: 0.075in;
padding-top: 0in;
padding-bottom: 0in;
border-width: 0.0176cm;
border-style: solid;
border-color: #000000;
writing-mode: horizontal-tb;
direction: ltr;
}
测试导出PDF
姓名
${username}
年龄
${age}
YML:
spring:
application:
name: demo
freemarker:
enabled: true
content-type: text/html
suffix: .html #后缀名
charset: UTF-8 #编码格式
template-loader-path: classpath:/templates/ #此为freemarker默认配置
server:
port: 8090
#字体
font: simsun.ttc
user-ftl: user-ftl.html
此为导出结果:
DEMO代码



