java使用freemarker模板生成html再轉(zhuǎn)為pdf
1.freemarker模板生成html
添加Maven依賴
在pom.xml文件中添加以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
創(chuàng)建Freemarker模板
新建一個HTML文件,例如table.ftl,然后在其中編寫HTML模板,包括表格的頭部、內(nèi)容和尾部等部分。具體可以參考下面這個例子:
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<#list users as user>
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.age}</td>
</tr>
</#list>
</tbody>
</table>上面的模板中使用了Freemarker的指令語法來實(shí)現(xiàn)動態(tài)生成表格內(nèi)容,包括使用<#list>標(biāo)簽來遍歷用戶列表,并使用${}語法來輸出用戶信息。
創(chuàng)建Controller方法
在Controller中編寫一個方法來獲取用戶列表,然后渲染上面的模板并返回HTML內(nèi)容。示例代碼如下:
@Controller
public class UserController {
@GetMapping("/users")
public String userList(Model model) {
List<User> users = new ArrayList<>();
users.add(new User(1, "Tom", 18));
users.add(new User(2, "Jerry", 20));
users.add(new User(3, "John", 22));
model.addAttribute("users", users);
return "table";
}
}
上面的方法使用@GetMapping注解來處理請求,然后創(chuàng)建一個用戶列表,并將其添加到模型中。最后返回table字符串,代表要使用的HTML模板文件。
運(yùn)行項(xiàng)目
運(yùn)行Spring Boot應(yīng)用程序,然后使用瀏覽器訪問http://localhost:8080/users,即可看到動態(tài)生成的HTML表格。
注意:上面的例子僅供參考,實(shí)際應(yīng)用中需要根據(jù)自己的需求進(jìn)行修改擴(kuò)展。
2.利用iText將生成的HTML轉(zhuǎn)換為PDF文件
理解了freemarker生成html的步驟以后,就可以利用iText把html生成pdf文件了。
1.編寫轉(zhuǎn)換代碼
添加Maven依賴
在pom.xml文件中添加以下依賴:
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!-- 支持css樣式渲染 -->
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.9</version>
</dependency>
2.編寫轉(zhuǎn)換代碼
在SpringBoot應(yīng)用程序中創(chuàng)建一個Service或者Controller類,然后編寫HTML轉(zhuǎn)PDF的代碼。
freeMarker轉(zhuǎn)換為html的方法:
public class HtmlGenerator {
??????? public static String generate(String template, Map<String, Object> variables) throws IOException, TemplateException, IOException {
Configuration config = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
config.setClassForTemplateLoading(HtmlGenerator.class, "/filePath");
//讀取模板文件地址
config.setDefaultEncoding("UTF-8");
//獲取模板文件
Template tp = config.getTemplate(template);
StringWriter stringWriter = new StringWriter();
BufferedWriter writer = new BufferedWriter(stringWriter);
tp.setEncoding("UTF-8");
//把map數(shù)據(jù)寫入
tp.process(variables, writer);
String htmlStr = stringWriter.toString();
writer.flush();
writer.close();
return htmlStr;
}
}/filePath為項(xiàng)目中的ftl文件相對路徑。
html生成pdf的方法:
public class PdfDocumentGenerator {
private static final Logger logger = LoggerFactory.getLogger(PdfDocumentGenerator.class);
/**
* Output a pdf to the specified outputstream
*
* @param htmlStr
* the htmlstr
* @param out
* the specified outputstream
* @throws Exception
*/
public static void generate(String htmlStr, OutputStream out)
throws Exception {
DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); // Compliant
df.setAttribute(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); // compliant
DocumentBuilder builder = df.newDocumentBuilder();
org.w3c.dom.Document doc = builder.parse(new ByteArrayInputStream(htmlStr
.getBytes()));
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(doc, null);
renderer.layout();
renderer.createPDF(out);
out.close();
}
public static void generatePlus(String htmlStr, OutputStream out) throws IOException, DocumentException {
final String charsetName = "UTF-8";
Document document = new Document(PageSize.A4, 30, 30, 30, 30);
document.setMargins(30, 30, 30, 30);
PdfWriter writer = PdfWriter.getInstance(document, out);
document.open();
// html內(nèi)容解析
HtmlPipelineContext htmlContext = new HtmlPipelineContext(
new CssAppliersImpl(new XMLWorkerFontProvider() {
@Override
public Font getFont(String fontname, String encoding,
float size, final int style) {
if (fontname == null) {
fontname = getChineseFont();
}
return super.getFont(fontname, encoding, size,
style);
}
})) {
@Override
public HtmlPipelineContext clone()
throws CloneNotSupportedException {
HtmlPipelineContext context = super.clone();
try {
ImageProvider imageProvider = this.getImageProvider();
context.setImageProvider(imageProvider);
} catch (NoImageProviderException e) {
}
return context;
}
};
// 圖片解析
htmlContext.setImageProvider(new AbstractImageProvider() {
String rootPath = PdfDocumentGenerator.class.getResource("/").getPath();
@Override
public String getImageRootPath() {
return rootPath;
}
@Override
public Image retrieve(String src) {
if (StringUtils.isEmpty(src)) {
return null;
}
try {
Image image = Image.getInstance(new File(rootPath, src).toURI().toString());
// 圖片顯示位置
image.setAbsolutePosition(400, 400);
if (image != null) {
store(src, image);
return image;
}
} catch (Throwable e) {
e.printStackTrace();
}
return super.retrieve(src);
}
});
htmlContext.setAcceptUnknown(true).autoBookmark(true).setTagFactory(Tags.getHtmlTagProcessorFactory());
// css解析
CSSResolver cssResolver = XMLWorkerHelper.getInstance().getDefaultCssResolver(true);
cssResolver.setFileRetrieve(new FileRetrieve() {
@Override
public void processFromStream(InputStream in,
ReadingProcessor processor) throws IOException {
try (
InputStreamReader reader = new InputStreamReader(in, charsetName)) {
int i = -1;
while (-1 != (i = reader.read())) {
processor.process(i);
}
} catch (Throwable e) {
}
}
// 解析href
@Override
public void processFromHref(String href, ReadingProcessor processor) throws IOException {
InputStream is = PdfDocumentGenerator.class.getResourceAsStream("/" + href);
try (InputStreamReader reader = new InputStreamReader(is,charsetName)) {
int i = -1;
while (-1 != (i = reader.read())) {
processor.process(i);
}
} catch (Throwable e) {
e.printStackTrace();
}
}
});
HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer));
Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);
XMLWorker worker = null;
worker = new XMLWorker(pipeline, true);
XMLParser parser = new XMLParser(true, worker, Charset.forName(charsetName));
try (InputStream inputStream = new ByteArrayInputStream(htmlStr.getBytes())) {
parser.parse(inputStream, Charset.forName(charsetName));
}
document.close();
}
/**
* 獲取中文字體位置
* @return
*/
public static String getChineseFont() {
String chineseFont = null;
chineseFont = Object.class.getResource("/").getPath() + "font/simsun.ttc";
if(!new File(chineseFont).exists()){
throw new RuntimeException("字體文件不存在!"+chineseFont);
}
return chineseFont;
}
}運(yùn)行測試方法:
public class Pdfdest {
public static void main(String[] args) throws Exception {
String outputFile = "d:/test1.pdf";
Map<String, Object> map = new HashMap<>();
map.put("XXX", "測試");
//生成工具,下面有代碼
String htmlStr = HtmlGenerator.generate("test.ftl", map);
//生成工具,下面有代碼
OutputStream out = new FileOutputStream(outputFile);
PdfDocumentGenerator.generatePlus(htmlStr,out);
}
}
準(zhǔn)備一個test.ftl放到resource/filePath下,當(dāng)然字體最好也放到resource/font下,運(yùn)行時需要使用。
test.ftl的代碼如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"></meta>
<style>
@page {
@top-center { content: element(header) }
}
@page {
@bottom-center { content: element(footer) }
}
.apply {
margin: 0 auto;
padding: 0 30px;
}
.title {
margin-top: 40px ;
text-align: center;
font-weight: bold;
//字體需要和后臺對應(yīng)上
font-family: SimSun;
font-weight: bold;
font-size: 20px;
color: #333333;
letter-spacing: 0;
}
.table {
border-collapse: collapse;
width: 100%;
margin-top: 30px;
font-family: SimSun;
font-size: 14px;
color: #111111;
letter-spacing: 0.54px;
}
.label {
background-color: #E6E6E6;
width: 20%;
}
.normaltd {
padding: 10px 0;
}
.maxtd {
height: 250px;
}
.value {
width: 30%;
padding-left: 10px;
}
.apply {
margin: 0 auto;
padding: 0 30px;
}
.title {
margin-top: 40px ;
text-align: center;
font-weight: bold;
//字體需要和后臺對應(yīng)上
font-family: SimSun;
font-weight: bold;
font-size: 20px;
color: #333333;
letter-spacing: 0;
}
.table {
width: 100%;
margin-top: 30px;
font-family: SimSun;
font-size: 14px;
color: #111111;
letter-spacing: 0.54px;
}
.label {
background-color: #E6E6E6;
width: 20%;
}
.normaltd {
padding: 10px 0;
}
.maxtd {
height: 250px;
}
.value {
width: 30%;
padding-left: 10px;
}
tr {
page-break-inside: avoid;
page-break-after: auto;
}
</style>
</head>
<body style="font-family: SimSun">
<div class="apply">
<p class="title">申請單</p>
<table border="1" cellspacing="0" class="table">
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">XXX</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr >
<td valign="middle" colspan="1" class="label maxtd" align="center">XXX</td>
<td valign="middle" colspan="3" class="maxtd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">XXX</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr >
<td valign="middle" colspan="1" class="label maxtd" align="center">XXX</td>
<td valign="middle" colspan="3" class="maxtd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td colspan="1" class="label normaltd" align="center">XXX</td>
<td colspan="3" class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">XXX</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
<tr>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
<td class="label normaltd" align="center">XXX</td>
<td class="normaltd value">${XXX}</td>
</tr>
</table>
</div>
</body>
</html>
執(zhí)行就可以看到生成的pdf文件了,文件路徑在d:/test1.pdf。
到此這篇關(guān)于java使用freemarker模板生成html再轉(zhuǎn)為pdf的文章就介紹到這了,更多相關(guān)java freemarker生成html內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript checkbox全選和反選的簡單實(shí)現(xiàn)
這篇文章主要介紹了javascript checkbox全選和反選的簡單實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下2017-05-05
Java根據(jù)正整數(shù)的位數(shù)并逆序打印出各位數(shù)字
給一個不多于5位的正整數(shù),要求:一、求它是幾位數(shù),二、逆序打印出各位數(shù)字,需要的朋友可以參考下2017-02-02
詳解MyBatis批量插入數(shù)據(jù)Mapper配置文件的寫法
本篇文章主要介紹了詳解MyBatis批量插入數(shù)據(jù)Mapper文件的寫法,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04
Spring Cloud Admin健康檢查 郵件、釘釘群通知的實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud Admin健康檢查 郵件、釘釘群通知的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08

