java实现打印pdf

Java实现PDF打印

准备工作

1.PDF编辑工具:Adobe Acrobat

该文件官网下载需要收费,已经放到百度网盘里了,有需自取

通过百度网盘分享的文件:Acrobat DC2024安装包.zip
链接:https://pan.baidu.com/s/1eAE27Ce_W0vEQpXPsuqhzA
提取码:7777

安装好之后需要制作一个pdf模板,用来存放生成的数据

1.1, 创建表格

制作一个简单的Excel表格,然后转为PDF文件

在这里插入图片描述

1.2 使用Adobe Acrobat编辑PDF

在这里插入图片描述

打开转换好的PDF文件
在这里插入图片描述

编辑改PDF文件即可,上方工具栏中有文本域,图像域,日期域等工具,主需要内容处设置好文本域即可,并起好属性名

保存起来当做PDF模版文件,后续生成PDF文件都会根据这个文件来生成

在这里插入图片描述

2.pom依赖文件

		<!--常用工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
        </dependency>
        <!-- io常用工具类 -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.7</version>
        </dependency>
        <!-- pdf -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext7-core</artifactId>
            <version>7.0.2</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>fontbox</artifactId>
            <version>2.0.12</version>
        </dependency>

        <!--二维码-->
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.2.1</version>
        </dependency>

3.工具类

大致需要以下工具类

PdfPrintData自定义工具类,用于封装PDF打印所需要的数据
QRUtils:生辰图片工具类,可以生成二维码,条形码等图片
PDFUtils:处理PDF文档的工具类,生成,合并,打印PDF
FileDirConfig:配置和管理文件目录
PDFConfig:PDF字体库路径
SpringUtils:spring工具类 方便在非spring管理环境中获取bean,可以替换
PDFService:PDF服务类,封装好数据,调用工具类,生成PDF,返回给前端

4.字体库文件

simsun.ttc 必需的文件,否则无法打印,添加到配置文件内,类似这样:

在这里插入图片描述

通过百度网盘分享的文件:simsun.ttc
链接:https://pan.baidu.com/s/1eO5KE0WXzDDir0LTlx26hA
提取码:7777

5.java实现PDF打印,打印表单

需要编写前端,前端添加打印按钮,调用后端的接口,把必要的数据(需要生成PDF文件的数据),通过接口传输到后端,后端处理这些数据,并生成PDF文件

5.1 单个打印PDF表单

类似下面这种效果:

在这里插入图片描述

controller类
	/**
     * 打印PDF(单个),表单
     */
    @GetMapping("/printPdf")
    public void printPdf(HttpServletResponse response,
                         @RequestParam(value = "orderId",required = false) String orderId) throws IOException {
        ServletOutputStream outputStream = response.getOutputStream();
        //根据orderId查询相关数据
        QueryWrapper<Orders> ordersQueryWrapper = new QueryWrapper<>();
        ordersQueryWrapper.eq("order_id",orderId);
        Orders order = orderService.getOne(ordersQueryWrapper);
        // 封装打印数据
        OrderPdfData orderPdfData = new OrderPdfData();
        BeanUtils.copyBeanProp(orderPdfData,order);
        //使用FileInputStream创建输入流,读取pdfService.printOrder方法返回的文件路径对应的标签文件内容
        FileInputStream inputStream = new FileInputStream(new File(pdfService.printOrder(orderPdfData,1)));
        int len = 0;
        // 初始化一个1024字节数组
        byte[] bytes = new byte[1024];
        // 使用inputStream.read(buffer)从输入流中读取数据到buffer,并将实际读取的字节数赋值给len
        // 将读取的数据写入输出流out,直到in无更多数据可读
        while ((len = inputStream.read(bytes)) > 0) {
            outputStream.write(bytes, 0, len);
        }
        response.setContentType("application/pdf");
        inputStream.close();
    }
PDFService.java

PDF服务类,封装好数据,调用工具类,生成PDF,返回给前端

