< dependency>
< groupId> org.freemarker</ groupId>
< artifactId> freemarker</ artifactId>
</ dependency>
< dependency>
< groupId> org.springframework.boot</ groupId>
< artifactId> spring-boot-starter-freemarker</ artifactId>
</ dependency>
< dependency>
< groupId> com.openhtmltopdf</ groupId>
< artifactId> openhtmltopdf-core</ artifactId>
< version> 1.0.0</ version>
</ dependency>
< dependency>
< groupId> com.openhtmltopdf</ groupId>
< artifactId> openhtmltopdf-pdfbox</ artifactId>
< version> 1.0.0</ version>
</ dependency>
package com. shell. common. utils. pdf ;
import com. openhtmltopdf. pdfboxout. PdfRendererBuilder ;
import org. springframework. util. ResourceUtils ;
import java. io. OutputStream ;
public class PdfUtil {
public static void buildPdf ( OutputStream os, String htmlContent) throws Exception {
PdfRendererBuilder builder = new PdfRendererBuilder ( ) ;
builder. useFont ( ResourceUtils . getFile ( "classpath:templates/fonts/simsun.ttf" ) , "simsun" ) ;
builder. useFastMode ( ) ;
builder. withHtmlContent ( htmlContent, ResourceUtils . getURL ( "classpath:templates/img/" ) . toString ( ) ) ;
builder. toStream ( os) ;
builder. run ( ) ;
}
}
package com. step. pdf. demo. controller ;
import com. step. pdf. demo. util. PdfUtil ;
import freemarker. template. Configuration ;
import freemarker. template. Template ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. web. bind. annotation. GetMapping ;
import org. springframework. web. bind. annotation. RestController ;
import org. thymeleaf. util. DateUtils ;
import javax. servlet. ServletOutputStream ;
import javax. servlet. http. HttpServletRequest ;
import javax. servlet. http. HttpServletResponse ;
import java. io. * ;
import java. util. Arrays ;
import java. util. HashMap ;
import java. util. Map ;
@RestController
public class DemoController {
@GetMapping ( "pdf2" )
public void test2 ( HttpServletResponse response, HttpServletRequest request) throws Exception {
OutputStream out = response. getOutputStream ( ) ;
Writer w = null ;
ByteArrayOutputStream outStream = null ;
Map < String , Object > variables = new HashMap < > ( ) ;
variables. put ( "staffName" , "staffName" ) ;
variables. put ( "functions" , "functions" ) ;
variables. put ( "assessmentDate" , "assessmentDate" ) ;
variables. put ( "roles" , "roles" ) ;
variables. put ( "aggregateSource" , "aggregateSource" ) ;
variables. put ( "questionList" , null ) ;
variables. put ( "comments" , null ) ;
variables. put ( "score" , "score" ) ;
variables. put ( "signature" , "signature" ) ;
variables. put ( "paperName" , "paperName" ) ;
variables. put ( "assessmentTypeName" , "info.getAssessmentTypeName()" ) ;
variables. put ( "pdfFileName" , "test" ) ;
try {
Configuration cfg = new Configuration ( Configuration . VERSION_2_3_0) ;
String templatePath = "src/main/resources" ;
cfg. setDirectoryForTemplateLoading ( new File ( templatePath) ) ;
Template freemarkerTemplate = cfg. getTemplate ( "/template/exam-paper.ftlh" ) ;
outStream = new ByteArrayOutputStream ( ) ;
w = new OutputStreamWriter ( outStream, "utf-8" ) ;
freemarkerTemplate. process ( variables, w) ;
String htmlContent = outStream. toString ( "utf-8" ) ;
PdfUtil . buildPdf ( out, htmlContent) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
finally {
try {
outStream. close ( ) ;
out. close ( ) ;
w. close ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
}
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8" />
<title>${pdfFileName}</title>
<style>
@page {
size: A4;
@top-center {
content: element(header);
}
@bottom-center {
font-family: 'simsun', serif;
}
}
html,
body {
font-family: 'simsun', serif;
font-size: 14px;
}
table {
-fs-table-paginate: paginate;
border-collapse: collapse;
width: 100%;
}
.headingBox {
font-size: 18px;
text-align: center;
font-style: italic;
font-weight: bolder;
}
table,
td,
th {
border: 0px solid #555;
padding: 3px 5px;
}
.box1,
.box2,
.box3 {
padding: 10px 20px;
border-top: 1px solid #999;
}
.trBox {
display: flex;
}
.tdBox {
width: 50%;
display: flex;
}
.titleBox {
display: inline-block;
width: 32%;
font-weight: bold;
}
.contentBox {
width: 68%;
color: cornflowerblue;
}
.titleOverviewBox {
display: inline-block;
width: 64%;
font-weight: bold;
}
.contentOverViewBox {
width: 36%;
color: cornflowerblue;
}
.functionTitleBox,
.commentsTitleBox {
font-style: italic;
font-weight: bolder;
margin: 0 0 0 2%;
}
</style>
<style>
#app {
border: 1px solid #999;
width: 550px;
box-sizing: border-box;
margin: 0px auto;
}
#comm {
height: 100px;
}
#content {
white-space: pre-line;
}
</style>
</head>
<body>
<div id="app">
<h3 class="headingBox">Competence Assessment_${assessmentTypeName}</h3>
<div class="box1">
<table border="0px;" class="baseInfoBox">
<tr class="trBox">
<td class="tdBox"><span class="titleBox">Name:</span><span class="contentBox"
>${staffName}</span></td>
<td class="tdBox"></td>
</tr>
<tr class="trBox">
<td class="tdBox"><span class="titleBox">Function:</span><span class="contentBox"
>${functions}</span></td>
<td class="tdBox"><span class="titleOverviewBox">Date:</span><span class="contentOverViewBox"
>${assessmentDate}</span></td>
</tr>
<tr class="trBox">
<td class="tdBox"><span class="titleBox">Role:</span><span class="contentBox"
>${roles}</span></td>
<td class="tdBox"><span class="titleOverviewBox">Aggregate Source:</span><span
class="contentOverViewBox">${aggregateSource}</span></td>
</tr>
</table>
</div>
<#--<#list questionList as question>
<div class="box1">
<h4 class="functionTitleBox">${question.functionName}:</h4>
<div class="w">
<tbody border="0">
<tr>
<td id="content">${question.questionContent}</td>
</tr>
</tbody>
</div>
</div>
<div class="box1">
<h4 class="commentsTitleBox">Comments:</h4>
<div class="c" height="500px" id="comm">
</div>
<div style="display: flex;">
<div style="padding-left: 18em"><span>Score:          </span>
<span>Signature:</span></div>
</div>
</div>
</#list>-->
</div>
</body>
</html>