记一次动态插入数据到excel并且转pdf导出(JAVA)

需求
    这次接到的任务是,将客户的资料动态写入到pdf文档中并下载。大体效果如下。
    
   
需求分析
    划重点,需求主要的是动态填充数据(譬如用户有三张银行卡,那么就需要循环插入数据)、并且导出后的文档格式是PDF。所以难度是在动态填充里面,其次是PDF,至于用户名这种固定的,直接占位符替换即可。如果直接在PDF进行数据填充,是否可以呢?答案是可以,但是动态填充的话,涉及到格式以及样式问题,就不好实现了。那咋整呢,我们可以曲线一下,先把数据填充到Excel模板,然后再把Excel文件转成PDF。所以整体可以拆到两步。
(ps:可能有些同学会问,直接整个Excel自己手写是否可以呢,也可以,但还是样式问题,不如模板 填充的形式更方便快捷。主要是自己懒得写样式)
1-找到支持动态插入数据到Excel的框架。
2-找Excel转PDF的框架。

EXCEL动态插入数据技术方案
1.Apache POI
Apache POI 是一个开源的 Java 库,用于读取和写入 Microsoft Office 格式的文件,例如 Excel(.xls 和 .xlsx)、Word(.doc 和 .docx)以及 PowerPoint(.ppt 和 .pptx)文件。
 优点
  .功能强大提供了丰富的 API,能够满足对 Office 文件的各种操作需求,如读写、格式设置、公式计算等。
   支持多种文件格式(.xls、.xlsx、.doc、.docx、.ppt、.pptx),几乎涵盖了所有常见的 Microsoft Office 文件类型。
    完全基于 Java 编写,不依赖于外部的 Microsoft Office 软件。这意味着它可以在没有安装 Microsoft Office 的环境中运行,减少了对环境的依赖。
 缺点
  .不能根据模板插入数据,尤其是循环插入的情况下。
2.esaypoi
  也是个开源框架,主要是支持根据占位符替换数据,且可以动态插入数据。完美。
但是,这玩意有个比较坑的地方,多个fe (循环)标签。就会出现莫名其妙的BUG,,会报【for each 当中存在空字符串,请检查模板】。整整花了2天的时间,后面实在没办法。直接放弃。
3.阿里的esayExcel
  免费开源,容易上手,但它对单元格的合并很不友好。加上升级框架对于现有项目的改动很大,然后放弃、、。(项目使用的是springbootcloud 架构)
4.Jxls
  JXLS‌是一个轻量级的Java库,主要用于基于模板的Excel报表生成。它通过在Excel模板中使用特定的标记或注释来定义数据的输出格式和布局,从而避免了编写大量重复且易出错的代码,特别适合处理复杂的Excel导出需求,如固定样式、合并单元格和动态列等‌。xlsx文件的模板如下


.其中第一个注释必须写在第一个单元格,内容是【jx:area(lastCell=“K6”)】,其中K6代表整体区域的最后一个位置,可相应的修改
.第二个注释【jx:each(items=“data”,var=“cell”,lastCell=“K5”)】代表将data里的列表数据进行循环,每一个为cell对象,生效范围一直到K5位置
.${name}  这种就是单纯的占位符替换了。
写代码的时候,
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "xxxxxx");
List<xxxxx> data= new ArrayList();
map.put("data",data);

代码中的name 就是对应的 ${name}了。
data 对应的就是循环里面的data 

我这里只是用到了部分功能、其他的功能使用建议自行查询。

模板内容讲解完毕后,就可以上代码了。
 首先是jxls的pom.xml

        <!-- jxls begin -->
        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls</artifactId>
            <version>2.8.0</version>
            <exclusions>
                <exclusion>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-poi</artifactId>
            <version>2.8.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi-ooxml</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.apache.poi</groupId>
                    <artifactId>poi</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.jxls</groupId>
            <artifactId>jxls-jexcel</artifactId>
            <version>1.0.9</version>
        </dependency>

        <!--根据jxls-cor-1.0.6修改,支持poi4.x版本-->
        <dependency>
            <groupId>net.sf.jxls</groupId>
            <artifactId>jxls-core</artifactId>
            <version>1.0.4</version>
        </dependency>

工具类

import org.jxls.common.Context;
import org.jxls.transform.Transformer;
import org.jxls.util.JxlsHelper;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

public class JxlsUtils{
     
    private static final String TEMPLATE_PATH="jxls-template";
     
    public static void exportExcel(InputStream is, OutputStream os, Map<String, Object> model) throws IOException {
        Context context = new Context();
        if (model != null) {
            for (String key : model.keySet()) {
                context.putVar(key, model.get(key));
            }
        }
        JxlsHelper jxlsHelper = JxlsHelper.getInstance();
        Transformer transformer  = jxlsHelper.createTransformer(is, os);
        //JexlExpressionEvaluator evaluator = (JexlExpressionEvaluator)transformer.getTransformationConfig().getExpressionEvaluator();
        //Map<String, Object> funcs = new HashMap<>();
      //  funcs.put("utils", new JxlsUtils());    //添加自定义功能
      //  evaluator.getJexlEngine().setFunctions(funcs);
        jxlsHelper.processTemplate(context, transformer);
    }
 
