开发者

java使用freemarker模板生成html再转为pdf

目录
  • 1.freemarker模板生成html
    • 添加Maven依赖
    • 创建Freemarker模板
    • 创建Controller方法
    • 运行项目
  • 2.利用iText将生成的HTML转换为PDF文件

    1.freemarker模板生成html

    添加Maven依赖

    在pom.XML文件中添加以下依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>
    

    创建Freemarker模板

    新建一个HTML文件,例如table.ftl,然后在其中编写HTML模板,包括表格的头部、内容和尾部等部分。具体可以参考下面这个例子:

    <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的指令语法来实现动态生成表格内容,包括使用<#list>标签来遍历用户列表,并使用${}语法来输出用户信息。

    创建Controller方法

    在Controller中编写一个方法来获取用户列表,然后渲染上面的模板并返回HTML内容。示例代码如下:

    @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);
    javascript        return "table";
        }
    }
    

    上面的方法使用@GetMapping注解来处理请求,然后创建一个用户列表,并将其添加到模型中。最后返回table字符串,代表要使用的HTML模板文件。

    运行项目

    运行Spring Boot应用程序,然后使用浏览器访问http://localhost:8080/users,即可看到动态生成的HTML表格。

    注意:上面的例子仅供参考,实际应用中需要根据自己的需求进行修改扩展。

    2.利用iText将生成的HTML转换为PDF文件

    理解了freemarker生成html的步骤以后,就可以利用iText把html生成pdf文件了。

    1.编写转换代码

    添加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.编写转换代码

    在SpringBoot应用程序中创建一个Service或者Controller类,然后编写HTML转PDF的代码。

    freeMarker转换为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数据写入
            tp.process(variables, writer);
            String htmlStr = stringWriter.toString();
            writer.flush();
            writer.close();
            return htmlStr;
        }
    }

    /filePath为项目中的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内容解析
            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;
        }
    }

    运行测试方法:

    public class Pdfdest {
        public static vophpid 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);
        }
    }
    

    准备一个test.ftl放到resource/filePath下,当然字体最好也放到resource/font下,运行时需要使用。

    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;
            //字体需要和后台对应上
            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;
            //字体需要和后台对应上
            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;
             php   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>
    <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<android/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>
    

    执行就可以看到生成的pdf文件了,文件路径在d:/test1.pdf。

    到此这篇关于Java使用freemarker模板生成html再转为pdf的文章就介绍到这了,更多相关java freemarker生成html内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