使用freemarker+itextpdf,通过html模板导出PDF

本文介绍了如何使用Freemarker模板和iText库在Spring Boot中将HTML转换为PDF,包括依赖配置、HTML模板的编写和异常处理关键点。重点展示了如何处理模板变量的空值检查,以及如何通过字体包实现PDF输出。
摘要由CSDN通过智能技术生成

1.引入pom

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>7.1.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>layout</artifactId>
            <version>7.1.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>font-asian</artifactId>
            <version>7.1.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>3.0.2</version>
        </dependency>

2.编写html模板,这里需要注意所有的标签都需要有结束标签,并且需要对模板变量进行空处理,否则会直接抛出异常

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>Document</title>
  <style>
      h2 {
          text-align: center;
      }

      table {
          width: 100%;
          border-collapse: collapse;
      }

      td {
          padding: 10px;
          text-align: center;
          border: 1px solid black;
      }

      .leftTxt td {
          border: none;
          text-align: left;
      }
  </style>
</head>
<body>
<h2>采购订单</h2>

<table>
  <tr class="leftTxt">
    <td colspan="2"><b>供应商:</b>${(mchtName)!''} </td>
    <td colspan="2"><b>业务日期:</b>${(applyTime)!''} </td>
    <td colspan="2"><b>订单编号:</b>${(applyNo)!''} </td>
  </tr>
  <tr class="leftTxt">
    <td colspan="2"><b>采购员:</b>${(customerName)!''} </td>
    <td colspan="4"><b>收货地址:</b>${(receiverAddress)!''} </td>
  </tr>
  <tr>
    <td><b>产品类型</b></td>
    <td><b>产品名称</b></td>
    <td><b>数量</b></td>
    <td><b>计量单位</b></td>
    <td><b>含税单价(元)</b></td>
    <td><b>含税金额(元)</b></td>
  </tr>
    <#if productList?? && (productList?size >0)>
        <#list productList as product>
          <tr>
            <td>${(product.deviceModel)!''}</td>
            <td>${(product.productName)!''}</td>
            <td>${(product.deliverNums)!''}</td>
            <td>${(product.unit)!''}</td>
            <td>${(product.purchasePrice)!''}</td>
            <td>${(product.purchaseTotalPrice)!''}</td>
          </tr>
        </#list>
    </#if>
</table>
</body>
</html>

3.代码实现

1.)Controller代码

import freemarker.template.Template;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

@RestController
public class TestController {

  @Autowired
  private FreeMarkerConfigurer configurer;

  @Value("${nf.dc.pdf.fontPath:/opt/appl/spring-cloud/font}")
  private String fontPath;

  @GetMapping(value = "/apply_order/v1/get")
  public void exportTest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 准备数据
    Map<String, Object> dataMap = new HashMap();
    dataMap.put("applyNo", "测试");
    dataMap.put("mchtName", "测试");
    dataMap.put("applyTime", "测试");
    dataMap.put("customerName", "测试");
    dataMap.put("receiverAddress", "测试");
    List<ExportProductmentProductDto> productList = new ArrayList<>();
    ExportProductmentProductDto dto = new ExportProductmentProductDto();
    dto.setUnit("台");
    dto.setProductName("商品1");
    dto.setDeliverNums("10");
    dto.setPurchasePrice("200.00");
    dto.setDeviceModel("M-550");
    dto.setPurchaseTotalPrice("2000.00");
    productList.add(dto);
    productList.add(dto);
    productList.add(dto);
    dataMap.put("productList", productList);
    Template template = configurer.getConfiguration().getTemplate("productment.ftl");
    // 该路径用于本地测试使用
//    fontPath = "F://workspace/xxx/target/classes";
    ServletOutputStream out;
    response.setContentType("application/pdf");
    // 设置浏览器以下载的方式处理该文件
    response.setHeader("content-disposition", "attachment;filename=document.pdf");
    out = response.getOutputStream();
    PdfUtil.writeFile(dataMap, template, fontPath, out);
  }

2.)导出工具类代码

import com.itextpdf.html2pdf.ConverterProperties;
import com.itextpdf.html2pdf.HtmlConverter;
import com.itextpdf.io.font.PdfEncodings;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.font.FontProvider;
import freemarker.template.Template;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import javax.servlet.ServletOutputStream;
import lombok.extern.slf4j.Slf4j;

/**
 * PDF工具类
 */
@Slf4j
public class PdfUtil {

  /**
   * 创建pdf文件
   */
  public static void writeFile(Map<String, Object> paramMap, Template template, String fontPath, ServletOutputStream outPutStream) {

    log.info("开始创建pdf");
    long start = System.currentTimeMillis();

    try {
      Writer out = new StringWriter();
      // 合并数据模型与模板
      template.process(paramMap, out);
      out.flush();
      out.close();

      String html = out.toString();
      ConverterProperties props = new ConverterProperties();
      FontProvider fontProvider = new FontProvider();

      PdfFont ttcFont = PdfFontFactory.createTtcFont(fontPath + "/simsun.ttc", 1,
          PdfEncodings.IDENTITY_H, false, true);
      fontProvider.addFont(ttcFont.getFontProgram());
      props.setFontProvider(fontProvider);
      props.setCharset("utf-8");

      // 导出到本地
//      String fileName = fontPath + "/ABC.jpg";
//      File file = new File(fileName);
//      createDir(fileName);
//      FileOutputStream output = new FileOutputStream(file);

//      outPutStream = new ByteArrayOutputStream();

      PdfDocument pdf = new PdfDocument(new PdfWriter(outPutStream));
      pdf.setDefaultPageSize(PageSize.A4);
      Document document = HtmlConverter.convertToDocument(html, pdf, props);
      document.getRenderer().close();
      document.close();
      log.info("写入pdf完成,耗时: {}", System.currentTimeMillis() - start);
    } catch (Exception e) {
      log.error("writeFile", e);
      log.error("写入pdf失败: {}", e.getMessage());
    }
  }

  private static void createDir(String fileName) {
    File file = new File(fileName);
    if (!file.exists()) {
      try {
        file.getParentFile().mkdirs();
        file.createNewFile();
      } catch (IOException e) {
        return;
      }
    }
  }
}

3.)使用itext导出时需要自己引入一个字体包,如simsun.ttc,否则会抛出异常

 4.结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值