打印不再烦恼!Java 编程助力,个性化打印模板指南!

 前言😊

只要你能看懂中文就会用,直接CV直接改,讲究的就是CV大法的魅力!!!

 

 须知🐱‍👤

我们需要了解图像尺寸和物理尺寸之间的转换关系。

在图像处理中,通常使用像素作为图像的尺寸单位。
而像素和物理尺寸之间通常有一个固定的转换关系,这个关系取决于DPI(每英寸点数)。
在这个问题中,DPI是72,这意味着1英寸等于72像素。

因此,我们可以使用以下公式来进行换算:
图像尺寸(像素) = 物理尺寸(毫米) × (DPI / 25.4)

其中,25.4是1英寸的毫米数。

A4纸的尺寸为210mm×297mm,世界上多数国家所使用的纸张尺寸都是采用这一国际标准.

所以210x297mm的尺寸换算成72的图像尺寸的计算结果为:图像的宽度是 595.28 像素,高度是 841.89 像素。

xy轴的单位是像素,所以需要学会计算尺寸

图像尺寸(像素) = 物理尺寸(毫米) × (DPI / 25.4) 其中,25.4是1英寸的毫米数。

计算结果为:图像的宽度是 595.28 像素,高度是 841.89 像素。 所以,210x297mm的尺寸换算成72的图像尺寸是 595.28x841.89 像素。

已知毫米求出需要多少像素:假设输出设备的分辨率是72 DPI,即每英寸有72个像素

210mm ÷ 25.4 = 8.26英寸

接下来,使用DPI来将这些英寸尺寸转换为像素尺寸。每英寸有72个像素,所以:

8.26英寸 × 72 DPI = 594.72像素

已知像素求出需要多少毫米:假设输出设备的分辨率是72 DPI,即每英寸有72个像素

594.72 ÷ 72 =8.26 英寸

接下来,使用来将这些英寸尺寸转换为毫米尺寸。每英寸有25.4毫米,所以:

8.26 x 25.4 ≈ 210mm


效果展示🤣

预览效果👀

 打印效果💖


 代码🐱‍🐉

系统属性🎂

import java.awt.*;

public final class SystemProperties {
    public static final double SCREEN_WIDTH = Toolkit.getDefaultToolkit().getScreenSize().getWidth();
    public static final double SCREEN_HEIGHT = Toolkit.getDefaultToolkit().getScreenSize().getHeight();
    public static final String USER_DIR = System.getProperty("user.dir");
    public static final String USER_HOME = System.getProperty("user.home");
    public static final String USER_NAME = System.getProperty("user.name");
    public static final String FILE_SEPARATOR = System.getProperty("file.separator");
    public static final String LINE_SEPARATOR = System.getProperty("line.separator");
    public static final String PATH_SEPARATOR = System.getProperty("path.separator");
    public static final String JAVA_HOME = System.getProperty("java.home");
    public static final String JAVA_VENDOR = System.getProperty("java.vendor");
    public static final String JAVA_VENDOR_URL = System.getProperty("java.vendor.url");
    public static final String JAVA_VERSION = System.getProperty("java.version");
    public static final String JAVA_CLASS_PATH = System.getProperty("java.class.path");
    public static final String JAVA_CLASS_VERSION = System.getProperty("java.class.version");
    public static final String OS_NAME = System.getProperty("os.name");
    public static final String OS_ARCH = System.getProperty("os.arch");
    public static final String OS_VERSION = System.getProperty("os.version");
    public static final String[] FONT_NAME_LIST = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
    public static final Font[] FONT_LIST = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();

    public SystemProperties() {
    }
}

 预览弹窗👀

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;


public class PrintPreviewDialog extends JDialog
        implements ActionListener {
    private JButton nextButton = new JButton("下一个");
    private JButton previousButton = new JButton("以前");
    private JButton closeButton = new JButton("关闭");
    private JPanel buttonPanel = new JPanel();
    private PreviewCanvas canvas;

    public PrintPreviewDialog(Frame parent, String title, boolean modal, PrintHelp pt, String str) {
        super(parent, title, modal);
        canvas = new PreviewCanvas(pt, str);
        setLayout();
    }

    private void setLayout() {
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(canvas, BorderLayout.CENTER);

        nextButton.setMnemonic('N');
        nextButton.addActionListener(this);
        buttonPanel.add(nextButton);
        previousButton.setMnemonic('N');
        previousButton.addActionListener(this);
        buttonPanel.add(previousButton);
        closeButton.setMnemonic('N');
        closeButton.addActionListener(this);
        buttonPanel.add(closeButton);
        this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
        // 弹窗xy位置,宽高
        this.setBounds((int) ((SystemProperties.SCREEN_WIDTH - 400) / 2), (int) ((SystemProperties.SCREEN_HEIGHT - 400) / 2), 2360, 1180);
    }

    public void actionPerformed(ActionEvent evt) {
        Object src = evt.getSource();
        if (src == nextButton)
            nextAction();
        else if (src == previousButton)
            previousAction();
        else if (src == closeButton)
            closeAction();
    }

    private void closeAction() {
        this.setVisible(false);
        this.dispose();
    }

    private void nextAction() {
        canvas.viewPage(1);
    }

    private void previousAction() {
        canvas.viewPage(-1);
    }

    class PreviewCanvas extends JPanel {
        private String printStr;
        private int currentPage = 0;
        private PrintHelp preview;

        public PreviewCanvas(PrintHelp pt, String str) {
            printStr = str;
            preview = pt;
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2 = (Graphics2D) g;
            PageFormat pf = PrinterJob.getPrinterJob().defaultPage();

            double xoff;
            double yoff;
            double scale;
            double px = pf.getWidth();

            double py = pf.getHeight();
            double sx = getWidth() - 1;
            double sy = getHeight() - 1;
            if (px / py < sx / sy) {
                scale = sy / py;
                xoff = 0.5 * (sx - scale * px);
                yoff = 0;
            } else {
                scale = sx / px;
                xoff = 0;
                yoff = 0.5 * (sy - scale * py);
            }
            g2.translate((float) xoff, (float) yoff);
            g2.scale((float) scale, (float) scale);
            // 白板xy轴位置,宽高
            Rectangle2D page = new Rectangle2D.Double(0, 0, px, py);
            g2.setPaint(Color.white);
            g2.fill(page);
            g2.setPaint(Color.black);
            g2.draw(page);

            try {
                preview.print(g2, pf, currentPage);
            } catch (PrinterException pe) {
                g2.draw(new Line2D.Double(0, 0, px, py));
                g2.draw(new Line2D.Double(0, px, 0, py));
            }
        }

        public void viewPage(int pos) {
            int newPage = currentPage + pos;
            if (0 <= newPage && newPage < preview.getPagesCount(printStr)) {
                currentPage = newPage;
                repaint();
            }
        }
    }
}