@Service
public class PDFService {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 打印运单信息,单个打印,打印表单信息
     * @param orderPdfData 要打印的数据
     * @param num 打印份数
     * @return 打印的pdf文件路径
     * @throws Exception 抛出异常
     */
    public String printOrder(OrderPdfData orderPdfData,int num) throws Exception {
        logger.info("打印订单信息");
        if (num < 1){
            num = 1;
        }
        // 填充数据,map的key值,就是PDF模板文件中,表单域的属性值,二者要对应
        Map<String, String> map = new HashMap<>();
        map.put("order_id",orderPdfData.getOrderId());
        map.put("robot_id",orderPdfData.getRobotId());
        map.put("pickup_dock_id",orderPdfData.getPickupDockId());
        map.put("dropoff_time", DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getDropoffTime()));
        map.put("delivery_dock_id",orderPdfData.getDeliveryDockId());
        map.put("order_status", OrderStatusEnum.getDescriptionByStatus(orderPdfData.getStatusId()));
        //日期需要转为String类型的
  map.put("create_time",DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getCreateTime()));

        ArrayList<PdfPrintData> pdfList = new ArrayList<>();
        for (int i = 0; i < num; i++){
            // 存放生成的二维码图片
            HashMap<String, String> map2 = new HashMap<>();
            // 生成二维码图片,key值是图片域中的属性名,value值是图片路径
            map2.put("qr_af_image", QRUtils.qrout("orderId"+orderPdfData.getOrderId()));
            PdfPrintData pdfPrintData = new PdfPrintData();
            // 填入表单数据
            pdfPrintData.setField(map);
            // 填入图片
            pdfPrintData.setImage(map2);
            // 填入模板文件
            pdfPrintData.setTemplatePath("pdf/order.pdf");
            pdfList.add(pdfPrintData);
        }
        return PDFUtils.pdfouts(pdfList);
    }
}

5.2 批量打印PDF表单

controller类
	/**
     * 批量打印PDF
     */
    @GetMapping("/printPdfBatch/{orderIds}")
    public void printPdfBatch(HttpServletResponse response, @PathVariable("orderIds") String[] orderIds) throws Exception {
        ArrayList<OrderPdfData> dataArrayList = new ArrayList<>();
        OutputStream out = null;
        InputStream in = null;
        try {
            out = response.getOutputStream();
            for (String orderId : orderIds){
                QueryWrapper<Orders> ordersQueryWrapper = new QueryWrapper<>();
                ordersQueryWrapper.eq("order_id",orderId);
                Orders order = orderService.getOne(ordersQueryWrapper);
                OrderPdfData orderPdfData = new OrderPdfData();
                BeanUtils.copyBeanProp(orderPdfData,order);
                dataArrayList.add(orderPdfData);
            }
            in = new FileInputStream(new File(pdfService.printOrder(dataArrayList)));
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = in.read(buffer)) > 0) {
                out.write(buffer, 0, len);
            }
            response.setContentType("application/pdf");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            try {
                out.close();
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
PDFService.java

PDF服务类,封装好数据,调用工具类,生成PDF,返回给前端

	/**
     * 批量打印运单信息
     */
    public String printOrder(List<OrderPdfData> orderPdfDataList) throws Exception {
        HashMap<String, String> map = null;
        ArrayList<PdfPrintData> pdfDatalist = new ArrayList<>();
        for (OrderPdfData orderPdfData : orderPdfDataList){
            //处理数据
            map = new HashMap<>();
            map.put("order_id",orderPdfData.getOrderId());
            map.put("robot_id",orderPdfData.getRobotId());
            map.put("pickup_dock_id",orderPdfData.getPickupDockId());
            map.put("dropoff_time", DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getDropoffTime()));
            map.put("delivery_dock_id",orderPdfData.getDeliveryDockId());
            map.put("order_status", OrderStatusEnum.getDescriptionByStatus(orderPdfData.getStatusId()));
            map.put("create_time",DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getCreateTime()));
            //处理图片
            HashMap<String, String> map2 = new HashMap<>();
            map2.put("qr_af_image", QRUtils.qrout("orderId"+orderPdfData.getOrderId()));
            PdfPrintData pdfPrintData = new PdfPrintData();
            pdfPrintData.setField(map);
            pdfPrintData.setImage(map2);
            pdfPrintData.setTemplatePath("pdf/order.pdf");
            pdfDatalist.add(pdfPrintData);
        }
        return PDFUtils.pdfouts(pdfDatalist);
    }

6.java实现PDF打印,打印表单+表格数据

类似下面这种效果,格式有点不匹配,需要调一下,比较麻烦,下面那个是生成的表格数据,也没有自适应,显得比较突兀

在这里插入图片描述

