小工具      在线工具  汉语词典  css  js  c++  java

Java PDF文件生成

Java 额外说明

收录于:93天前

需求:根据订单数据生成 PDF 文件

解决方案:想法是通过本地Excel模板和订单数据生成PDF文件。

首先将数据填写到Excel模板中,然后通过Excel将其转换为PDF文件并输出PDF文件。

Excel模板的内容如下:

生成PDF所需的依赖如下:


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <poi.version>3.17</poi.version>
    </properties>        

     <!--excel转pdf依赖-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-collections4</artifactId>
            <version>4.1</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
        <dependency>
            <groupId>net.sf.jxls</groupId>
            <artifactId>jxls-core</artifactId>
            <version>1.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${poi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>${poi.version}</version>
        </dependency>

编写一个工具类FileUtils如下:

package com.robinboot.service.utils;

import com.alibaba.fastjson.JSON;
import com.itextpdf.text.*;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.*;
import com.robinboot.dto.TruckBrokerOrderDto;
import com.robinboot.utils.ServiceException;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * @author TF12778
 * @Date 2020/3/27
 */
public class FileUtils {

    private static final String TEMP_PATH = "/httx/run/temp/";

    public static byte[] excelToPdf(Map<String, Object> exportParam,
                                    String templatePath, boolean horizontal) throws Exception {

        InputStream in = FileUtils.class.getClassLoader().getResourceAsStream(templatePath);
        XLSTransformer transformer = new XLSTransformer();
        Workbook workbook = transformer.transformXLS(in, exportParam);

        Sheet sheet = workbook.getSheetAt(0);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        Document document = new Document();
        if (horizontal) {
            Rectangle pageSize = new Rectangle(PageSize.A4.getHeight(), PageSize.A4.getWidth());
            pageSize.rotate();
            document.setPageSize(pageSize);
        }
        PdfWriter writer = PdfWriter.getInstance(document, stream);
//        document.setMargins(0, 0, 15, 15);
        document.open();
        float[] widths = getColWidth(sheet);

        PdfPTable table = new PdfPTable(widths);
        table.setWidthPercentage(100);
        int colCount = widths.length;
        BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",
                BaseFont.NOT_EMBEDDED);

        for (int r = sheet.getFirstRowNum(); r < sheet.getPhysicalNumberOfRows(); r++) {
            Row row = sheet.getRow(r);
            if (row != null) {
                for (int c = row.getFirstCellNum(); (c < row.getLastCellNum() || c < colCount) && c > -1; c++) {
                    if (c >= row.getPhysicalNumberOfCells()) {
                        PdfPCell pCell = new PdfPCell(new Phrase(""));
                        pCell.setBorder(0);
                        table.addCell(pCell);
                        continue;
                    }
                    Cell excelCell = row.getCell(c);
                    String value = "";

                    if (excelCell != null) {
                        value = excelCell.toString().trim();
                        if (value != null && value.length() != 0) {
                            //获取excel单元格数据显示样式
                            String dataFormat = excelCell.getCellStyle().getDataFormatString();
                            if (dataFormat != "General" && dataFormat != "@") {
                                try {
                                    String numStyle = getNumStyle(dataFormat);
                                    value = numFormat(numStyle, excelCell.getNumericCellValue());
                                } catch (Exception e) {

                                }
                            }
                        }
                    }
                    org.apache.poi.ss.usermodel.Font excelFont = getExcelFont(excelCell);

                    Font pdFont = new Font(baseFont, excelFont.getFontHeightInPoints(), Font.NORMAL,
                            BaseColor.BLACK);
                    PdfPCell pCell = new PdfPCell(new Phrase(value, pdFont));
                    boolean hasBorder = hasBorder(excelCell);
                    if (!hasBorder) {
                        pCell.setBorder(0);
                    }
                    pCell.setHorizontalAlignment(getHorAglin(excelCell.getCellStyle().getAlignment()));
                    pCell.setVerticalAlignment(getVerAglin(excelCell.getCellStyle().getVerticalAlignment()));
                    pCell.setUseAscender(true);
                    pCell.setMinimumHeight(row.getHeightInPoints());
                    if (isMergedRegion(sheet, r, c)) {
                        int[] span = getMergedSpan(sheet, r, c);
                        //忽略合并过的单元格
                        if (span[0] == 1 && span[1] == 1) {
                            continue;
                        }
                        pCell.setRowspan(span[0]);
                        pCell.setColspan(span[1]);
                        //合并过的列直接跳过
                        c = c + span[1] - 1;
                    }
                    table.addCell(pCell);
                }
            } else {
                PdfPCell pCell = new PdfPCell(new Phrase(""));
                pCell.setBorder(0);
                pCell.setMinimumHeight(13);
                table.addCell(pCell);
            }
        }
        document.add(table);
        document.close();
        writer.close();

        byte[] pdfByte = stream.toByteArray();
        stream.flush();
        stream.reset();
        stream.close();

        return pdfByte;
    }

    /**
     * * 获取excel中每列宽度的占比
     * * @param sheet
     * * @return
     */
    private static float[] getColWidth(Sheet sheet) {
        int rowNum = getMaxColRowNum(sheet);
        Row row = sheet.getRow(rowNum);
        int cellCount = row.getPhysicalNumberOfCells();
        int[] colWidths = new int[cellCount];
        int sum = 0;

        for (int i = row.getFirstCellNum(); i < cellCount; i++) {
            Cell cell = row.getCell(i);
            if (cell != null) {
                colWidths[i] = sheet.getColumnWidth(i);
                sum += sheet.getColumnWidth(i);
            }
        }

        float[] colWidthPer = new float[cellCount];
        for (int i = row.getFirstCellNum(); i < cellCount; i++) {
            colWidthPer[i] = (float) colWidths[i] / sum * 100;
        }
        return colWidthPer;
    }

    /**
     * 获取字体
     *
     * @param cell
     * @return
     */
    private static org.apache.poi.ss.usermodel.Font getExcelFont(Cell cell) {
        return ((XSSFCell) cell).getCellStyle().getFont();
    }

    /**
     * 判断excel单元格是否有边框
     *
     * @param excelCell
     * @return
     */
    private static boolean hasBorder(Cell excelCell) {
        BorderStyle top = excelCell.getCellStyle().getBorderTopEnum();
        BorderStyle bottom = excelCell.getCellStyle().getBorderBottomEnum();
        BorderStyle left = excelCell.getCellStyle().getBorderLeftEnum();
        BorderStyle right = excelCell.getCellStyle().getBorderRightEnum();
        return top.getCode() + bottom.getCode() + left.getCode() + right.getCode() > 2;
    }

    /**
     * 获取excel单元格数据显示格式
     *
     * @param dataFormat
     * @return
     * @throws Exception
     */
    private static String getNumStyle(String dataFormat) throws Exception {
        if (dataFormat == null || dataFormat.length() == 0) {
            throw new Exception("");
        }
        if (dataFormat.indexOf("%") > -1) {
            return dataFormat;
        } else {
            return dataFormat.substring(0, dataFormat.length() - 2);
        }
    }

    /**
     * 判断单元格是否是合并单元格
     *
     * @param sheet
     * @param row
     * @param column
     * @return
     */
    private static boolean isMergedRegion(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 计算合并单元格合并的跨行跨列数
     *
     * @param sheet
     * @param row
     * @param column
     * @return
     */
    private static int[] getMergedSpan(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        int[] span = {1, 1};
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (firstColumn == column && firstRow == row) {
                span[0] = lastRow - firstRow + 1;
                span[1] = lastColumn - firstColumn + 1;
                break;
            }
        }
        return span;
    }

    /**
     * 获取excel中列数最多的行号
     *
     * @param sheet
     * @return
     */
    private static int getMaxColRowNum(Sheet sheet) {
        int rowNum = 0;
        int maxCol = 0;
        for (int r = sheet.getFirstRowNum(); r < sheet.getPhysicalNumberOfRows(); r++) {
            Row row = sheet.getRow(r);
            if (row != null && maxCol < row.getPhysicalNumberOfCells()) {
                maxCol = row.getPhysicalNumberOfCells();
                rowNum = r;
            }
        }
        return rowNum;
    }

    /**
     * excel垂直对齐方式映射到pdf对齐方式
     *
     * @param aglin
     * @return
     */
    private static int getVerAglin(short aglin) {
        switch (aglin) {
            case 1:
                return com.itextpdf.text.Element.ALIGN_MIDDLE;
            case 2:
                return com.itextpdf.text.Element.ALIGN_BOTTOM;
            case 3:
                return com.itextpdf.text.Element.ALIGN_TOP;
            default:
                return com.itextpdf.text.Element.ALIGN_MIDDLE;
        }
    }

    /**
     * excel水平对齐方式映射到pdf水平对齐方式
     *
     * @param aglin
     * @return
     */
    private static int getHorAglin(short aglin) {
        switch (aglin) {
            case 2:
                return com.itextpdf.text.Element.ALIGN_CENTER;
            case 3:
                return com.itextpdf.text.Element.ALIGN_RIGHT;
            case 1:
                return com.itextpdf.text.Element.ALIGN_LEFT;
            default:
                return com.itextpdf.text.Element.ALIGN_CENTER;
        }
    }

    /**
     * 格式化数字
     *
     * @param pattern
     * @param num
     * @return
     */
    private static String numFormat(String pattern, double num) {
        DecimalFormat format = new DecimalFormat(pattern);
        return format.format(num);
    }

    public static int getPage(String fileId) {
        int pages = 1;
        PdfReader pdfReader = null;
        String localFilePath = "";
        try {
            localFilePath = FileUtils.genLocalFilePath(fileId);
            FileUtils.downLoadNetFile("https://www.com/fastdfsWeb/dfs/" + fileId, localFilePath);

            FileInputStream fileInputStream = new FileInputStream(localFilePath);
            pdfReader = new PdfReader(fileInputStream);
            pages = pdfReader.getNumberOfPages();
            if (pages <= 1) {
                return 1;
            }
        } catch (Exception e) {
            System.out.println("read page error");
            System.out.println(e);
            // 以防万一 读取报错
            pages = 1000;
        } finally {
            if(pdfReader != null) {
                pdfReader.close();
            }
            FileUtils.deleteDir(localFilePath);
        }
        return pages;
    }

    public static String upload(InputStream inputStream, long fileSize, String ext, Map<String, String> meta) {
        try {
//            return FastDFSUtil.upload(inputStream, fileSize, ext, meta);
            return null;
        } catch (Exception e) {
//            log.info("[UploadFileUtil --> upload]  is error, error is:{}", e);
//            throw new BizException("上传失败");
            throw new ServiceException("上传失败", "500");
        }
    }

    public static void downLoadNetFile(String netUrl, String localPath) throws Exception {
        // 下载网络文件
        int bytesum = 0;
        int byteread = 0;

        URL url = new URL(netUrl);
        InputStream inStream = null;
        FileOutputStream fs = null;
        try {
            URLConnection conn = url.openConnection();
            inStream = conn.getInputStream();
            fs = new FileOutputStream(localPath);

            byte[] buffer = new byte[2048];
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
            }
            inStream.close();
            fs.flush();
            fs.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inStream != null) {
                    inStream.close();
                }
                if (fs != null) {
                    fs.close();
                }
            } catch (Exception e) {
            }
        }
    }

    public static String genLocalFilePath(String remoteFilePath) {
//        AssertUtil.notEmpty(remoteFilePath, "远程文件路径不能为空");
        if (StringUtils.isBlank(remoteFilePath)) {
            throw new ServiceException("远程文件路径不能为空", "500");
        }
        String[] remoteFilePathArray = remoteFilePath.split("/");
        if (remoteFilePathArray.length == 0) {
            throw new ServiceException("远程文件路径不能为空", "500");
        }
//        AssertUtil.notEmpty(remoteFilePathArray, "远程文件路径不正确,提取文件名后缀失败");

        //文件(文件名+后缀)
        String file = remoteFilePathArray[remoteFilePathArray.length - 1];

        file = file.split("\\?")[0];

        file = file.split("\\.")[0].concat(".").concat(file.split("\\.")[1]);

        //文件路径
        String localFilePath = TEMP_PATH.concat(file);

        return localFilePath;
    }

    public static void deleteDir(String dirPath) {
        File file = new File(dirPath);
        if (file.isFile()) {
            file.delete();
        } else {
            File[] files = file.listFiles();
            if (files == null) {
                file.delete();
            } else {
                for (int i = 0; i < files.length; i++) {
                    deleteDir(files[i].getAbsolutePath());
                }
                file.delete();
            }
        }
    }
}