打印模板🐱‍👤

import com.scwl.printer_jg.model.GoodsDTO;
import com.scwl.printer_jg.model.WeighingListDTO;

import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.*;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Properties;

/**
 * @author 小影
 * @create 2023-12-22 17:05
 * @describe: JFrame:Java图形化界面设计——容器
 * java.awt.print.Printable动作事件监听器
 * java.awt.print.Printable:通用的打印 API 提供类和接口
 */
public class PrintHelp extends JFrame implements ActionListener, Printable {
    public PrintHelp() {
        this.setTitle("小影打印测试");// 窗口标题
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setBounds((int) ((SystemProperties.SCREEN_WIDTH - 800) / 2), (int) ((SystemProperties.SCREEN_HEIGHT - 600) / 2), 800, 600);
        initLayout();
    }

    private WeighingListDTO weighingListDTO;// 参数实体类
    private int PAGES = 0;
    private JTextArea area = new JTextArea();// 用来创建一个默认的文本域
    private JPanel buttonPanel = new JPanel();// 创建面板
    private JScrollPane scroll = new JScrollPane(area);// 创建窗口
    private String printStr;
    private JButton printTextButton = new JButton("打印测试");
    private JButton previewButton = new JButton("打印预览");
    private JButton printText2Button = new JButton("打印测试2");
    private JButton printFileButton = new JButton("打印文件");
    private JButton printFrameButton = new JButton("Print Frame");
    private JButton exitButton = new JButton("退出");


    public static void main(String[] args) throws PrinterException {
        Book book = new Book();
        PageFormat pf = new PageFormat();
        pf.setOrientation(PageFormat.PORTRAIT);
        Paper p = new Paper();
        p.setSize(595, 283);// 纸张大小单位是像素
        p.setImageableArea(1, 5, 590, 282);// A4(595 X 842)设置打印区域,其�?0�?0应该�?72�?72,因为A4纸的默认X,Y边距�?72
        pf.setPaper(p);
        WeighingListDTO datas = new WeighingListDTO();
        datas.setUnitName("XXXXX有限公司称重计量单");
        datas.setClientName("客户名称: XXXXX里科技有限公司");
        datas.setPlateNumber("闽C:66666");
        datas.setOrderNo("过磅单:GB88888888");
        datas.setSjName("司机签名:");
        datas.setSjPhone("司机电话:");
        datas.setYssl("一式三联");

        ArrayList<GoodsDTO> goodList = new ArrayList<>();
        GoodsDTO goods = new GoodsDTO();
        GoodsDTO goods2 = new GoodsDTO();
        goods.setGoodsName("物料名称");
        goods.setNumber("件数");
        goods.setTare("皮重");
        goods.setGrossWeight("毛重");
        goods.setSuttle("净重");
        goods.setCSuttle("纯净重");
        goods.setQingTime("轻磅时间");
        goods.setZhongTime("重磅时间");

        goods2.setGoodsName("皂角");
        goods2.setNumber("100");
        goods2.setTare("15.76");
        goods2.setGrossWeight("49.80");
        goods2.setSuttle("34.0400");
        goods2.setCSuttle("34.0400");
        goods2.setQingTime("2023/12/22 09:30:00");
        goods2.setZhongTime("2023/12/22 10:30:00");
        goodList.add(goods);
        goodList.add(goods2);
        datas.setList(goodList);


        PrintHelp printHelp = new PrintHelp();
        printHelp.init(datas);
        book.append(printHelp, pf);
        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPageable(book);
        // job.print();//进行打印
        printHelp.setVisible(true); // 打印窗口
    }


    public void init(WeighingListDTO datas) {
        this.weighingListDTO = datas;
    }


    private void initLayout() {
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(scroll, BorderLayout.CENTER);
        printTextButton.setMnemonic('P');
        printTextButton.addActionListener(this);
        buttonPanel.add(printTextButton);
        previewButton.setMnemonic('v');
        previewButton.addActionListener(this);
        buttonPanel.add(previewButton);
        printText2Button.setMnemonic('e');
        printText2Button.addActionListener(this);
        buttonPanel.add(printText2Button);
        printFileButton.setMnemonic('i');
        printFileButton.addActionListener(this);
        buttonPanel.add(printFileButton);
        printFrameButton.setMnemonic('F');
        printFrameButton.addActionListener(this);
        buttonPanel.add(printFrameButton);
        exitButton.setMnemonic('x');
        exitButton.addActionListener(this);
        buttonPanel.add(exitButton);
        this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    }

