依赖包
<!-- pdf 开始 -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-core</artifactId>
<version>9.0.3</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency>
<!-- pdf 结束 -->
<!-- freemarker 开始 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- freemarker 结束 -->
工具类
import com.itextpdf.text.pdf.BaseFont;
import com.example.call.file.FileService;
import com.example.call.file.vo.FileUploadVo;
import com.example.call.quote.vo.QResultOrderCopiesVO;
import com.example.core.model.ReturnT;
import com.example.core.util.LocalDateTimeUtil;
import com.example.core.util.MultipartFileUtil;
import com.example.core.util.PropertyUtil;
import com.example.core.util.SpringUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* <生成PDF文件>
*/
public class PdfTool1 {
/**
* <生成合并报价单PDF文件,并上传OSS返回其URL>
* @param vo 报价单数据对象
* @return java.lang.String
* @author hmy
* @date 2022/12/28 21:00
* @version 1.0.0
*/
public static String createPdfFile(QtResultOrderCopiesVO vo){
try {
String htmlString = "";
try {
Configuration cfg = SpringUtil.getBean(Configuration.class);
//本次测试不依赖Spring容器时使用下边的
// Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
// cfg.setDirectoryForTemplateLoading(new File("D:\\myfiles\\xianniu-quote\\src\\main\\resources\\templates"));
// cfg.setDefaultEncoding("UTF-8");
// cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
Template temp = cfg.getTemplate("t_merge.ftl");
htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(temp, vo);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("PDF模板获取异常");
}
byte[] dataArray = html2pdf(htmlString);
String url = uploadPdf(dataArray);
return url;
}catch (Exception e){
e.printStackTrace();
throw new RuntimeException("生成PDF异常");
}
}
private static String uploadPdf(byte[] dataArray) throws IOException {
String fileName = "生成结果"+ LocalDateTimeUtil.getCurrentStrByFormatter(LocalDateTimeUtil.yyyyMMddHHmmssSSS) +".pdf";
PropertyUtil p = SpringUtil.getBean(PropertyUtil.class);
String fileUploadPath = p.getProperties("xxx.file-upload-path"); //临时文件保存目录
String filePath = ExcelUtils.getWebRootPath(fileUploadPath+ fileName);
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
// 输出pdf
assert dataArray != null;
fileOutputStream.write(dataArray);
fileOutputStream.flush();
fileOutputStream.close();
File file = new File(filePath);
FileService fileService = SpringUtil.getBean(FileService.class);
String url = "";
MultipartFile multipartFile = MultipartFileUtil.toMultipartFile(file);
//将导入结果反馈给前端
ReturnT<FileUploadVo> r = fileService.uploadFile(multipartFile);
if(r.verifySuccess()) {
url = r.getData().getUrl();
}
return url;
}
/**
* html转pdf
* @param htmlString html字符
* @return byte[]
*/
public static byte[] html2pdf(String htmlString) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(htmlString);
// 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont("simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont("fontawesome-webfont.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//解决图片的相对路径问题,图片使用base64编码即可,否则就得如下使用,建议使用base64
// renderer.getSharedContext().setBaseURL("http://www.baidu.com/test.jpg");
renderer.getSharedContext().setReplacedElementFactory(new B64ImgReplacedElementFactory());
renderer.layout();
renderer.createPDF(byteArrayOutputStream);
return byteArrayOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
byteArrayOutputStream.flush();
byteArrayOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 生成pdf单元测试
*/
// @Test
// public void createMergeResultPdfTest() {
// QResultOrderCopiesVO vo = new QResultOrderCopiesVO();
// Map<String, Object> model = BeanUtil.beanToMap(vo);
// // other value map
//
// try {
// Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
//// cfg.setDirectoryForTemplateLoading(new File("D:\\myfiles\\xia-quote\\src\\main\\resources\\templates"));
// cfg.setDirectoryForTemplateLoading(new File("src\\main\\resources\\templates"));
// cfg.setDefaultEncoding("UTF-8");
// cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
//
// Template temp = cfg.getTemplate("t_merge" + ".ftl");
//
// String htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(temp, model);
// FileUtil.writeUtf8String(htmlString, "createMergeResultPdfTest.html");
// byte[] dataArray = PdfTool.html2pdf(htmlString);
// if (dataArray != null && dataArray.length > 0) {
// // 输出pdf
// FileOutputStream fileOutputStream = new FileOutputStream("createMergeResultOrderPdfTest.pdf");
// fileOutputStream.write(dataArray);
// fileOutputStream.flush();
// fileOutputStream.close();
// }
// } catch (Exception e) {
// e.printStackTrace();
// throw new RuntimeException("PDF模板获取异常");
// }
// }
}
辅助类
// 支持base64的实现
public class B64ImgReplacedElementFactory implements ReplacedElementFactory {
public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
Element e = box.getElement();
if (e == null) {
return null;
}
String nodeName = e.getNodeName();
if (nodeName.equals("img")) {
String attribute = e.getAttribute("src");
FSImage fsImage;
try {
fsImage = buildImage(attribute, uac);
} catch (BadElementException e1) {
fsImage = null;
} catch (IOException e1) {
fsImage = null;
}
if (fsImage != null) {
if (cssWidth != -1 || cssHeight != -1) {
fsImage.scale(cssWidth, cssHeight);
}
return new ITextImageElement(fsImage);
}
}
return null;
}
public void remove(Element arg0) {
// Auto-generated method stub
}
public void reset() {
// Auto-generated method stub
}
public void setFormSubmissionListener(FormSubmissionListener arg0) {
// Auto-generated method stub
}
protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException, BadElementException {
FSImage fsImage;
if (srcAttr.startsWith("data:image/")) {
String b64encoded = srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(), srcAttr.length());
byte[] decodedBytes = Base64.getDecoder().decode(b64encoded);
fsImage = new ITextFSImage(Image.getInstance(decodedBytes));
} else {
fsImage = uac.getImageResource(srcAttr).getImage();
}
return fsImage;
}
}