测试如下:

public class LJPDFTest extends LJTest {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Test
    public void pdfTest() {
        try {
            List<OrderDto> list = JSON.parseArray("[{\"auditStatus\":0,\"bankCardStatus\":0,\"billStatus\":0,\"cancelDate\":1585376549000,\"cancelMemo\":\"列表,取消订单,20032814215320001\",\"cancelType\":1,\"customerCode\":\"568146143\",\"driverFreight\":2000.00,\"driverMobile\":\"17700008810\",\"driverName\":\"李国风\",\"driverPartyId\":568103143,\"driverTotalFreight\":2000.00,\"fromAddress\":\"安徽芜湖市);

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
            SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Map<String, Object> exportParam = new HashMap<>();
            exportParam.put("list", list);
            exportParam.put("applyTime", sdf.format(new Date()));
            exportParam.put("signMobile", "13421678621");
            exportParam.put("count", list.size());
            exportParam.put("amount", "9999.08");
            exportParam.put("company", "浙江大神有限公司");
            exportParam.put("df", df);
            byte[] bytes = FileUtils.excelToPdf(exportParam, "template/account.xlsx", true);
            String fileId = FileUtils.upload(new ByteArrayInputStream(bytes), bytes.length, "pdf", null);
            System.out.println("=========================" + fileId);
//            System.out.println("=========================" + SignUtil.addSign4Url(FAST_DFS + fileId));

            FileOutputStream fileOutputStream = new FileOutputStream(new File("/Users/sunww/Desktop/对账单.pdf"));
            fileOutputStream.write(bytes);
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后就可以在桌面上看到PDF文件的内容了,如下:

. . .

相关推荐

额外说明

一名阿里服务端开发工程师的进阶之路

一名阿里服务端开发工程师的进阶之路 一、前言 目前,资讯、社交、游戏、消费、出行等丰富多彩的互联网应用已经渗透到了人们生活和工作的方方面面,正深刻改变着信息时代。随着用户规模的增长和应用复杂度的上升,服务端面临的技术挑战越来越严峻。在头部互联网企业,服务

额外说明

Unity3d——构建真实地形

QQ 1285575001 Wechat M010527 技术交流 QQ群599020441 纪年科技aming 构建真实地形 战争题材或者模拟飞行类型的游戏,经常要构建真实的地形地貌 方法1:利用Unity插件—WorldComposer 1、申请Bi

额外说明

【Unity3D进阶4-2】Unity3D A*寻路算法

一、目录 【Unity3D从入门到进阶】文章目录及设置这个专栏的初衷 二、A*寻路原理分析 假设我们有一个人想从A点到B点,假设两点之间有一道墙。如下所示,绿色是起点A,红色是结束点B,蓝色填充的方块是中间的墙。 如图所示简易地图, 其中绿色方块的是起点

额外说明

开源项目中的 Java 异常处理示例

开源项目中的 Java 异常处理示例 本文译自:Java Exception Handling Examples in Open Source Projects 在“ Effective Java ”中,Joshua Bloch 写了关于如何在 Java

额外说明

JVM实战:内存溢出的定位与分析

文章目录 模拟内存溢出 运行测试 导入到MAT工具中进行分析 内存溢出在实际的生产环境中经常会遇到,比如,不断的将数据写入到一个集合中,出现了死循环,读取超大的文件等等,都可能会造成内存溢出。 如果出现了内存溢出,首先我们需要定位到发生内存溢出的环节,并

额外说明

什么是低代码

文章目录 no code / low code / pro code 按适用范围的维度来分类 低代码的技术意义与商业价值 技术意义 商业价值 行业状态速读 平台分类 不同的实现方式 不同的使用群体 不同的使用方式 优秀开源项目推荐 no code / l

额外说明

JS中的增删改 -splice的用法

今天开始学习JS,JS和Java基础部分很相似。主要是一些方法的记忆,下面总结几个有关数组增删改的方法: 一、增 push(i):末位加上i unshift(i):头部加上i 二、删 pop() splice(i,j) 第i个位置开始删除j个数 shif

额外说明

wordpress表格筛选_如何在WordPress博客文章中嵌入PDF,电子表格等

wordpress 表过滤器 您想在 WordPress 博客文章中嵌入 PDF、电子表格和其他类型的文档吗? 您想在 WordPress 博客文章中嵌入 PDF、电子表格和其他类型的文档吗? WordPress comes with a powerfu

额外说明

稳定低保唯品会搬运得物,小副业轻松月入过千详细教程

标题:分享一份月薪轻松过千的小副业,以及唯品会转稳定低保的详细教程 文本: 随着互联网时代的到来,越来越多的人试图通过小型副业来增加收入。在这篇文章中,我将分享一个有稳定低保的小副业,那就是把唯品会产品搬到得物平台上。通过这个方法,你可以轻松月入千余。接

额外说明

您应该了解的一些跨领域问题和解决方案

应该了解的一些跨越问题和解决方法 同源策略 在遇到跨域问题的时候,我们首先应该想到的就是同源政策这个概念。同源策略 same-origin policy,在1995年由 Netspace 公司引入浏览器的一种安全策略,现在市面上的所有浏览器都必须遵守同源

ads via 小工具