Java整合FreeMarker导出Pdf文件

news/2024/10/6 4:12:47

引入依赖

<!--Freemarker wls--><dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.30</version></dependency><dependency><groupId>com.itextpdf.tool</groupId><artifactId>xmlworker</artifactId><version>5.5.11</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.1.18</version></dependency><dependency><groupId>gui.ava</groupId><artifactId>html2image</artifactId><version>2.0.1</version></dependency>

代码示例

/*** @author alin* @date 2024-06-11*/
@Slf4j
public class TestCreatePdf {public static void main(String[] args) throws Exception {generatePdfUrl();}/*** 生成pdf** @return*/public static String generatePdfUrl() throws Exception {// 构造参数Model model = assembleData();return createPdfAndUpload(beanToMap(model), UUID.randomUUID() + ".pdf", "testCreatePdf.html", "testCreatePdf.css");}/*** 创建pdf并上传/输出* * @param data* @param fileName 文件名* @param templateFileName 模板文件名, html模板文件* @param cssPath css文件路径* @return* @throws Exception*/private static String createPdfAndUpload(Map<String, Object> data, String fileName, String templateFileName, String cssPath) throws Exception {ByteArrayOutputStream outputStream = new ByteArrayOutputStream();try {// 根据模板生成html字符串String pdf = createHtmlStr(data, templateFileName);// 通过html字符串生成pdf文件generatePdf(pdf, outputStream, cssPath);} catch (Exception e) {return null;}// 输出/上传至指定位置FileOutputStream out = new FileOutputStream("d:/testPdf/" + fileName);out.write(outputStream.toByteArray());return "d:/testPdf/" + fileName;}/*** bean转map* * @param bean* @return*/public static Map<String, Object> beanToMap(Object bean) {Class<?> clazz = bean.getClass();return Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toMap(Field::getName,field -> {try {field.setAccessible(true);return field.get(bean);} catch (IllegalAccessException e) {// 处理异常return null;}}));}/*** 模板生成html字符串** @param data             数据* @param templateFileName 模板文件名* @throws Exception 捕获异常*/public static String createHtmlStr(Map<String, Object> data, String templateFileName) throws Exception {// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);// 指定FreeMarker模板文件的位置cfg.setClassForTemplateLoading(TestCreatePdf.class, "/template");// 获取模板文件Template template = cfg.getTemplate(templateFileName, "UTF-8");StringWriter stringWriter = new StringWriter();BufferedWriter writer = new BufferedWriter(stringWriter);template.process(data, writer);String htmlStr = stringWriter.toString();writer.flush();writer.close();return htmlStr;}/*** 通过html字符串生成pdf文件** @param htmlStr* @param out* @param cssPath* @throws IOException* @throws DocumentException*/public static void generatePdf(String htmlStr, OutputStream out, String cssPath) throws IOException, DocumentException {Document document = new Document(PageSize.A3);PdfWriter writer = PdfWriter.getInstance(document, out);document.open();// html内容解析HtmlPipelineContext htmlContext = new HtmlPipelineContext(new CssAppliersImpl(new XMLWorkerFontProvider() {@Overridepublic Font getFont(String fontName, String encoding,float size, final int style) {Font font = null;if (fontName == null) {//字体BaseFont bf;try {bf = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);font = new Font(bf, size, style);} catch (Exception e) {log.error("getFont", e);}}return font;}})) {@Overridepublic HtmlPipelineContext clone()throws CloneNotSupportedException {HtmlPipelineContext context = super.clone();try {ImageProvider imageProvider = this.getImageProvider();context.setImageProvider(imageProvider);} catch (Exception e) {log.error("clone", e);}return context;}};// 图片解析htmlContext.setImageProvider(new AbstractImageProvider() {@Overridepublic String getImageRootPath() {return StringUtils.EMPTY;}@Overridepublic Image retrieve(String src) {if (StringUtils.isEmpty(src)) {return null;}try {int pos = src.indexOf("base64,");try {if (src.startsWith("data") && pos > 0) {byte[] img = Base64.decode(src.substring(pos + 7));return Image.getInstance(img);} else if (src.startsWith("http")) {return Image.getInstance(src);}} catch (Exception ex) {log.error("retrieve", ex);return null;}return null;} catch (Throwable e) {log.error("retrieve", e);}return super.retrieve(src);}});htmlContext.setAcceptUnknown(true).autoBookmark(true).setTagFactory(Tags.getHtmlTagProcessorFactory());// css解析CSSResolver cssResolver = new StyleAttrCSSResolver();InputStream cssInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(cssPath);CssFile cssfile = XMLWorkerHelper.getCSS(cssInputStream);cssResolver.addCss(cssfile);HtmlPipeline htmlPipeline = new HtmlPipeline(htmlContext, new PdfWriterPipeline(document, writer));Pipeline<?> pipeline = new CssResolverPipeline(cssResolver, htmlPipeline);XMLWorker worker = new XMLWorker(pipeline, true);XMLParser parser = new XMLParser(true, worker, StandardCharsets.UTF_8);try (InputStream inputStream = new ByteArrayInputStream(htmlStr.getBytes())) {parser.parse(inputStream, StandardCharsets.UTF_8);}document.close();}/*** 组装数据** @return* @throws Exception*/private static Model assembleData() throws Exception {TestCreatePdf.Model model = new TestCreatePdf.Model();model.setCompanyName("公司名称");model.setField1("字段一");model.setField2("字段二");model.setField3("字段三");model.setField4("字段四");model.setField5("字段五");model.setField6("字段六");model.setField7("字段七");model.setRemark("备注~~~~~~~~~");model.setSignUrl1("D:/testPdf/test.png");model.setSignUrl2("D:/testPdf/test.png");model.setSignUrl3("D:/testPdf/test.png");model.setSignTime1("2024-04-28 17:08:52");model.setSignTime2("2024-04-28 17:08:52");model.setSignTime3("2024-04-28 17:08:52");List<Object> modeDetailFieldList = Lists.newArrayList();modeDetailFieldList.add("表头一");modeDetailFieldList.add("表头二");modeDetailFieldList.add("表头三");modeDetailFieldList.add("表头四");modeDetailFieldList.add("表头五");modeDetailFieldList.add("表头六");model.setModeDetailFieldList(modeDetailFieldList);List<List<Object>> modeDetailValueList = Lists.newArrayList();for (int i = 1; i < 6; i++) {List<Object> valueList = Lists.newArrayList();valueList.add("表头一值--" + i);valueList.add("表头二值--" + i);valueList.add("表头三值--" + i);valueList.add("表头四值--" + i);valueList.add("表头五值--" + i);valueList.add("表头六值--" + i);modeDetailValueList.add(valueList);}model.setModeDetailValueList(modeDetailValueList);return model;}@Datapublic static class Model {/*** companyName*/private String companyName;/*** 字段1*/private String field1;/*** 字段2*/private String field2;/*** 字段3*/private String field3;/*** 字段4*/private String field4;/*** 字段5*/private String field5;/*** 字段6*/private String field6;/*** 字段7*/private String field7;/*** 备注*/private String remark;/*** 图片地址(base64结构)*/private String imgBase64;/*** signUrl1*/private String signUrl1;/*** signUrl2*/private String signUrl2;/*** signUrl3*/private String signUrl3;/*** signTime1*/private String signTime1;/*** signTime2*/private String signTime2;/*** signTime3*/private String signTime3;/*** 表格字段名称*/private List<Object> modeDetailFieldList;/*** 表格字段值*/private List<List<Object>> modeDetailValueList;}}

结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hjln.cn/news/43087.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

PHP文件上传接口

文件上传接口 上传在项目/runtime/storage/下,返回的是相对路径.// 文件上传接口public function uploadAjax(){// 获取上传的文件$file = Request::file(file);// 验证规则$validate = Validate::rule([file => fileExt:jpg,jpeg,png,gif|fileSize:10485760, // 限制文件扩…

The field file exceeds its maximum permitted size of 1048576 bytes

问题—基于Springboot 项目,文件上传功能报错 Caused by: The field file exceeds its maximum permitted size of 1048576 bytes. 文件的大小超出了允许的范围。错误原因 SpringBoot内嵌的 Tomcat 默认的所有上传的文件大小为 1MB,超出这个大小就会报错,解决这个问题需要更…

云盘下载加速

1:下载助手 下面都是油猴插件 网盘直链下载助手 配合其他下载器达到加速下载,百度、夸克 等主流网盘都支持,可以选择多个文件,但不能选择文件夹下载。 123网盘直接拥 IDM 满速下载就行,直接浏览器下载,不需要保存到自己网盘里。 https://greasyfork.org/zh-CN/scripts/43…

计算机简史第五章 未来时代

未来计算机会是什么样呢?‍未来计算机会是什么样呢?‍ ‍ 光学计算 世界上速度最快的就是光,尽管电的传播速度也接近光速,但光还是凭借许多压倒性的优势不断吸引着计算机科学家们的注意力:电路布线时,为避免短路和电磁干扰,必须确保线路间的相互隔离,多条光波却可以直接…

Xshell如何修改编辑文件 Xshell如何保存修改后的文件

软件版本:Xshell 7 Xshell是一款功能强大的终端模拟软件,它可以让用户通过SSH、Telnet等协议远程连接到Linux服务器,并执行各种命令。在使用Xshell时,有时候我们需要修改服务器上的文件,或者保存我们的修改。那么,Xshell如何修改编辑文件,Xshell如何保存修改后的文件呢?…

杭州的 IT 崩盘了么?

大家好,我是R哥。 今天分享一个爽飞了的面试辅导 case:这个杭州兄弟空窗期 1 个月+,面试了 6 家公司 0 Offer,不知道问题出在哪,难道是杭州的 IT 崩盘了么? 报名面试辅导后,经过一个多月的辅导打磨,现在成功入职某上市公司,涨薪 30%+,955 工作制,不咋加班,还不卷。…

MQCal工程算量V1.3.3.30(2024-6-10)更新增加辅助输入

MQCal工程算量辅助输入来了! 1、数据输入设置辅助输入数据设置 辅助输入框可以设置辅助输入所需要的数据,并且可以设置数据对应的列。这是一个完全自定义的设置,哪一列对应什么输入数据。 2、数据上屏查找:辅助输入查找数据并排序 数据查找支持拼英首字母查找,查找的数据…

E - Reachability in Functional Graph

E - Reachability in Functional Graph https://atcoder.jp/contests/abc357/tasks/abc357_e思路 概念: 基环树-内生树。 https://www.cnblogs.com/Dfkuaid-210/p/14696378.html 方法: 使用拓扑排序,从入度为0的点开始,依此从外层向内层拆点,直到剩下环, 拆换过程中把拆掉…