Java PDF文件生成

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

方案:思路是通过本地的Excle模版和订单数据生成PDF文件。

先把数据填入到Excle模版中,然后通过Excle转为PDF文件,输出PDF文件。

Excle模版内容如下:

生成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文件内容如下所示:

猜你喜欢

转载自blog.csdn.net/robinson_911/article/details/105733504
今日推荐