controller类
	/**
     * 打印PDF表单+表格数据
     */
    @GetMapping("/printPdf/{orderId}")
    public void printPdfTable(HttpServletResponse response, @PathVariable("orderId") String orderId) throws Exception {
        ServletOutputStream outputStream = response.getOutputStream();
        QueryWrapper<Orders> ordersQueryWrapper = new QueryWrapper<>();
        ordersQueryWrapper.eq("order_id",orderId);
        List<Orders> ordersList = orderService.list(ordersQueryWrapper);
        ArrayList<OrderPdfData> pdfDataList = new ArrayList<OrderPdfData>();
        if (ordersList != null && ordersList.size() > 0){
            for (Orders orders : ordersList){
                OrderPdfData orderPdfData = new OrderPdfData();
                BeanUtils.copyBeanProp(orderPdfData,orders);
                pdfDataList.add(orderPdfData);
            }
        }
        FileInputStream fileInputStream = new FileInputStream(new File(pdfService.printOrderTable(pdfDataList)));
        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fileInputStream.read(bytes)) > 0) {
            outputStream.write(bytes, 0, len);
        }
        response.setContentType("application/pdf");
        fileInputStream.close();
        outputStream.close();
    }
pdfService.java
	/**
     * 打印表单+表格数据
     */
    public String printOrderTable(List<OrderPdfData> orderPdfDataList) throws Exception {
        PdfPrintData pdfPrintData = new PdfPrintData();
        HashMap<String, String> map = new HashMap<>();
        // 创建二维数组
        String[][] data = null;
        //表格标题
        pdfPrintData.setTitle(new String[]{"行号","机器人id","取货库位","卸货库位","完成时间","任务状态"});
        //表格列宽
        pdfPrintData.setColum(new float[]{1,1,1,1,1,1});
        //初始化二维数组
        data = new String[orderPdfDataList.size() + 1][6];
        int i = 1;
        for (OrderPdfData orderPdfData : orderPdfDataList){
            map.put("order_id",orderPdfData.getOrderId());
            map.put("create_time",DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getCreateTime()));
            data[i][0] = String.valueOf(i);
            data[i][1] = orderPdfData.getRobotId();
            data[i][2] = orderPdfData.getPickupDockId();
            data[i][3] = orderPdfData.getDeliveryDockId();
            data[i][4] = DateUtil.parseDateToStr(DateUtil.YYYY_MM_DD,orderPdfData.getDropoffTime());
            data[i][5] = OrderStatusEnum.getDescriptionByStatus(orderPdfData.getStatusId());
            i++;
        }
        // 设置表单数据
        pdfPrintData.setField(map);
        // 设置表格数据
        pdfPrintData.setData(data);
        // 设置表格域名
        pdfPrintData.setTable("table_af_image");
        //生成二维码图片
        HashMap<String, String> imgMap =  new HashMap<>();
        imgMap.put("qr_af_image", QRUtils.qrout("orderId"+orderPdfDataList.get(0).getOrderId()));
        pdfPrintData.setImage(imgMap);
        pdfPrintData.setTemplatePath("pdf/order_table_data.pdf");
        return PDFUtils.pdfout(pdfPrintData, Color.LIGHT_GRAY, Color.BLACK);
    }

7.必要的工具类以及配置类

QRUtils.java

,生成二维码/条形码图片

/**
 * @author itchao
 * @create 2024-09-11
 */
public class QRUtils {
    /**
     * 生成二维码
     * @param content 二维码内容
     * @return 二维码路径
     * @throws Exception 抛出异常
     */
    public static String qrout(String content) throws Exception{
        File file = new File(FileDirConfig.FILE_TEMP);
        if (!file.exists()){
            file.mkdirs();
        }
        //生成二维码
        int width = 200;
        int height = 200;
        Map<EncodeHintType, Object> config = new HashMap<>();
        //设置字符集
        config.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        // 误差纠正级别:
        // L(Low):约7%的纠错能力。
        // M(Medium):约15%的纠错能力。
        // Q(Quartile):约25%的纠错能力。
        // H(High):约30%的纠错能力。
        config.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        //设置二维码的边距
        config.put(EncodeHintType.MARGIN, 0);
        // 生成二维码
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, config);

