首页 > 编程语言 >Java整合FreeMarker导出Pdf文件

Java整合FreeMarker导出Pdf文件

时间:2024-06-11 10:45:02浏览次数:12  
标签:return String FreeMarker 字段 private Java new Pdf model

引入依赖

<!--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() {
                    @Override
                    public 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;
                    }
                })) {
            @Override
            public 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() {
            @Override
            public String getImageRootPath() {
                return StringUtils.EMPTY;
            }

            @Override
            public 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;
    }

    @Data
    public 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;

    }


}

结果

标签:return,String,FreeMarker,字段,private,Java,new,Pdf,model
From: https://www.cnblogs.com/menghl/p/18241663

相关文章