zoukankan      html  css  js  c++  java
  • java通过html生成pdf,支持css和图片以及横向打印

    项目当中通常会有生成pdf的需求,pdf的排版尤为重要!通过html生成,最为方便.

    1. 依赖

    工具使用freemarker模板进行数据渲染

    <dependency>
      <groupId>org.freemarker</groupId>
      <artifactId>freemarker</artifactId>
      <version>2.3.29</version>
    </dependency>
    <dependency>
      <groupId>org.xhtmlrenderer</groupId>
      <artifactId>flying-saucer-pdf</artifactId>
      <version>9.1.18</version>
    </dependency>
    

    2. 工具类

    import java.io.*;
    import java.util.Locale;
    import java.util.Map;
    import org.xhtmlrenderer.pdf.ITextRenderer;
    import com.lowagie.text.pdf.BaseFont;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    
    public class PdfUtil {
    
    	/**
    	 * 通过模板导出pdf文件
    	 * @param data 数据
    	 * @param templateFileName 模板文件名
    	 * @throws Exception
    	 */
        public static ByteArrayOutputStream createPDF(Map<String,Object> data, String templateFileName) throws Exception {
            // 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
            Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
            // 指定FreeMarker模板文件的位置 
            cfg.setClassForTemplateLoading(PdfUtil.class,"/templates");
            ITextRenderer renderer = new ITextRenderer();
            OutputStream out = new ByteArrayOutputStream();
            try {
                // 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
                renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                // 设置模板的编码格式
                cfg.setEncoding(Locale.CHINA, "UTF-8");
                // 获取模板文件 
                Template template = cfg.getTemplate(templateFileName, "UTF-8");
                StringWriter writer = new StringWriter();
                
                // 将数据输出到html中
                template.process(data, writer);
                writer.flush();
    
                String html = writer.toString();
                // 把html代码传入渲染器中
                renderer.setDocumentFromString(html);
    
                 // 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="images/xh.jpg"/>
                String url = PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString();
                renderer.getSharedContext().setBaseURL(url);
                renderer.layout();
                
                renderer.createPDF(out, false);
                renderer.finishPDF();
                out.flush();
                return (ByteArrayOutputStream)out;
            } finally {
            	if(out != null){
            		 out.close();
            	}
            }
        }
    }
    

    代码中需要注意路径设置,否则会导致css和图片引入无效

    • cfg.setClassForTemplateLoading(PdfUtil.class,"/templates"); 指定FreeMarker模板文件的位置

    • renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); 指定字体文件,否则中文不显示

    • PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString(); 指定模板中图片路径

    宋体字体下载: https://dl.pconline.com.cn/download/367689-1.html

    静态资源目录结构:

    3. 使用

    建议使用时,先写一个html静态页面,调试好了再复制到ftl文件中,保存成模板

    静态index.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <title></title>
        <style>
            .center{
                 380px;
                height: 538px;
                background: url("images/zs.png") center no-repeat;
                margin: 10% auto;
                font-family: SimSun;
                position: relative;
            }
            .name{
                position: absolute;
                top: 216px;
                left: 60px;
                font-size: 20px;
                 74px;
                text-align: center;
                display: block;
            }
        </style>
    </head>
    <body>
    <div class="center">
        <span class="name">李逍遥</span>
    </div>
    </body>
    </html>
    

    模板zhengshu.ftl

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8"/>
        <title></title>
        <style>
            .center{
                 380px;
                height: 538px;
                background: url("images/zs.png") center no-repeat;
                margin: 15% auto;
                font-family: SimSun;
                position: relative;
            }
            .name{
                position: absolute;
                top: 216px;
                left: 60px;
                font-size: 20px;
                 74px;
                text-align: center;
                display: block;
            }
        </style>
    </head>
    <body>
    <div class="center">
        <span class="name">${name}</span>
    </div>
    </body>
    </html>
    

    把需要设置数据的地方,用freemarker语法进行占位${}

    单元测试

    @Test
    public void pdf() throws IOException {
        ByteArrayOutputStream baos = null;
        FileOutputStream out = null;
        try {
            Map<String,Object> data = new HashMap<>();
            data.put("name", "李逍遥");
            baos = PdfUtil.createPDF(data, "zhengshu.ftl");
            String fileName = "获奖证书.pdf";
            File file = new File(fileName);
            out = new FileOutputStream(file);
            baos.writeTo(out);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(baos!=null){
                baos.close();
            }
            if(out != null){
                out.close();
            }
        }
    }
    

    使用controller

    mport java.io.ByteArrayOutputStream;
    import java.io.OutputStream;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.http.HttpServletResponse;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RequestMapping("/pdf")
    public class PdfController {
    	
    	@RequestMapping("/export")
    	public void exportPdf(HttpServletResponse response) throws Exception{
    		ByteArrayOutputStream baos = null;
    		OutputStream out = null;
    		try {
    			// 模板中的数据,实际运用从数据库中查询
    			Map<String,Object> data = new HashMap<>();
    			data.put("name", "李逍遥");
    			baos = PdfUtil.createPDF(data, "zhengshu.ftl");;
    			// 设置响应消息头,告诉浏览器当前响应是一个下载文件
    			response.setContentType( "application/x-msdownload");
    			// 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码 
    			String fileName = URLEncoder.encode("获奖证书.pdf", "UTF-8");
    			response.setHeader( "Content-Disposition", "attachment;filename=" + fileName);
    			out = response.getOutputStream();
    			baos.writeTo(out);
    			baos.close();
    		} catch (Exception e) {
    			e.printStackTrace();
    		    throw new Exception("导出失败:" + e.getMessage());
    		} finally{
    			if(baos != null){
    				baos.close();
    			}
    			if(out != null){
    				out.close();
    			}
    		}
    	}
    }
    

    4. 横向打印

    有时网页比较宽时,生成的pdf宽度不够,导致显示内容不完整,可以通过在模板css设置@page控制

    /*设置页面宽高 A4大小*/
    @page{size:297mm 210mm;}
    

    参考:

  • 相关阅读:
    meta 标签禁止缩放失效
    [UE4]打包EXE
    [UE4]Set Array Elem
    [UML]用例图
    [UE4]函数参数引用
    阻止移动鼠标双击页面放大, no double tap
    spring boot入门 -- 介绍和第一个例子
    SpringBoot 启动错误搜集
    spring boot 启动找不到或无法加载主类
    Spring Boot中Starter是什么
  • 原文地址:https://www.cnblogs.com/linyufeng/p/13402901.html
Copyright © 2011-2022 走看看