        String guid = String.valueOf(OrderDateNumberGenerator.generate());
        String path = FileDirConfig.FILE_TEMP+ guid;
        //创建一个输出流的文件,文件命名为uuid.png二维码图片
        OutputStream out = new FileOutputStream(new File(path));
        MatrixToImageWriter.writeToStream(bitMatrix,"png",out);
        out.close();
        return path ;
    }

    /**
     * 生成带有logo的二维码图片
     * @param content 二维码内容
     * @param logoUrl logo图片地址
     * @return 二维码路径
     * @throws Exception 抛出异常
     */
    public static String qrLogoOut(String content, String logoUrl) throws Exception{
        //生成二维码
        int width = 200;
        int height = 200;
        Map<EncodeHintType, Object> config = new HashMap<>();
        config.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        config.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
        config.put(EncodeHintType.MARGIN, 0);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, config);
        BufferedImage matrixImage = MatrixToImageWriter.toBufferedImage(bitMatrix);

        // 读取二维码图片,并构建绘图对象
        Graphics2D g2 = matrixImage.createGraphics();
        // 消除锯齿。不设置的话,圆弧效果会出现锯齿
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int matrixWidth = matrixImage.getWidth();
        int matrixHeight = matrixImage.getHeight();

        // 读取logo图片
        BufferedImage logo = ImageIO.read(new URL(logoUrl));

        // 在底图(源二维码)上绘制logo。logo大小为地图的2/5
//        g2.drawImage(logo, matrixWidth / 5 * 2, matrixHeight / 5 * 2,
//                matrixWidth / 5, matrixHeight / 5, null);//绘制
        // 采用平滑缩放的方式,来解决logo质量变差的问题
        g2.drawImage(logo.getScaledInstance(matrixWidth / 5,matrixWidth / 5, Image.SCALE_SMOOTH),
                matrixWidth / 5 * 2, matrixHeight / 5 * 2, null);

        // 圆滑的粗线条
        // 参见:https://blog.csdn.net/li_tengfei/article/details/6098093
        BasicStroke stroke = new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        // 设置画笔的画出的线条
        g2.setStroke(stroke);

        // 指定弧度的圆角矩形(空心的,白色边的)
        RoundRectangle2D.Double round = new RoundRectangle2D.Double(matrixWidth / 5 * 2, matrixHeight / 5 * 2,
                matrixWidth / 5, matrixHeight / 5, 5, 5);
        g2.setColor(Color.white);
        // 用于绘制logo外层的白边
        g2.draw(round);

        // 圆滑的细线条
        BasicStroke stroke2 = new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND);
        g2.setStroke(stroke2);
        // 设置圆角矩形
        RoundRectangle2D.Double round2 = new RoundRectangle2D.Double(matrixWidth / 5 * 2 + 2, matrixHeight / 5 * 2 + 2,
                matrixWidth / 5 - 4, matrixHeight / 5 - 4, 5, 5);
        g2.setColor(new Color(211, 211, 211));
        // 绘制logo内部的灰色边框
        g2.draw(round2);

        g2.dispose();
        matrixImage.flush();

        // 输出测试
        File file = new File(FileDirConfig.FILE_TEMP);
        if (!file.exists()){
            file.mkdirs();
        }
        String guid = String.valueOf(OrderDateNumberGenerator.generate());
        String path = FileDirConfig.FILE_TEMP+ guid;
        OutputStream out = new FileOutputStream(new File(path));
        ImageIO.write(matrixImage, "png", out);
        out.close();
        return path ;
    }
}
PdfPrintData.java

自定义工具类,用于封装PDF打印所需要的数据

/**
 * @author itchao
 * @create 2024-09-11
 */
@Data
public class PdfPrintData {
    public String templatePath;//模板文件地址

    public Map<String, String> field; //表单

    public Map<String, String> image;//图片

    public String table;//table 的所有域

    public float[] colum;//table表格的宽度比

    public String[] title;//表格标题

    public String[][] data;//表格数据

}
PDFUtils.java

处理PDF文档的工具类,生成,合并,打印PDF

/**
 * @author itchao
 * @create 2024-09-11
 */
