根据Velocity模板动态导出多语言PDF文件或流

背景:需要将数据填充到一个模板里面,根据这个模板生成pdf文件或者数据流。首先考虑的是AdobeAcrobat DC生成一个pdf模板,然后填充数据,但是考虑框中填充表格数据时,可能不满足动态数据撑开输入框,所以改用Velocity模板动态生成html转为PDF文件或者数据流

1.POM文件

		<!-- html转PDF -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>kernel</artifactId>
            <version>7.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>layout</artifactId>
            <version>7.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>html2pdf</artifactId>
            <version>2.0.1</version>
        </dependency>

2.准备Velocity模板

用法和Velocity模板使用方式是一致,附一个简单的模板样例
如果表格用<tfoot>,表格的每页都会显示底行,但是如果需要只是尾页显示表格底行,可以采用一个<tr>即可

<div class="sku-list">
     <table cellpadding="0" cellspacing="0" width="100%">
            <colgroup>
            	<col width="48"/>
                <col width="147"/>
                <col width="147"/>
                <col width="147"/>
                <col width="147"/>
                <col width="100"/>
                <col width="100"/>
                <col width="100"/>
             </colgroup>
             <thead>
                <tr>
                    <th class="left">$!printText.table.index</th>
                    <th></th>
                    <th class="left">$!printText.table.title1</th>
                    <th>$!printText.table.title2</th>
                    <th>$!printText.table.title3</th>
                    <th>$!printText.table.title4</th>
                    <th>$!printText.table.title5</th>
                    <th>$!printText.table.title6</th>
                  </tr>
              </thead>
              <tbody>
                  #if($!printInfo.data)
                     #foreach ($!print in $!printInfo.data)
                     	#set($index = $foreach.count)
                     		<tr>
	                        	<td class="left">$!{index}</td>
                                <td class="left">
                                	<img src="$!print.imgPath" width="60" height="60"/>
                          		</td>
                                <td class="left">$!print.name</td>
                               	<td>$!print.id</td>
                                <td>$!print.content1</td>
                                <td>$print.content2</td>
                                <td>$!print.content3</td>
                                <td>$!print.content4</td>
                        	</tr>
                       	#end
                   #end
              </tbody>
              <tr class="foot">
                   <td></td>
                   <td></td>
                   <td></td>
                   <td>$!printText.table.total</td>
                   <td></td>
                   <td>$!printInfo.contentOne</td>
                   <td>$!printInfo.contentTwo</td>
                   <td>$!printInfo.contentThree</td>
              </tr>
       </table>
</div>

3.准备多语言

yaml需要的包

		<dependency>
            <groupId>org.jyaml</groupId>
            <artifactId>jyaml</artifactId>
            <version>1.3</version>
        </dependency>

多语言的方式有很多,这里使用的是yaml方式做的多语言,通过Locale取的语言取出对应的文案

en_US:
  table:
    index: No.
    title1: t1
    title2: t2
    title3: t3
    title4: t4
    title5: t5
    title6: t6
    total: Total
zh_CN:
  table:
    index: No.
    title1: 标题1
    title2: 标题2
    title3: 标题3
    title4: 标题4
    title5: 标题5
    title6: 标题6
    total: Total

4.准备Velocity引擎工具

public class VelocityUtils {
    /**
     * 初始化velocity引擎
     *
     * @param path 模板所在路径
     */
    public static void initVelocityEngine(String path) {
        velocityEngine = new VelocityEngine();
        velocityEngine.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, path);// 这是模板所在路径
        velocityEngine.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
        //指定编码格式,避免生成模板就造成乱码,影响到转pdf后的文件
        velocityEngine.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
        velocityEngine.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
        velocityEngine.init();
    }

    /**
     *  得到模板引擎渲染数据后的写入器
     * @param templatePath 模板所在位置
     * @param paramMap 模板数据k-y
     * @return
     */
    public static Writer getWriterByTemplate(String templatePath, Map paramMap) {
        Writer writer =new StringWriter();
        Template template = velocityEngine.getTemplate(templatePath, "utf-8");
        VelocityContext context = new VelocityContext(paramMap);
        template.merge(context, writer);
        return writer;
    }
}