    /**
     * 监听按钮
     *
     * @param evt
     */
    public void actionPerformed(ActionEvent evt) {
        Object src = evt.getSource();
        if (src == printTextButton)
            printTextAction();
        else if (src == previewButton)
            previewAction();
        else if (src == printText2Button)
            printText2Action();
        else if (src == printFileButton)
            printFileAction();
        else if (src == printFrameButton)
            printFrameAction();
        else if (src == exitButton)
            exitApp();
    }

    /**
     * 打印测试
     */
    private void printTextAction() {
        printStr = area.getText().trim();
        if (printStr != null && printStr.length() > 0) {
            PAGES = getPagesCount(printStr);
            PrinterJob myPrtJob = PrinterJob.getPrinterJob();
            PageFormat pageFormat = myPrtJob.defaultPage();
            myPrtJob.setPrintable(this, pageFormat);
            if (myPrtJob.printDialog()) {
                try {
                    myPrtJob.print();
                } catch (PrinterException pe) {
                    pe.printStackTrace();
                }
            }
        } else {
            // 需要输入内容
            JOptionPane.showConfirmDialog(null, "对不起,打印作业为空,打印取消!", "提示"
                    , JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 打印预览
     */
    private void previewAction() {
        printStr = area.getText().trim();
        PAGES = getPagesCount(printStr);
        (new PrintPreviewDialog(this, "打印预览", true, this, printStr)).setVisible(true);
    }

    private void printText2Action() {
        printStr = area.getText().trim();
        if (printStr != null && printStr.length() > 0) {
            PAGES = getPagesCount(printStr);
            DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
            PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
            DocPrintJob job = printService.createPrintJob();
            PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
            DocAttributeSet das = new HashDocAttributeSet();
            Doc doc = new SimpleDoc(this, flavor, das);

            try {
                job.print(doc, pras);
            } catch (PrintException pe) {
                pe.printStackTrace();
            }
        } else {
            JOptionPane.showConfirmDialog(null, "Sorry, Printer Job is Empty, Print Cancelled!", "Empty"
                    , JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
        }
    }

    private void printFileAction() {
        JFileChooser fileChooser = new JFileChooser(SystemProperties.USER_DIR);
        int state = fileChooser.showOpenDialog(this);
        if (state == fileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
            DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
            PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
            PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
            PrintService service = ServiceUI.printDialog(null, 200, 200, printService
                    , defaultService, flavor, pras);
            if (service != null) {
                try {
                    DocPrintJob job = service.createPrintJob();
                    FileInputStream fis = new FileInputStream(file);
                    DocAttributeSet das = new HashDocAttributeSet();
                    Doc doc = new SimpleDoc(fis, flavor, das);
                    job.print(doc, pras);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void printFrameAction() {
        Toolkit kit = Toolkit.getDefaultToolkit();
        Properties props = new Properties();
        props.put("awt.print.printer", "durango");
        props.put("awt.print.numCopies", "2");
        if (kit != null) {
            PrintJob printJob = kit.getPrintJob(this, "Print Frame", props);
            if (printJob != null) {
                Graphics pg = printJob.getGraphics();
                if (pg != null) {
                    try {
                        this.printAll(pg);
                    } finally {
                        pg.dispose();
                    }
                }
                printJob.end();
            }
        }
    }

    /**
     * 退出
     */
    private void exitApp() {
        this.setVisible(false);
        this.dispose();
        System.exit(0);
    }


    /**
     * 获取页数数量
     *
     * @param curStr
     * @return
     */
    public int getPagesCount(String curStr) {
        int page = 0;
        int position, count = 0;
        String str = curStr;
        while (str.length() > 0) {
            position = str.indexOf('\n');
            count += 1;
            if (position != -1)
                str = str.substring(position + 1);
            else
                str = "";
        }

        if (count > 0)
            page = count / 54 + 1;

        return page;
    }

    /**
     * 打印模板
     *
     * @param g    将页面绘制到其中的上下文
     * @param pf   正在绘制的页面的大小和方向
     * @param page 要绘制的页的从零开始的索引
     * @return
     * @throws PrinterException
     */
    @Override
    public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
        // 转换成Graphics2D
        Graphics2D g2 = (Graphics2D) g;
        // 设置打印颜色为黑
        // 抗锯齿就是减少图形边缘的锯齿状像素格,使画面看上去更精细而不是满屏的马赛克
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.black);// 黑色

        // 打印起点坐标 对象的可成像区域左上方点的x 坐标 和左上的y坐标
        double x = pf.getImageableX();// 返回与此 PageFormat 相关 Paper
        double y = pf.getImageableY();

        switch (page) {
            case 0:
                // 新建 个打印字体样式(1.字体名称 2.样式(加粗).3字号大小
                Font font = new Font("微软雅黑", Font.PLAIN, 16);
                // 给g2设置字体
                g2.setFont(font);
                // 保存虚线的宽
                float[] dash1 = {2.0f};
                // 设置打印线的属 1.线宽 2 3、不知道 4、空白的宽度 5、虚线的宽度 6、偏移量
                g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
                float fontHeigth1 = font.getSize2D();// 字体大小

                // 左上40起点  中间160  右边400起点
                // 240高起点
                // 标题 (渲染的值,X轴,Y轴)
                g2.drawString(weighingListDTO.getUnitName(), 220, 40);

                // 如果把握不好尺寸就打印(g2.drawString(weighingListDTO.getUnitName() + "2", 50, 20);),然后再自己慢慢推敲出来想要的位置
                // g2.drawString(weighingListDTO.getUnitName() + "2", 50, 20);
                // g2.drawString(weighingListDTO.getUnitName() + "3", 60, 40);
                // g2.drawString(weighingListDTO.getUnitName() + "4", 70, 60);
                // g2.drawString(weighingListDTO.getUnitName() + "5", 80, 80);
                // g2.drawString(weighingListDTO.getUnitName() + "6", 90, 100);
                // g2.drawString(weighingListDTO.getUnitName() + "7", 100, 120);
                // g2.drawString(weighingListDTO.getUnitName() + "8", 110, 140);
                // g2.drawString(weighingListDTO.getUnitName() + "9", 120, 160);
                // g2.drawString(weighingListDTO.getUnitName() + "11", 130, 180);
                // g2.drawString(weighingListDTO.getUnitName() + "12", 140, 200);
                // g2.drawString(weighingListDTO.getUnitName() + "13", 150, 220);
                // g2.drawString(weighingListDTO.getUnitName() + "14", 160, 240);
                // g2.drawString(weighingListDTO.getUnitName() + "15", 170, 260);


                // 新建个字体
                Font font2 = new Font("微软雅黑", Font.PLAIN, 10);
                g2.setFont(font2);// 设置字体
                g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
                float fontHeigth2 = (int) font.getSize2D();// 字体2的高
                int tempHeight = (int) (fontHeigth1 * 2 + 50);// 临时高。字体1的高2倍 +50
                Integer hang_juInteger = 15;// 行距


                g2.drawString(weighingListDTO.getClientName(), 40, 60); 客户/供应商
                g2.drawString(weighingListDTO.getPlateNumber(), 250, 60);// 车牌号
                g2.drawString(weighingListDTO.getOrderNo(), 440, 60);// 磅单号

                int listY = 80;
                for (GoodsDTO dto : weighingListDTO.getList()) {
                    // 物料名称
                    g2.drawString(dto.getGoodsName(), 40, listY);
                    // 件数
                    g2.drawString(dto.getNumber(), 90,listY);
                    // 皮重
                    g2.drawString(dto.getTare(), 130,listY);
                    // 毛重
                    g2.drawString(dto.getGrossWeight(), 170,listY);
                    // 净重
                    g2.drawString(dto.getSuttle(), 210,listY);
                    // 纯净重
                    g2.drawString(dto.getSuttle(), 250,listY);
                    // 轻榜时间
                    g2.drawString(dto.getQingTime(), 320,listY);
                   // 重磅时间
                    g2.drawString(dto.getZhongTime(), 430,listY);
                    listY += 20;// 每行间距20像素
                }

                // 司机签名
                g2.drawString(weighingListDTO.getSjName(), 40,230);
                // // 司机电话
                g2.drawString(weighingListDTO.getSjPhone(), 160,230 );
                // // 一式三联
                g2.drawString(weighingListDTO.getYssl(), 500, 230);
                return PAGE_EXISTS;
            default:
                return NO_SUCH_PAGE;
        }
    }

}

注意:💖

如果要改成接口触发打印就需要改一下启动类,否则会报错:java.awt.HeadlessException: null

@SpringBootApplication
public class PrinterJgApplication {
    public static void main(String[] args) {
        SpringApplicationBuilder builder = new SpringApplicationBuilder(PrinterJgApplication.class);
        builder.headless(false).run(args);
    }
}

到此绘画完毕!!!如果需要绘制表格请往下看!!!

绘制表格👍

替换PrintHelp代码

package com.scwl.printer_jg.utils;


import cn.hutool.core.date.LocalDateTimeUtil;
import com.scwl.printer_jg.model.GoodsDTO;
import com.scwl.printer_jg.model.WeighingList;
import com.scwl.printer_jg.model.WeighingListDTO;

import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.HashDocAttributeSet;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.*;
import java.io.File;
import java.io.FileInputStream;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Properties;

/**
 * @author 小影
 * @create 2023-12-05 17:05
 * @describe: JFrame:Java图形化界面设计——容器
 * java.awt.print.Printable动作事件监听器
 * java.awt.print.Printable:通用的打印 API 提供类和接口
 */
public class PrintHelp extends JFrame implements ActionListener, Printable {
    public PrintHelp() {
        this.setTitle("打印测试");// 窗口标题
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setBounds((int) ((SystemProperties.SCREEN_WIDTH - 800) / 2), (int) ((SystemProperties.SCREEN_HEIGHT - 600) / 2), 800, 600);
        initLayout();
    }

    private WeighingList weighingList;// 参数实体类
    private WeighingListDTO weighingListDTO;// 参数实体类
    private int PAGES = 0;
    private JTextArea area = new JTextArea();// 用来创建一个默认的文本域
    private JPanel buttonPanel = new JPanel();// 创建面板
    private JScrollPane scroll = new JScrollPane(area);// 创建窗口
    private String printStr;
    private JButton printTextButton = new JButton("打印测试");
    private JButton previewButton = new JButton("打印预览");
    private JButton printText2Button = new JButton("打印测试2");
    private JButton printFileButton = new JButton("打印文件");
    private JButton printFrameButton = new JButton("Print Frame");
    private JButton exitButton = new JButton("退出");


    public static void main(String[] args) throws PrinterException {
        Book book = new Book();
        PageFormat pf = new PageFormat();
        pf.setOrientation(PageFormat.PORTRAIT);
        Paper p = new Paper();
        p.setSize(595, 283);// 纸张大小单位是像素
        p.setImageableArea(1, 5, 590, 282);
        pf.setPaper(p);
        WeighingListDTO datas = new WeighingListDTO();
        datas.setUnitName("xxxx有限公司称重计量单");
        datas.setClientName("客户名称: xxxx科技有限公司");
        datas.setPlateNumber("闽C:66666");
        datas.setOrderNo("过磅单:GB88888888");
        datas.setSjName("司机签名:");
        datas.setSjPhone("司机电话:");
        datas.setYssl("一式三联");

        ArrayList<GoodsDTO> goodList = new ArrayList<>();
        GoodsDTO goods = new GoodsDTO();
        GoodsDTO goods2 = new GoodsDTO();
        goods.setGoodsName("物料名称");
        goods.setNumber("件数");
        goods.setTare("皮重");
        goods.setGrossWeight("毛重");
        goods.setSuttle("净重");
        goods.setCSuttle("纯净重");
        goods.setQingTime("轻磅时间");
        goods.setZhongTime("重磅时间");

        goods2.setGoodsName("皂角");
        goods2.setNumber("100");
        goods2.setTare("15.76");
        goods2.setGrossWeight("49.80");
        goods2.setSuttle("34.0400");
        goods2.setCSuttle("34.0400");
        goods2.setQingTime("2023/12/22 09:30:00");
        goods2.setZhongTime("2023/12/22 10:30:00");
        goodList.add(goods);
        goodList.add(goods2);
        datas.setList(goodList);


        PrintHelp printHelp = new PrintHelp();
        printHelp.init(datas);
        book.append(printHelp, pf);
        PrinterJob job = PrinterJob.getPrinterJob();
        job.setPageable(book);
        // job.print();//进行打印
        printHelp.setVisible(true); // 打印窗口
    }

    public void init(WeighingList datas) {
        this.weighingList = datas;
    }

    public void init(WeighingListDTO datas) {
        this.weighingListDTO = datas;
    }


    private void initLayout() {
        this.getContentPane().setLayout(new BorderLayout());
        this.getContentPane().add(scroll, BorderLayout.CENTER);
        printTextButton.setMnemonic('P');
        printTextButton.addActionListener(this);
        buttonPanel.add(printTextButton);
        previewButton.setMnemonic('v');
        previewButton.addActionListener(this);
        buttonPanel.add(previewButton);
        printText2Button.setMnemonic('e');
        printText2Button.addActionListener(this);
        buttonPanel.add(printText2Button);
        printFileButton.setMnemonic('i');
        printFileButton.addActionListener(this);
        buttonPanel.add(printFileButton);
        printFrameButton.setMnemonic('F');
        printFrameButton.addActionListener(this);
        buttonPanel.add(printFrameButton);
        exitButton.setMnemonic('x');
        exitButton.addActionListener(this);
        buttonPanel.add(exitButton);
        this.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    }

    /**
     * 监听按钮
     *
     * @param evt
     */
    public void actionPerformed(ActionEvent evt) {
        Object src = evt.getSource();
        if (src == printTextButton)
            printTextAction();
        else if (src == previewButton)
            previewAction();
        else if (src == printText2Button)
            printText2Action();
        else if (src == printFileButton)
            printFileAction();
        else if (src == printFrameButton)
            printFrameAction();
        else if (src == exitButton)
            exitApp();
    }

    /**
     * 打印测试
     */
    private void printTextAction() {
        printStr = area.getText().trim();
        if (printStr != null && printStr.length() > 0) {
            PAGES = getPagesCount(printStr);
            PrinterJob myPrtJob = PrinterJob.getPrinterJob();
            PageFormat pageFormat = myPrtJob.defaultPage();
            myPrtJob.setPrintable(this, pageFormat);
            if (myPrtJob.printDialog()) {
                try {
                    myPrtJob.print();
                } catch (PrinterException pe) {
                    pe.printStackTrace();
                }
            }
        } else {
            // 需要输入内容
            JOptionPane.showConfirmDialog(null, "对不起,打印作业为空,打印取消!", "提示"
                    , JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
        }
    }

    /**
     * 打印预览
     */
    private void previewAction() {
        printStr = area.getText().trim();
        PAGES = getPagesCount(printStr);
        (new PrintPreviewDialog(this, "打印预览", true, this, printStr)).setVisible(true);
    }

    private void printText2Action() {
        printStr = area.getText().trim();
        if (printStr != null && printStr.length() > 0) {
            PAGES = getPagesCount(printStr);
            DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
            PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
            DocPrintJob job = printService.createPrintJob();
            PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
            DocAttributeSet das = new HashDocAttributeSet();
            Doc doc = new SimpleDoc(this, flavor, das);

            try {
                job.print(doc, pras);
            } catch (PrintException pe) {
                pe.printStackTrace();
            }
        } else {
            JOptionPane.showConfirmDialog(null, "Sorry, Printer Job is Empty, Print Cancelled!", "Empty"
                    , JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE);
        }
    }

    private void printFileAction() {
        JFileChooser fileChooser = new JFileChooser(SystemProperties.USER_DIR);
        int state = fileChooser.showOpenDialog(this);
        if (state == fileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
            DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
            PrintService printService[] = PrintServiceLookup.lookupPrintServices(flavor, pras);
            PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
            PrintService service = ServiceUI.printDialog(null, 200, 200, printService
                    , defaultService, flavor, pras);
            if (service != null) {
                try {
                    DocPrintJob job = service.createPrintJob();
                    FileInputStream fis = new FileInputStream(file);
                    DocAttributeSet das = new HashDocAttributeSet();
                    Doc doc = new SimpleDoc(fis, flavor, das);
                    job.print(doc, pras);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void printFrameAction() {
        Toolkit kit = Toolkit.getDefaultToolkit();
        Properties props = new Properties();
        props.put("awt.print.printer", "durango");
        props.put("awt.print.numCopies", "2");
        if (kit != null) {
            PrintJob printJob = kit.getPrintJob(this, "Print Frame", props);
            if (printJob != null) {
                Graphics pg = printJob.getGraphics();
                if (pg != null) {
                    try {
                        this.printAll(pg);
                    } finally {
                        pg.dispose();
                    }
                }
                printJob.end();
            }
        }
    }

    /**
     * 退出
     */
    private void exitApp() {
        this.setVisible(false);
        this.dispose();
        System.exit(0);
    }


    /**
     * 获取页数数量
     *
     * @param curStr
     * @return
     */
    public int getPagesCount(String curStr) {
        int page = 0;
        int position, count = 0;
        String str = curStr;
        while (str.length() > 0) {
            position = str.indexOf('\n');
            count += 1;
            if (position != -1)
                str = str.substring(position + 1);
            else
                str = "";
        }

        if (count > 0)
            page = count / 54 + 1;

        return page;
    }

    private static final int CELL_SIZE = 82; // 表格宽度
    private static final int MARGIN = 40; // 表格高度
    private static final int TABLE_WIDTH = 7; // 几根竖线
    private static final int TABLE_HEIGHT = 4; // 几根横线

    private void drawTable(Graphics2D g2d) { // 自定义一个方法,用于绘制表格的行和列
        g2d.setColor(Color.BLACK); // 设置绘制的颜色为黑色
        int width = getWidth(); // 获取组件的宽度
        int height = getHeight(); // 获取组件的高度
        int startX = MARGIN; // 设置绘制的起始位置为边缘间距
        int startY = MARGIN; // 设置绘制的起始位置为边缘间距
        for (int i = 0; i < TABLE_HEIGHT; i++) { // 循环绘制表格的行
            // 竖线:x1:起点X轴 y1:起点Y轴  x2:终点X轴 y2:终点Y轴
            drawLine(g2d, startX, 75 + i * 20, 540, 75 + i * 20); // 绘制行之间的分隔线
        }
        for (int i = 0; i < TABLE_WIDTH; i++) { // 循环绘制表格的列
            if (i == 0) {
                // 竖线:x1:起点X轴 y1:起点Y轴  x2:终点X轴 y2:终点Y轴
                drawLine(g2d, startX + i * CELL_SIZE, 75, startX + i * CELL_SIZE, 135); // 绘制列之间的分隔线
            } else if (i % 2 == 0) {
                // 竖线:x1:起点X轴 y1:起点Y轴  x2:终点X轴 y2:终点Y轴
                drawLine(g2d, startX + i * CELL_SIZE +9, 75, startX + i * CELL_SIZE + 9, 135); // 绘制列之间的分隔线
            } else {
                // 竖线:x1:起点X轴 y1:起点Y轴  x2:终点X轴 y2:终点Y轴
                drawLine(g2d, (startX + i * CELL_SIZE) - 15, 75, (startX + i * CELL_SIZE) - 15, 135); // 绘制列之间的分隔线
            }
        }
    }

    /**
     * @param g2d   用于在组件上进行绘制2D图形。
     * @param x1、y1 这两个参数定义了线的起始点的坐标。
     * @param x2、y2 这两个参数定义了线的终点的坐标。
     */
    private void drawLine(Graphics2D g2d, int x1, int y1, int x2, int y2) { // 自定义一个方法,用于绘制直线
        g2d.drawLine(x1, y1, x2, y2); // 使用Graphics2D的drawLine方法绘制直线
    }

    /**
     * 打印模板
     *
     * @param g    将页面绘制到其中的上下文
     * @param pf   正在绘制的页面的大小和方向
     * @param page 要绘制的页的从零开始的索引
     * @return
     * @throws PrinterException
     */
    @Override
    public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
        // 转换成Graphics2D
        Graphics2D g2 = (Graphics2D) g;
        // 设置打印颜色为黑
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2.setColor(Color.black);

        // 打印起点坐标 对象的可成像区域左上方点的x 坐标 和左上的y坐标
        double x = pf.getImageableX();// 返回与此 PageFormat 相关 Paper
        double y = pf.getImageableY();
        // 绘制表格
        drawTable(g2);
        switch (page) {
            case 0:
                // 新建 个打印字体样式(1.字体名称 2.样式(加粗).3字号大小
                Font font = new Font("微软雅黑", Font.PLAIN, 16);
                // 给g2设置字体
                g2.setFont(font);
                // 保存虚线的宽
                float[] dash1 = {2.0f};
                // 设置打印线的属 1.线宽 2 3、不知道 4、空白的宽度 5、虚线的宽度 6、偏移量
                g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
                float fontHeigth1 = font.getSize2D();// 字体大小

                // 左上40起点  中间160  右边400起点
                // 240高起点
                // 标题
                g2.drawString(weighingListDTO.getUnitName(), 180, 40);

                // g2.drawString(weighingListDTO.getUnitName() + "2", 50, 20);
                // g2.drawString(weighingListDTO.getUnitName() + "3", 60, 40);
                // g2.drawString(weighingListDTO.getUnitName() + "4", 70, 60);
                // g2.drawString(weighingListDTO.getUnitName() + "5", 80, 80);
                // g2.drawString(weighingListDTO.getUnitName() + "6", 90, 100);
                // g2.drawString(weighingListDTO.getUnitName() + "7", 100, 120);
                // g2.drawString(weighingListDTO.getUnitName() + "8", 110, 140);
                // g2.drawString(weighingListDTO.getUnitName() + "9", 120, 160);
                // g2.drawString(weighingListDTO.getUnitName() + "11", 130, 180);
                // g2.drawString(weighingListDTO.getUnitName() + "12", 140, 200);
                // g2.drawString(weighingListDTO.getUnitName() + "13", 150, 220);
                // g2.drawString(weighingListDTO.getUnitName() + "14", 160, 240);
                // g2.drawString(weighingListDTO.getUnitName() + "15", 170, 260);


                // 新建个字体
                Font font2 = new Font("微软雅黑", Font.PLAIN, 10);
                g2.setFont(font2);// 设置字体
                g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
                float fontHeigth2 = (int) font.getSize2D();// 字体2的高
                int tempHeight = (int) (fontHeigth1 * 2 + 50);// 临时高。字体1的高2倍 +50
                Integer hang_juInteger = 15;// 行距


                g2.drawString("单位名称:厦门三川万里科技有限公司", 40, 70); 客户/供应商
                g2.drawString("系统磅单号:GB2024010211", 230, 70); 客户/供应商
                g2.drawString("打印时间:" + LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"), 390, 70);

            {
                g2.drawString("物料名称", 55, 90);
                g2.drawString("皂角", 40 + CELL_SIZE, 90);

                g2.drawString("毛重 (吨)", 55 + CELL_SIZE * 2, 90);
                g2.drawString("39.4500", 40 + CELL_SIZE * 3, 90);

                g2.drawString("净重 (吨)", 55 + CELL_SIZE * 4, 90);
                g2.drawString("39.4500", 40 + CELL_SIZE * 5, 90);

            }

            {
                g2.drawString("件    数", 55, 90 + 20);
                g2.drawString("33", 40 + CELL_SIZE, 90 + 20);

                g2.drawString("皮重 (吨)", 55 + CELL_SIZE * 2, 90 + 20);
                g2.drawString("39.4500", 40 + CELL_SIZE * 3, 90 + 20);

                g2.drawString("纯净重(吨)", 55 + CELL_SIZE * 4, 90 + 20);
                g2.drawString("39.4500", 40 + CELL_SIZE * 5, 90 + 20);
            }

            {
                g2.drawString("车牌号", 55, 90 + 40);
                g2.drawString("闽:C666666", 40 + CELL_SIZE, 90 + 40);

                g2.drawString("轻磅时间", 55 + CELL_SIZE * 2, 90 + 40);
                g2.drawString(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"), 30 + CELL_SIZE * 3, 90 + 40);

                g2.drawString("重磅时间", 55 + CELL_SIZE * 4, 90 + 40);
                g2.drawString(LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"), 30 + CELL_SIZE * 5, 90 + 40);
            }
            g2.drawString("司机签字:小影", 40, 90+60);
            g2.drawString("电话号码:13555555555", 230, 90+60);
            g2.drawString("一式三联" , 500, 90+60);


            return PAGE_EXISTS;
            default:
                return NO_SUCH_PAGE;
        }
    }
    // public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
    //     // 转换成Graphics2D
    //     Graphics2D g2 = (Graphics2D) g;
    //     // 设置打印颜色为黑
    //     g2.setColor(Color.black);
    //
    //     // 打印起点坐标 对象的可成像区域左上方点的x 坐标 和左上的y坐标
    //     double x = pf.getImageableX();// 返回与此 PageFormat 相关 Paper
    //     double y = pf.getImageableY();
    //
    //     switch (page) {
    //         case 0:
    //             // 新建 个打印字体样式(1.字体名称 2.样式(加粗).3字号大小
    //             Font font = new Font("微软雅黑", Font.PLAIN, 23);
    //             // 给g2设置字体
    //             g2.setFont(font);
    //             // 保存虚线的宽
    //             float[] dash1 = {2.0f};
    //             // 设置打印线的属 1.线宽 2 3、不知道 4、空白的宽度 5、虚线的宽度 6、偏移量
    //             g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
    //             float fontHeigth1 = font.getSize2D();// 字体大小
    //             // 标题
    //             String str1 = weighingList.getTitle();
    //             g2.drawString(str1, (int) x + 200, (int) y + fontHeigth1 + 50);
    //             // 新建个字体
    //             Font font2 = new Font("微软雅黑", Font.PLAIN, 14);
    //             g2.setFont(font2);// 设置字体
    //             g2.setStroke(new BasicStroke(0.5f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2.0f, dash1, 0.0f));
    //             float fontHeigth2 = (int) font.getSize2D();// 字体2的高
    //             int tempHeight = (int) (fontHeigth1 * 2 + 50 );// 临时高。字体1的高2倍 +50
    //             Integer hang_juInteger = 15;// 行距
    //
    //             String line1 = "company";
    //             line1 = line1.replaceAll("company", this.weighingList.getCompany());
    //             g2.drawString(line1, (int) x + 150, (int) y + fontHeigth2 + hang_juInteger + tempHeight);
    //
    //             String line2 = "客户:clientName";
    //             line2 = line2.replaceAll("clientName", this.weighingList.getClientName());
    //             g2.drawString(line2, (int) x + 150, (int) y + fontHeigth2 * 1 + hang_juInteger + (hang_juInteger * 1) + tempHeight);
    //
    //             String line3 = "序号:serialNumber";
    //             line3 = line3.replaceAll("serialNumber", this.weighingList.getSerialNumber());
    //             g2.drawString(line3,(int)x+170,(int)y+(int) y + fontHeigth2* 2  + hang_juInteger + tempHeight);
    //
    //             String line4 = "日期:date";
    //             line4 = line4.replaceAll("date", this.weighingList.getDate());
    //             g2.drawString(line4,(int)x+170,(int)y+(int) y + fontHeigth2* 3 + hang_juInteger + tempHeight);
    //
    //             String line5 = "时间:time";
    //             line5 = line5.replaceAll("time", this.weighingList.getTime());
    //             g2.drawString(line5,(int)x+170,(int)y+(int) y + fontHeigth2 *4+ hang_juInteger + tempHeight);
    //
    //             String line6 = "车号:plateNumber";
    //             line6 = line6.replaceAll("plateNumber", this.weighingList.getPlateNumber());
    //             g2.drawString(line6,(int)x+170,(int)y+(int) y + fontHeigth2*5 + hang_juInteger + tempHeight);
    //
    //             String line7 = "货号:itemNo";
    //             line7 = line7.replaceAll("itemNo", this.weighingList.getItemNo());
    //             g2.drawString(line7,(int)x+170,(int)y+(int) y + fontHeigth2 *6+ hang_juInteger + tempHeight);
    //
    //             String line8 = "总重:totalWeight";
    //             line8 = line8.replaceAll("totalWeight", this.weighingList.getTotalWeight());
    //             g2.drawString(line8,(int)x+170,(int)y+(int) y + fontHeigth2*7 + hang_juInteger + tempHeight);
    //
    //             String line9 = "皮重:tare";
    //             line9 = line9.replaceAll("tare", this.weighingList.getTare());
    //             g2.drawString(line9,(int)x+170,(int)y+(int) y + fontHeigth2*8 + hang_juInteger + tempHeight);
    //
    //             String line10 = "扣率:kl";
    //             line10 = line10.replaceAll("kl", this.weighingList.getTare());
    //             g2.drawString(line10,(int)x+170,(int)y+(int) y + fontHeigth2 *9+ hang_juInteger + tempHeight);
    //
    //             String line11 = "皮重:suttle";
    //             line11 = line11.replaceAll("suttle", this.weighingList.getTare());
    //             g2.drawString(line11,(int)x+170,(int)y+(int) y + fontHeigth2 *10+ hang_juInteger + tempHeight);
    //             return PAGE_EXISTS;
    //         default:
    //             return NO_SUCH_PAGE;
    //     }
    // }
}

效果如下:

注意:打印程序如果打印成win的服务来实现自动启动,使用时会报错 java.awt.print.PrinterException: No print service found. 无法找到打印服务,暂无方案只能配置bat启动。如有解决的同志可以评论区分享一下解决方案🌹


后续扩展的🥇

绘制表格效果图🤷‍♀️

绘制二维码条形码😁

如果对您有帮助,帮忙三连一下!❤

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助力现代医院高质量发展方案信息化助
要在Java打印PDF模板,您可以使用iText库。iText是一款基于Java的开源PDF库,可以用于创建、编辑和读取PDF文档。 以下是一个简单的示例代码,演示如何使用iText库打印PDF模板: ```java import com.itextpdf.text.Document; import com.itextpdf.text.PageSize; import com.itextpdf.text.pdf.PdfContentByte; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfTemplate; import com.itextpdf.text.pdf.PdfWriter; import java.io.FileOutputStream; public class PrintTemplate { public static void main(String[] args) { try { // 读取PDF模板文件 PdfReader reader = new PdfReader("template.pdf"); // 创建输出流 FileOutputStream fos = new FileOutputStream("output.pdf"); // 创建PDF文档 Document document = new Document(PageSize.A4); // 创建PDF写入器 PdfWriter writer = PdfWriter.getInstance(document, fos); // 打开文档 document.open(); // 获取PDF页面 PdfContentByte contentByte = writer.getDirectContent(); // 获取PDF页面模板 PdfTemplate template = contentByte.createTemplate(PageSize.A4.getWidth(), PageSize.A4.getHeight()); // 将PDF模板内容绘制到页面模板上 PdfContentByte canvas = writer.getDirectContentUnder(); canvas.addTemplate(template, 0, 0); // 关闭文档 document.close(); // 关闭输出流 fos.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述代码中,我们首先读取PDF模板文件,然后创建一个输出流以便输出打印结果。接着,我们创建一个新的PDF文档,并将其打开。然后,我们获取PDF页面并创建一个页面模板,将PDF模板内容绘制到页面模板上。最后,我们将页面模板添加到PDF页面中,并关闭文档。 请注意,上述示例代码仅演示了如何使用iText库打印PDF模板,并没有包含任何模板内容的替换或修改。如果您需要替换或修改模板内容,可以使用iText库提供的相关API进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值