public class PDFUtils {
    /**
     * 单个pdf打印,表单
     * @param pdfPrintData 模板数据
     * @return PDF路径
     * @throws Exception 抛出异常
     */
    public static String pdfout(PdfPrintData pdfPrintData) throws Exception {
        File file = new File(FileDirConfig.FILE_TEMP);
        if (!file.exists()) {
            file.mkdirs();
        }
        // 生成的新文件路径
        String newPDFPath = FileDirConfig.FILE_TEMP + OrderDateNumberGenerator.generate();
        // 加载模板文件地址,模板文件在resources下
        ClassPathResource cpr = new ClassPathResource(pdfPrintData.getTemplatePath());
        // 读取模板文件的输入流
        PdfReader reader = new PdfReader(cpr.getInputStream());
        // 将文档路径写入输出流
        PdfWriter writer = new PdfWriter(new FileOutputStream(newPDFPath));
        // 创建pdf文档
        PdfDocument pdfDoc = new PdfDocument(reader, writer);
        // 操作PDF
        Document document = new Document(pdfDoc);
        pdfDoc.setDefaultPageSize(PageSize.A4);

        PDFConfig pdfConfig = SpringUtils.getBean(PDFConfig.class);
        //  /usr/share/fonts/simsun.ttc,1
        // 获取字体库路径,设置编码方式,false:字体是否嵌入
        PdfFont sysFont = PdfFontFactory.createFont(pdfConfig.getPdfFontLibrary(), PdfEncodings.IDENTITY_H, false);
        try {
            // 设置页边距,上:20 右:5 下:20 左:5
            document.setMargins(20,5,20,5);
            // 设置字体大小
            document.setFontSize(8);
            // 设置页面大小的高度
            document.setHeight(pdfDoc.getDefaultPageSize().getHeight());

            // 获取表单对象,设置表单自动生成外观图像
            PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
            form.setGenerateAppearance(true);
            //文字类的内容处理
            // 获取PDF表单中的所有字段
            Map<String, PdfFormField> fields = form.getFormFields();
            // 获取PDF打印数据中的字段映射
            Map<String, String> datemap = pdfPrintData.getField();
            // 如果字段映射不为空
            if (datemap != null) {
                for (String key : datemap.keySet()) {
                    // 获取当前键对应的值
                    String value = datemap.get(key);
                    // 根据键获取对应的PDF表单字段
                    PdfFormField pdfFormField = fields.get(key);
                    if (pdfFormField !=null && value != null){
                        // 设置表单字段的字体
                        pdfFormField.setFont(sysFont);
                        // 设置表单字段的值
                        pdfFormField.setValue(value);
                    }

                }
            }
            // 关闭表单编辑功能,即将表单字段进行扁平化处理,防止后续编辑
            form.flattenFields();
            //图片类的内容处理
            Map<String, String> imgmap = pdfPrintData.getImage();
            if (imgmap != null) {
                for (String key : imgmap.keySet()) {
                    String value = imgmap.get(key);
                    String imgpath = value;
                    PdfFormField pdfFormField = form.getField(key);
                    if (pdfFormField == null){
                        continue;
                    }
                    // 获取key对应的矩形区域,转换城Rectangle对象
                    Rectangle rectangle = form.getField(key).getWidgets().get(0).getRectangle().toRectangle();
//                //根据路径读取图片
                    // 1.使用FileInputStream读取图片文件路径imgpath对应文件的内容。然后使用IOUtils.toByteArray把输入流转为字节数组
                    // 2.使用ImageDataFactory.create(byte[] data)创建图片对象
                    // 最终构造成一个Image对象
                    Image image = new Image(ImageDataFactory.create(IOUtils.toByteArray(new FileInputStream(imgpath))));
                    ;
//                //图片大小自适应
                    image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
                    image.setFixedPosition(rectangle.getX(), rectangle.getY());
//                //添加图片
                    document.add(image);
                }
            }

            //表格处理
            if (StringUtils.isNotEmpty(pdfPrintData.getTable())) {
                // 获取对应字段的矩形区域位置信息
                Rectangle rectangle = form.getField(pdfPrintData.getTable()).getWidgets().get(0).getRectangle().toRectangle();
                // 根据column表格列宽,创建一个新的表格对象,用来存储数据
                Table table = new Table(UnitValue.createPercentArray(pdfPrintData.getColum()));
                //获取PDF文档的第一页的页面大小和高度值,
                float pageheight = document.getPdfDocument().getPage(1).getPageSize().getHeight();
                //设置表格的顶部间距 = 页面高度 - 矩形Y坐标 - 高度值
                table.setMarginTop(pageheight - rectangle.getY() -rectangle.getHeight());
                //设置表格左侧和右侧间距,都为x值
                table.setMarginLeft(rectangle.getX());
                table.setMarginRight(rectangle.getX());
                //设置标题
                for (String title : pdfPrintData.getTitle()) {
                    // 设置标题,将标题添加到段落中,设置字体,设置背景颜色,设置字体颜色,设置文字对齐方式:居中(center)
                    table.addCell(new Cell().add(new Paragraph(title).setFont(sysFont)).setBackgroundColor(Color.BLUE).setFontColor(Color.WHITE)
                            .setTextAlignment(TextAlignment.CENTER));
                }
                // 添加数据
                for (String[] datas : pdfPrintData.getData()) {
                    for (String data : datas) {
                        // 没有数据就设置为空
                        if (data == null){
                            data = "" ;
                        }
                        // 添加数据,设置字体(上方的字体库路径),设置对齐方式:左对齐(left)
                        table.addCell(new Cell().add(new Paragraph(data).setFont(sysFont))
                                .setTextAlignment(TextAlignment.LEFT));
                    }
                }
                // 创建列数为1,宽度根据标题长度变化的单元格,设置内容,设置字体,设置对齐方式:居中(center)
                table.addFooterCell(new Cell(1,pdfPrintData.getTitle().length)
                        .add(new Paragraph("- - - 此页结束 - - -").setFont(sysFont))
                        .setTextAlignment(TextAlignment.CENTER));
                // 把表格数据添加到pdf中
                document.add(table);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return newPDFPath;
    }

    /**
     * 单个pdf打印,表单+表格数据类型
     * @param pdfPrintData pdf打印数据
     * @param backgroundColor 背景颜色
     * @param fontColor 字体颜色
     * @return pdf文件路径
     * @throws Exception 抛出异常
     */
    public static String pdfout(PdfPrintData pdfPrintData, Color backgroundColor, Color fontColor) throws Exception {
        File file = new File(FileDirConfig.FILE_TEMP);
        if (!file.exists()) {
            file.mkdirs();
        }
        // 生成的新文件路径
        String newPDFPath = FileDirConfig.FILE_TEMP + OrderDateNumberGenerator.generate();
        ClassPathResource cpr = new ClassPathResource(pdfPrintData.getTemplatePath());
        PdfReader reader = new PdfReader(cpr.getInputStream());
        PdfWriter writer = new PdfWriter(new FileOutputStream(newPDFPath));
        PdfDocument pdfDoc = new PdfDocument(reader, writer);
        Document document = new Document(pdfDoc);
        pdfDoc.setDefaultPageSize(PageSize.A4);

        //获取字体库配置类的bean实例
        PDFConfig pdfConfig = SpringUtils.getBean(PDFConfig.class);
        //  /usr/share/fonts/simsun.ttc,1 配置字体
        PdfFont sysFont = PdfFontFactory.createFont(pdfConfig.getPdfFontLibrary(),PdfEncodings.IDENTITY_H, false);
        try {
            document.setMargins(20,5,20,5);
            document.setFontSize(8);

            document.setHeight(pdfDoc.getDefaultPageSize().getHeight());

            PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true);
            form.setGenerateAppearance(true);
            //文字类的内容处理
            Map<String, PdfFormField> fields = form.getFormFields();
            Map<String, String> datemap = pdfPrintData.getField();
            if (datemap != null) {
                for (String key : datemap.keySet()) {
                    String value = datemap.get(key);
                    PdfFormField pdfFormField = fields.get(key);
                    if (pdfFormField !=null && value != null){
                        pdfFormField.setFont(sysFont);
                        pdfFormField.setValue(value);
                    }

                }
            }
            form.flattenFields();//关闭表单编辑
            //图片类的内容处理
            Map<String, String> imgmap = pdfPrintData.getImage();
            if (imgmap != null) {
                for (String key : imgmap.keySet()) {
                    String value = imgmap.get(key);
                    String imgpath = value;
                    PdfFormField pdfFormField = form.getField(key);
                    if (pdfFormField == null){
                        continue;
                    }
                    Rectangle rectangle = form.getField(key).getWidgets().get(0).getRectangle().toRectangle();
//                //根据路径读取图片
                    Image image = new Image(ImageDataFactory.create(IOUtils.toByteArray(new FileInputStream(imgpath))));
                    ;
//                //图片大小自适应
                    image.scaleToFit(rectangle.getWidth(), rectangle.getHeight());
                    image.setFixedPosition(rectangle.getX(), rectangle.getY());
//                //添加图片
                    document.add(image);
                }
            }

            //表格处理
            if (StringUtils.isNotEmpty(pdfPrintData.getTable())) {
                Rectangle rectangle = form.getField(pdfPrintData.getTable()).getWidgets().get(0).getRectangle().toRectangle();
                Table table = new Table(UnitValue.createPercentArray(pdfPrintData.getColum()));
                float pageheight = document.getPdfDocument().getPage(1).getPageSize().getHeight();
                table.setMarginTop(pageheight - rectangle.getY() -rectangle.getHeight());
                table.setMarginLeft(rectangle.getX());
                table.setMarginRight(rectangle.getX());
                //设置标题
                for (String title : pdfPrintData.getTitle()) {
                    table.addCell(new Cell().add(new Paragraph(title).setFont(sysFont)).setBackgroundColor(backgroundColor).setFontColor(fontColor)
                            .setTextAlignment(TextAlignment.CENTER));
                }
                for (String[] datas : pdfPrintData.getData()) {
                    for (String data : datas) {
                        if (data == null){
                            data = "" ;
                        }
                        table.addCell(new Cell().add(new Paragraph(data).setFont(sysFont))
                                .setTextAlignment(TextAlignment.LEFT));
                    }
                }
                table.addFooterCell(new Cell(1,pdfPrintData.getTitle().length)
                        .add(new Paragraph("- - - 此页结束 - - -").setFont(sysFont))
                        .setTextAlignment(TextAlignment.CENTER));
                document.add(table);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            document.close();
        }
        return newPDFPath;
    }


    /**
     * 多个PDF合并
     * @param pdfPrintDataList 模板数据,二维码图片,模板路径文件...
     * @return 合并后的PDF路径
     * @throws Exception 抛出异常
     */
    public static String pdfouts(List<PdfPrintData> pdfPrintDataList) throws Exception {
        // 创建临时目录, 用于存放临时文件
        File file = new File(FileDirConfig.FILE_TEMP);
        if (!file.exists()) {
            file.mkdirs();
        }
        // 遍历入参列表,存到新的集合中
        List<String> files = new ArrayList<>();
        for (PdfPrintData pdfPrintData : pdfPrintDataList) {
            files.add(pdfout(pdfPrintData));
        }
        // 生成的新文件路径,""+uuid
        String newPDFPath = FileDirConfig.FILE_TEMP + OrderDateNumberGenerator.generate();
        //将文档路径写入输出流
        PdfWriter writer = new PdfWriter(new FileOutputStream(newPDFPath));
        // 创建pdf文档
        PdfDocument pdfDes = new PdfDocument(writer);
        //合并多个PDF文档
        PdfMerger merger = new PdfMerger(pdfDes);
        for (String filePath : files) {
            PdfReader reader = new PdfReader(filePath);
            PdfDocument pdfResource = new PdfDocument(reader);
            merger.setCloseSourceDocuments(true).merge(pdfResource, 1, pdfResource.getNumberOfPages());
            pdfResource.close();

        }
        pdfDes.close();
        return newPDFPath;
    }
}
FileDirConfig.java

需要在配置文件中配置文件路径,被@Value()读取到,否则会报错,类似这样,可以定义自己的路径

在这里插入图片描述

配置和管理文件目录

/**
 * @author itchao
 * @create 2024-09-11
 */
@Component
public class FileDirConfig {
    public static final String FILE_DOWNLOAD_URL = "/file/";
    public static final String FILE_PREVIEW_URL = "/file/preview/";

    public static String FILE_DIR ="";

    public static String FILE_TEMP = "";

    public static String FILE_GYTZ = "";

    /**
     * 设置文件目录及其子目录,不存在则创建
     * @param fileDir 文件目录路径
     */
    @Value("${filedir}")
    public void setFileDir(String fileDir) {
        FILE_DIR = fileDir;
        File file = new File(fileDir);
        if (!file.exists()){
            file.mkdirs();
        }
        FILE_GYTZ = FILE_DIR + "GYTZ/";
        file = new File(FILE_GYTZ);
        if (!file.exists()){
            file.mkdirs();
        }
    }

    /**
     * 设置文件目录,不存在则创建
     * @param fileDir
     */
    @Value("${filetemp}")
    public void setFileTemp(String fileDir) {
        FILE_TEMP = fileDir;
        File file = new File(fileDir);
        if (!file.exists()){
            file.mkdirs();
        }
    }

    /**
     * 创建一个新的文件
     *
     * @return
     */
    public static File getTempFile(String filename) {
        File dir = new File(FileDirConfig.FILE_TEMP);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(FileDirConfig.FILE_TEMP, filename);
        return file;
    }


    /**
     * 获取磁盘上的文件
     *
     * @param filename
     * @return
     */
    public static File getDiskFile(String dirs, String filename) {
        File dir = new File(FileDirConfig.FILE_DIR + dirs);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(FileDirConfig.FILE_DIR + dirs, filename);
        return file;
    }
    
}

PDFConfig.java

从配置文件中,获取PDF字体库路径,字体库文件路径改成自己的
在这里插入图片描述

/**
 * pdf字体库路径
 * @author itchao
 * @create 2024-09-11
 */
@Component
public class PDFConfig {
    // 配置文件中配置自己的文件路径
    @Value("${pdf.pdf_font_library}")
    private String pdf_font_library;

    public String getPdfFontLibrary(){
        return pdf_font_library;
    }
}
SpringUtils.java

spring工具类 方便在非spring管理环境中获取bean

/**
 * spring工具类 方便在非spring管理环境中获取bean
 * @author itchao
 * @create 2024-09-11
 */
@Component
public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware {
    /** Spring应用上下文环境 */
    private static ConfigurableListableBeanFactory beanFactory;

    private static ApplicationContext applicationContext;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
    {
        SpringUtils.beanFactory = beanFactory;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 获取对象
     *
     * @param name
     * @return Object 一个以所给名字注册的bean的实例
     * @throws org.springframework.beans.BeansException
     *
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException
    {
        return (T) beanFactory.getBean(name);
    }

    /**
     * 获取类型为requiredType的对象
     *
     * @param clz
     * @return
     * @throws org.springframework.beans.BeansException
     *
     */
    public static <T> T getBean(Class<T> clz) throws BeansException
    {
        T result = (T) beanFactory.getBean(clz);
        return result;
    }

}
DateUtil.java

日期工具类,主要是为了把日期转为字符串

/**
 * 时间日期工具类
 * 针对 java.util.Date 日期时间处理
 * @author itchao
 * @create 2024-09-11
 */
public class DateUtil extends org.apache.commons.lang3.time.DateUtils{

	public static String YYYY = "yyyy";

	public static String YYYY_MM = "yyyy-MM";

	public static String YYYY_MM_DD = "yyyy-MM-dd";

	public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

	public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

	private static String[] parsePatterns = {
			"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
			"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

	/**
	 * 获取当前Date型日期
	 *
	 * @return Date() 当前日期
	 */
	public static Date getNowDate() {
		return new Date();
	}

	/**
	 * 获取当前日期, 默认格式为yyyy-MM-dd
	 *
	 * @return String
	 */
	public static String getDate() {
		return dateTimeNow(YYYY_MM_DD);
	}

	public static final String getTime() {
		return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
	}

	public static final String dateTimeNow() {
		return dateTimeNow(YYYYMMDDHHMMSS);
	}

	public static final String dateTimeNow(final String format) {
		return parseDateToStr(format, new Date());
	}

	public static final String dateTime(final Date date) {
		return parseDateToStr(YYYY_MM_DD, date);
	}

	public static final String parseDateToStr(final String format, final Date date) {
		return new SimpleDateFormat(format).format(date);
	}
}

8.前端部分

8.1 PDF打印,打印表单

8.1.2 单个打印PDF表单

打印按钮调用的函数,类似这样的,根据自己的自行修改,id不一样

// 打印方法  
handleComplement(item){
      printLabel(item.labelId).then(response => {
        const binaryData = [];
        binaryData.push(response);
        let pdfUrl = window.URL.createObjectURL(new Blob(binaryData, { type: "application/pdf" }));
        window.open(pdfUrl);
      });
	}
8.1.3 批量打印PDF表单
/** 批量打印 */
    handlePrintBatch(row){
      const labelIds = row.labelId || this.ids;
      printLabelBatch(labelIds).then(response => {
        const binaryData = [];
        binaryData.push(response);
        let pdfUrl = window.URL.createObjectURL(new Blob(binaryData, { type: "application/pdf" }));
        window.open(pdfUrl);
      });
    }

8.2 PDF打印,打印表单+表格数据

8.2.1 打印PDF表单+表格数据
// 打印方法  
handleComplement(item){
      printLabel(item.labelId).then(response => {
        const binaryData = [];
        binaryData.push(response);
        let pdfUrl = window.URL.createObjectURL(new Blob(binaryData, { type: "application/pdf" }));
        window.open(pdfUrl);
      });
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值