    public static void exportExcel(File xls, File out, Map<String, Object> model) throws FileNotFoundException, IOException {
            exportExcel(new FileInputStream(xls), new FileOutputStream(out), model);
    }
     
    public static void exportExcel(String templateName, OutputStream os, Map<String, Object> model) throws FileNotFoundException, IOException {
        File template = getTemplate(templateName);
        if(template!=null){
            exportExcel(new FileInputStream(template), os, model);    
        }
    }
     
     
    //获取jxls模版文件
 
    public static File getTemplate(String name){
        String templatePath = JxlsUtils.class.getClassLoader().getResource(TEMPLATE_PATH).getPath();
        File template = new File(templatePath, name);
        if(template.exists()){
            return template;
        }
        return null;
    }    
     
    // 日期格式化
    public String dateFmt(Date date, String fmt) {
        if (date == null) {
            return "";
        }
        try {
            SimpleDateFormat dateFmt = new SimpleDateFormat(fmt);
            return dateFmt.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
     
    // if判断
    public Object ifelse(boolean b, Object o1, Object o2) {
        return b ? o1 : o2;
    }
     
}

 excel转pdf技术方案
.Spire ,功能强大,直接几行代码转DF, 但是免费版只能转3页,超过3页会出现提示。。。
.aspose 功能强大,上手简单,虽然收费但是网上免费资源较多(自行体会)。
自然而然得选择了aspose

上代码
附上asposepom.xml(ps:这个jar需要自己下载,然后放到项目里面引用的。)

       <dependency>
            <groupId>com.aspose</groupId>
            <artifactId>aspose-cells</artifactId>
            <version>8.5.2</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/../file/lib/aspose-cells-8.5.2.jar</systemPath>
        </dependency>

附上导出代码——将上面的excel转换成PDF
 

Map<String, Object> map = new HashMap<String, Object>();
        //设置参数,excel是模板填充
        map.put("services",service);
        // excel 路径
        URL url=new URL("http://xxxxxxxx);
        
        String fileName = URLEncoder.encode("文件名.pdf", CharsetUtil.UTF_8);
        response.reset();
        response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
        response.setContentType("application/octet-stream;charset=UTF-8");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();


        InputStream inputStream1 = url.openStream();
        log.info("开始导出excel============================时间为:"+DateUtil.format(new Date(),"yyyy-MM-dd HH:ss:mm"));
        JxlsUtils.exportExcel(inputStream1,outputStream,map);
        log.info("结束导出excel============================时间为:"+DateUtil.format(new Date(),"yyyy-MM-dd HH:ss:mm"));
        

        log.info("开始导出pdf============================时间为:"+DateUtil.format(new Date(),"yyyy-MM-dd HH:ss:mm"));
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        ServletOutputStream responseOutputStream = response.getOutputStream();
        Excel2Pdf.excel2pdf(inputStream,responseOutputStream);

        log.info("结束导出pdf============================时间为:"+DateUtil.format(new Date(),"yyyy-MM-dd HH:ss:mm"));

        responseOutputStream.flush();
        responseOutputStream.close();
        inputStream.close();
        inputStream1.close();
        outputStream.flush();
        outputStream.close();

补上 Excel2Pdf 工具类
 

import com.aspose.cells.License;
import com.aspose.cells.SaveFormat;
import com.aspose.cells.Workbook;

import javax.servlet.ServletOutputStream;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

/**
 * 
 * @version 1.0.0
 * @ClassName Excel2Pdf
 * @Description
 * @createTime 2022年10月23日
 */
public class Excel2Pdf {

    public static boolean getLicense() {
        boolean result = false;
        try {
            InputStream is = Excel2Pdf.class.getClassLoader().getResourceAsStream("xlsxlicense.xml"); //  license.xml应放在..WebRootWEB-INFclasses路径下
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void excel2pdf(ByteArrayInputStream inputStream, ServletOutputStream responseOutputStream) {
        if (!getLicense()) {          // 验证License 若不验证则转化出的pdf文档会有水印产生
            return;
        }
        try {
            Workbook wb = new Workbook(inputStream);// 原始excel路径
            wb.save(responseOutputStream, SaveFormat.PDF);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
以下是 xlsxlicense.xml

<License>
  <Data>
    <Products>
      <Product>Aspose.Total for Java</Product>
      <Product>Aspose.Words for Java</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SubscriptionExpiry>20991231</SubscriptionExpiry>
    <LicenseExpiry>20991231</LicenseExpiry>
    <SerialNumber>8bfe198c-7f0c-4ef8-8ff0-acc3237bf0d7</SerialNumber>
  </Data>
  <Signature>sNLLKGMUdF0r8O1kKilWAGdgfs2BvJb/2Xp8p5iuDVfZXmhppo+d0Ran1P9TKdjV4ABwAgKXxJ3jcQTqE/2IRfqwnPf8itN8aFZlV3TJPYeD3yWE7IT55Gz6EijUpC7aKeoohTb4w2fpox58wWoF3SNp6sK6jDfiAUGEHYJ9pjU=</Signature>
</License>

至此,收工,有问题欢迎留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值