一个案例教你使用java生成pdf文件

339 阅读4分钟

案例

一、引入依赖

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>easyexcel</artifactId>
   <version>2.2.6</version>
</dependency>

二、创建模板excel文件,放入工程中

image.png

三、编写代码

/**
 * @author: huangshuai
 * @Description 打印装车清单
 * @date 2021/9/7 11:50
 */
public class PrintLoadedWagons {

    //指定装车清单模板文件路径
    private static final String MODE_FILE_PATH = "templates/装车清单模板.xlsx";

    //往excel填充的数据
    private Map<String, Object> dataMap;

    public PrintLoadedWagons(Map<String, Object> dataMap) {
        this.dataMap = dataMap;
    }

    /**
     * 生成pdf文件
     */
    public boolean generatePsPdfFile() {
        InputStream modelFileIn = null;
        ByteArrayInputStream swapStream = null;
        ByteArrayOutputStream outputStream = null;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
        ByteArrayInputStream printStream = null;
        ByteArrayInputStream bis = null;
        InputStream imageStream = null;

        try {
            modelFileIn = FileUtil.getResourcesStream(MODE_FILE_PATH);
            ExcelWriter excelWriter = EasyExcel.write(baos).withTemplate(modelFileIn).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            excelWriter.fill(dataMap, writeSheet);
            excelWriter.finish();
            //excel文件的输入流
            swapStream = new ByteArrayInputStream(baos.toByteArray());
            BufferedImage bufferedImage = BarcodeUtils.insertWords(BarcodeUtils.getBarCode(dataMap.get("batch").toString(), 220, 80), "*" + dataMap.get("batch").toString() + "*");
            imageStream = getImageStream(bufferedImage);
            //将条形码图片插入到excel中
            outputStream = insBarcodeInExcel(imageStream, swapStream);
            bis = new ByteArrayInputStream(outputStream.toByteArray());
            //将excel转为pdf
            Excel2PdfUtil.excel2pdf(bis, bos2);
            printStream = new ByteArrayInputStream(bos2.toByteArray());
         
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (baos != null) {
                    baos.close();
                }

                if (bos2 != null) {
                    bos2.close();
                }

                if (swapStream != null) {
                    swapStream.close();
                }

                if (imageStream != null) {
                    imageStream.close();
                }

                if (outputStream != null) {
                    outputStream.close();
                }

                if (bis != null) {
                    bis.close();
                }

                if (printStream != null) {
                    printStream.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    /**
     * @param imageInput  条形码图片的输入流
     * @param sourceInput excel文件的输入流
     */
    public static ByteArrayOutputStream insBarcodeInExcel(InputStream imageInput, InputStream sourceInput) {
        XSSFWorkbook wb = null;
        XSSFSheet sheet = null;
        ByteArrayOutputStream baos = null;
        try {
            wb = new XSSFWorkbook(sourceInput);
            sheet = wb.getSheetAt(0);
            byte[] bytes = IOUtils.toByteArray(imageInput);
            int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
            CreationHelper helper = wb.getCreationHelper();
            ClientAnchor anchor = helper.createClientAnchor();
            anchor.setCol1(2);//设置条形码的横坐标位置
            anchor.setRow1(40);//设置条形码的纵坐标位置
            Picture pict = sheet.createDrawingPatriarch().createPicture(anchor, pictureIdx);
            pict.resize();
            baos = new ByteArrayOutputStream();
            wb.write(baos);
            return baos;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (imageInput != null) {
                    imageInput.close();
                }
                if (sourceInput != null) {
                    sourceInput.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将BufferedImage转为InputStream
     */
    public static InputStream getImageStream(BufferedImage bimage) {
        InputStream is = null;
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageOutputStream imOut;
        try {
            imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(bimage, "jpg", imOut);
            is = new ByteArrayInputStream(bs.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return is;
    }
}

excel转成pdf的工具类如下:

public class Excel2PdfUtil {

    public static void excel2pdf(InputStream sourceFileStream, OutputStream destFileStream) {
        if (!getLicense()) { // 验证License 若不验证则转化出的pdf文档会有水印产生
            return;
        }
        try {
            Workbook wb = new Workbook(sourceFileStream);// 原始excel路径

            PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
            pdfSaveOptions.setOnePagePerSheet(false);

            int[] autoDrawSheets = {3};
            //当excel中对应的sheet页宽度太大时,在PDF中会拆断并分页。此处等比缩放。
//            autoDraw(wb,autoDrawSheets);

            int[] showSheets = {0};
            //隐藏workbook中不需要的sheet页。
            printSheetPage(wb, showSheets);
            wb.save(destFileStream, pdfSaveOptions);
            destFileStream.flush();
            destFileStream.close();

        } catch (Exception e) {
            throw new RuntimeException("Excel转PDF异常!", e);
        }
    }

    /**
     * 获取license 去除水印
     *
     * @return
     */
    private static boolean getLicense() {
        boolean result = false;
        try {
            InputStream is = Excel2PdfUtil.class.getClassLoader().getResourceAsStream("\license.xml");
            License aposeLic = new License();
            aposeLic.setLicense(is);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    


    /**
     * 隐藏workbook中不需要的sheet页。
     *
     * @param wb
     * @param page 显示页的sheet数组
     */
    private static void printSheetPage(Workbook wb, int[] page) {
        for (int i = 1; i < wb.getWorksheets().getCount(); i++) {
            wb.getWorksheets().get(i).setVisible(false);
        }
        if (null == page || page.length == 0) {
            wb.getWorksheets().get(0).setVisible(true);
        } else {
            for (int i = 0; i < page.length; i++) {
                wb.getWorksheets().get(i).setVisible(true);
            }
        }
    }
}

生成条形码和二维码的工具类如下:

/**
 * @author: huangshuai
 * @Description 生成条形码工具类
 * @date 2021/7/26 10:48
 */
public class BarcodeUtils {

    private static final String CHARSET = "utf-8";

    /**
     * 条形码宽度
     */
    private static final int WIDTH = 220;
    /**
     * 条形码高度
     */
    private static final int HEIGHT = 80;

    /**
     * 字体大小
     */
    private static final int FONT_SIZE = 28;

    /**
     * 加文字 条形码
     */
    private static final int WORD_HEIGHT = HEIGHT + FONT_SIZE;

    /**
     * 文字间距
     */
    private static final int WORD_DISTANCE = 17;

    /**
     * 文字编写相对纵坐标
     */
    private static final int WORD_Y = 21;


    /**
     * 设置 条形码参数
     */
    private static Map<EncodeHintType, Object> hints = new HashMap<>(5);

    static {
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
    }

    /**
     * 生成条形码图片
     * @param vaNumber 条形码的内容
     * @param width    条形码的宽度
     * @param height   条形码的高度
     */
    public static BufferedImage getBarCode(String vaNumber, int width, int height) {
        try {
            Code128Writer writer = new Code128Writer();
            // 编码内容, 编码类型, 宽度, 高度, 设置参数
            BitMatrix bitMatrix = writer.encode(vaNumber, BarcodeFormat.CODE_128, width, height, hints);
            return MatrixToImageWriter.toBufferedImage(bitMatrix);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 图片下边插入文字,并且文字与图片对齐
     * @param image 条形码图片
     * @param words 待插入的文字
     */
    public static BufferedImage insertWords(BufferedImage image, String words) {
        // 新的图片,把带logo的二维码下面加上文字
        if (!StringUtils.isEmpty(words)) {
            BufferedImage outImage = new BufferedImage(WIDTH, WORD_HEIGHT, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = outImage.createGraphics();
            // 抗锯齿
            setGraphics2D(g2d);
            // 设置白色
            setColorWhite(g2d);
            // 画条形码到新的面板
            g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
            // 画文字到新的面板
            g2d.setColor(Color.BLACK);
            // 字体、字型、字号
            g2d.setFont(new Font("黑体", Font.PLAIN, FONT_SIZE));
            int wordStartY = HEIGHT + 21;
            String content = words.substring(1, words.length() - 1);
            int inputWidth = new Code128Writer().encode(content).length;
            int fullWidth = inputWidth + 1;
            int outputWidth = Math.max(WIDTH, fullWidth);
            int multiple = outputWidth / fullWidth;
            int leftPadding = (outputWidth - (inputWidth * multiple)) / 2;
            int x = leftPadding;
            String[] split = words.split("");
            int len = split.length;
            int step = new Long(Math.round(WIDTH - leftPadding * 2) / words.length()).intValue();
            for (int i = 0; i < len; i++) {
                g2d.drawString(split[i], x, wordStartY);
                x = x + step;
            }
            outImage.flush();
            return outImage;
        }
        return null;
    }


    /**
     * 设置 Graphics2D 属性 (抗锯齿)
     *
     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
     */
    private static void setGraphics2D(Graphics2D g2d) {
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_DEFAULT);
        Stroke s = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
        g2d.setStroke(s);
    }

    /**
     * 设置背景为白色
     *
     * @param g2d Graphics2D提供对几何形状、坐标转换、颜色管理和文本布局更为复杂的控制
     */
    private static void setColorWhite(Graphics2D g2d) {
        g2d.setColor(Color.WHITE);
        // 填充整个屏幕
        g2d.fillRect(0, 0, 600, 600);
        // 设置笔刷
        g2d.setColor(Color.BLACK);
    }

    /**
     * 将imageInput图片输入流插入到excel文件中
     * @param imageInput  条形码图片的输入流
     * @param sourceInput excel文件的输入流
     * @param x           图片插入excel的横坐标
     * @param y           图片插入excel的纵坐标
     */
    public static ByteArrayOutputStream insBarcodeInExcel(InputStream imageInput,
                                                          InputStream sourceInput,
                                                          int x,
                                                          int y) {
        XSSFWorkbook wb = null;
        XSSFSheet sheet = null;
        ByteArrayOutputStream baos = null;
        try {
            wb = new XSSFWorkbook(sourceInput);
            sheet = wb.getSheetAt(0);
            byte[] bytes = IOUtils.toByteArray(imageInput);
            int pictureIdx = wb.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
            CreationHelper helper = wb.getCreationHelper();
            ClientAnchor anchor = helper.createClientAnchor();
            anchor.setCol1(x);//设置条形码的横坐标位置
            anchor.setRow1(y);//设置条形码的纵坐标位置
            Picture pict = sheet.createDrawingPatriarch().createPicture(anchor, pictureIdx);
            pict.resize();
            baos = new ByteArrayOutputStream();
            wb.write(baos);
            return baos;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (imageInput != null) {
                    imageInput.close();
                }
                if (sourceInput != null) {
                    sourceInput.close();
                }
                if (baos != null) {
                    baos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 将BufferedImage转为InputStream
     */
    public static InputStream getImageStream(BufferedImage bimage) {
        InputStream is = null;
        ByteArrayOutputStream bs = new ByteArrayOutputStream();
        ImageOutputStream imOut;
        try {
            imOut = ImageIO.createImageOutputStream(bs);
            ImageIO.write(bimage, "jpg", imOut);
            is = new ByteArrayInputStream(bs.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return is;
    }

    /**
     * 图片下边插入文字,并且文字相对图片居中
     * @param image   图片
     * @param words   待插入的文字
     * @param width   图片宽度
     * @param height  图片高度
     */
    public static BufferedImage insertWordsIntoImage(BufferedImage image,
                                                     String words,
                                                     int width,
                                                     int height) {
        // 新的图片,把带logo的二维码下面加上文字
        if (!StringUtils.isEmpty(words)) {
            BufferedImage outImage = new BufferedImage(width, height + FONT_SIZE, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = outImage.createGraphics();
            // 抗锯齿
            setGraphics2D(g2d);
            // 设置白色
            setColorWhite(g2d);
            // 画条形码到新的面板
            g2d.drawImage(image, 0, 0, image.getWidth(), image.getHeight(), null);
            // 画文字到新的面板
            g2d.setColor(Color.BLACK);
            // 字体、字型、字号
            g2d.setFont(new Font("黑体", Font.PLAIN, FONT_SIZE));

            int inputWidth = new Code128Writer().encode(words).length;
            int fullWidth = inputWidth + 1;
            int outputWidth = Math.max(width, fullWidth);
            int multiple = outputWidth / fullWidth;
            int leftPadding = (outputWidth - inputWidth * multiple) / 2;//条形码左边留白距离

            String[] split = words.split("");
            int len = split.length;
            int x = leftPadding + (width - 2 * leftPadding - len * WORD_DISTANCE) / 2;//文字开始写的横坐标
            int wordStartY = height + WORD_Y;//条形码下方文字的纵坐标
            for (int i = 0; i < len; i++) {
                g2d.drawString(split[i], x, wordStartY);
                x = x + WORD_DISTANCE;
            }
            outImage.flush();
            return outImage;
        }
        return null;
    }
}

效果如下:

image.png