5.测试demo

测试生成html,查看样式是否满足要求,进行微调

  1. 准备基本数据

    //获取yaml多语言资源
    File file = new File( "/对应yaml文件的根路径/xxxx.yml");
    Map map = (Map) Yaml.load(file);
    String localStr = "en_US";
    
    //打印的数据源
    PrintInfo printInfo = new PrintInfo();
             
    Map paramValue = new ConcurrentHashMap();
    paramValue.put("printInfo",printInfo);
    paramValue.put("printText",map.get(localStr));
    
  2. 初始化引擎

     String path = "src/main/webapp/WEB-INF/vm";
     VelocityUtils.initVelocityEngine(path);
    
  3. 生成html文件进行微调

    OutputStream os = new FileOutputStream("/utils/test.html");
    int bytesRead = 0;
    byte[] buffer = new byte[8192];
    while ((bytesRead = in.read(buffer, 0, 8192)) != -1) {
    	os.write(buffer, 0, bytesRead);
    }
    

    生成pdf文件,可以使用
    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new FileOutputStream("/utils/test.pdf")));

  4. 生成base64字符串

    //生成字节输出流
    ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
    //放入pdf文本
    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(swapStream));
    
    //主要转化工具 html -> pdf
    HtmlConverter.convertToPdf(in,pdfDocument);
    //base64加密器
    Base64.Encoder encoder = Base64.getEncoder();
    //加密为base64字符串
    String base64 = encoder.encodeToString(swapStream.toByteArray());
    

6.最终方法

/**
 * 获取pdf的base64字符串
 *
 * @param templatePath 模板路径
 * @param paramValue html入参的参数
 * @return base64字符串
 * @throws Exception
 */
protected String getPDF2Base64Str(String templatePath, Map paramValue) throws Exception {
    //输入流
    Writer writer = VelocityUtils.getWriterByTemplate(templatePath, paramValue);
    InputStream in = new ByteArrayInputStream(writer.toString().getBytes(Charset.defaultCharset()));
    //字节输出流
    ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(swapStream));
    //html -> pdf
    HtmlConverter.convertToPdf(in, pdfDocument);
    //转化为base64字符串
    return Base64.getEncoder().encodeToString(swapStream.toByteArray());
}

如果需要根据base64字符串查看图片或文件什么样,可以用<iframe>,src用data:application/pdf;base64,+bae64字符串组合作为值,即可查看图片或文件,也可以直接data:application/pdf;base64,+bae64字符串组合放到浏览器上即可预览图片信息


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Velocity的能力远不止web站点开发这个领域,例如,它可以从模板(template)产生SQL和PostScript、XML,它也可以被当作一个独立工具来产生源代码和报告,或者作为其他系统的集成组件使用。Velocity也可以为Turbine web开发架构提供模板服务(template service)。Velocity+Turbine提供一个模板服务的方式允许一个web应用以一个真正的MVC模型进行开发。 Velocity能为我们作什么? The Mud Store Example 假设你是一家专门出售Mud的在线商店的页面设计人员,让我们暂且称它为“在线MUD商店”。你们的业务很旺,客户下了各种类型和数量的mud订单。他们都是通过输入用户名和密码后才登陆到你的网站,登陆后就允许他们查看订单并购买更多的mud。现在,一种非常流行的mud正在打折销售。另外有一些客户规律性的购买另外一种也在打折但是不是很流行的Bright Red Mud,由于购买的人并不多所以它被安置在页面的边缘。所有用户的信息都是被跟踪并存放于数据库中的,所以某天有一个问题可能会冒出来:为什么不使用 velocity来使用户更好的浏览他们感兴趣的商品呢? Velocity使得web页面的客户化工作非常容易。作为一个web site的设计人员,你希望每个用户登陆时都拥有自己的页面。 你会见了一些公司内的软件工程师,你发现他们每个人都同意客户应该拥有具有个性化的信息。那让我们把软件工程师应该作的事情发在一边,看一看你应该作些什么吧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值