You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java应用开发:监听打印队列并按文档属性重定向作业

Java监听打印队列并获取作业文档属性的解决方案

核心问题说明

JDK自带的javax.print API仅能获取打印作业的基础状态(如队列计数、作业ID),无法直接获取文档名称、内容等关键属性,必须依赖系统原生打印服务API或第三方库实现。以下分平台给出具体实现方案:


Windows平台实现

通过JNA调用Windows打印池(Winspool.drv)的原生API,可直接获取作业的文档名称、内容等属性。

1. 依赖准备

添加JNA及JNA平台依赖(Maven示例):

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.13.0</version>
</dependency>

2. 调用打印池API获取文档名称

定义JNA接口映射Winspool函数,并通过JOB_INFO_2结构体解析作业属性:

import com.sun.jna.Native;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.IntByReference;
import com.sun.jna.Structure;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;

public interface WinSpool extends StdCallLibrary {
    WinSpool INSTANCE = Native.load("winspool.drv", WinSpool.class);

    boolean OpenPrinter(String pPrinterName, WinNT.HANDLEByReference phPrinter, int pDefault);
    boolean EnumJobs(WinNT.HANDLE hPrinter, int firstJob, int noJobs, int level, Structure[] jobs, int cbBuf, IntByReference pcbNeeded, IntByReference pcReturned);
    boolean ClosePrinter(WinNT.HANDLE hPrinter);

    class JOB_INFO_2 extends Structure {
        public int JobId;
        public String pPrinterName;
        public String pMachineName;
        public String pUserName;
        public String pDocument; // 文档名称字段

        @Override
        protected List<String> getFieldOrder() {
            return Arrays.asList("JobId", "pPrinterName", "pMachineName", "pUserName", "pDocument");
        }
    }
}

// 使用示例
public class WindowsPrintMonitor {
    public static void main(String[] args) {
        String targetPrinter = "printspoller";
        WinNT.HANDLEByReference printerHandle = new WinNT.HANDLEByReference();

        if (WinSpool.INSTANCE.OpenPrinter(targetPrinter, printerHandle, 0)) {
            IntByReference pcbNeeded = new IntByReference();
            IntByReference pcReturned = new IntByReference();

            // 先获取所需缓冲区大小
            WinSpool.INSTANCE.EnumJobs(printerHandle.getValue(), 0, 100, 2, null, 0, pcbNeeded, pcReturned);
            int jobCount = pcReturned.getValue();
            WinSpool.JOB_INFO_2[] jobInfos = new WinSpool.JOB_INFO_2[jobCount];

            // 填充作业数据
            if (WinSpool.INSTANCE.EnumJobs(printerHandle.getValue(), 0, jobCount, 2, jobInfos, pcbNeeded.getValue(), pcbNeeded, pcReturned)) {
                for (WinSpool.JOB_INFO_2 job : jobInfos) {
                    System.out.printf("作业ID: %d | 文档名称: %s%n", job.JobId, job.pDocument);
                }
            }

            WinSpool.INSTANCE.ClosePrinter(printerHandle.getValue());
        }
    }
}

3. 获取文档内容

调用ReadPrinter函数可读取作业的原始数据流(RAW/EMF格式),需先通过OpenPrinter获取打印机句柄,再结合作业ID调用该函数。由于打印机型号一致,可直接将数据流转发至目标打印机,无需解析;若需解析内容,需针对数据流格式(如EMF、PDF)使用对应解析库。


Linux/Unix平台实现

基于CUPS(通用UNIX打印系统),可通过命令行工具或CUPS API获取作业属性。

1. 命令行方式快速实现

通过执行系统命令解析打印队列信息:

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class LinuxPrintMonitor {
    public static void main(String[] args) throws Exception {
        // 列出目标打印机的所有作业
        Process process = Runtime.getRuntime().exec("lpstat -o printspoller");
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        
        while ((line = reader.readLine()) != null) {
            // 解析输出格式:<作业ID>-<用户名> <文档名称> <大小> <时间>
            String[] parts = line.split("\\s+");
            String jobId = parts[0].split("-")[0];
            String docName = parts[1];
            System.out.printf("作业ID: %s | 文档名称: %s%n", jobId, docName);
        }

        // 导出作业内容(需root权限或CUPS配置允许)
        // Runtime.getRuntime().exec(String.format("lp -i %s -o raw > job-content.prn", jobId));
    }
}

2. CUPS API方式

使用cups4j库直接调用CUPS的HTTP API,可更灵活地获取作业属性及内容(需添加对应依赖)。


作业重定向逻辑

获取文档名称/内容后,可按以下步骤实现重定向:

  1. 读取作业原始数据流(Windows用ReadPrinter,Linux用CUPS导出)
  2. 基于文档名称或内容匹配目标打印机
  3. 使用javax.print API将数据流提交至目标打印机(因打印机型号一致,无需转换格式)

内容的提问来源于stack exchange,提问作者Hannes Ledl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 21:02:54