Linux环境JBoss上Java Web应用对接Windows打印服务器的技术问询
Alright, let's break down how to get this working for your Java web app running on JBoss (Linux) targeting that Windows print server's Building1Room15 printer. Since CUPS isn't an option, we need to work directly with Windows' SMB printing protocol—this is the native way Windows shares printers over the network. Here's a step-by-step approach with code examples:
Java's native javax.print API doesn't support SMB printing out of the box, so you'll need a library to handle the SMB connection to the Windows server. SMBJ is a modern, maintained replacement for the older JCIFS library and works well for this use case.
First, add the SMBJ dependency to your project (if using Maven):
<dependency> <groupId>com.hierynomus</groupId> <artifactId>smbj</artifactId> <version>0.10.0</version> <!-- Grab the latest stable version from Maven Central --> </dependency>
PrintServiceLookup for SMB Printers Java's PrintServiceLookup allows you to extend its default printer discovery logic. We'll create a custom implementation that connects to the Windows server, finds the shared printer by name, and wraps it into a javax.print.PrintService instance that your app can use.
Custom Lookup Class
import com.hierynomus.smbj.SMBClient; import com.hierynomus.smbj.auth.AuthenticationContext; import com.hierynomus.smbj.connection.Connection; import com.hierynomus.smbj.session.Session; import com.hierynomus.smbj.share.PrinterShare; import javax.print.PrintService; import javax.print.PrintServiceLookup; import javax.print.attribute.AttributeSet; import java.util.ArrayList; import java.util.List; public class SMBPrintServiceLookup extends PrintServiceLookup { private final String printServerName; private final String domainOrUsername; private final String password; // Constructor: pass in your Windows server details and credentials public SMBPrintServiceLookup(String printServerName, String domainOrUsername, String password) { this.printServerName = printServerName; this.domainOrUsername = domainOrUsername; this.password = password; } @Override protected PrintService[] getPrintServices(String printerNameFilter, AttributeSet attributes) { List<PrintService> matchingPrinters = new ArrayList<>(); try (SMBClient smbClient = new SMBClient()) { // Connect to the Windows print server try (Connection connection = smbClient.connect(printServerName)) { AuthenticationContext authCtx = new AuthenticationContext( domainOrUsername, password.toCharArray(), null // Leave as null if not using a domain ); try (Session session = connection.authenticate(authCtx)) { // Connect to the specific printer share (Building1Room15) PrinterShare printerShare = (PrinterShare) session.connectShare("Building1Room15"); // Wrap the SMB printer share into a Java PrintService implementation matchingPrinters.add(new SMBPrintService(printerShare)); } } } catch (Exception e) { // Handle exceptions gracefully in production (e.g., log errors) e.printStackTrace(); } return matchingPrinters.toArray(new PrintService[0]); } @Override protected PrintService getDefaultPrintService() { // Return null or implement logic if you need a default printer return null; } }
Custom PrintService Implementation
We need to wrap the SMB PrinterShare into a class that implements Java's PrintService interface. This bridges the SMB library to the standard Java printing API:
import com.hierynomus.smbj.share.PrinterShare; import javax.print.Doc; import javax.print.DocFlavor; import javax.print.PrintService; import javax.print.PrintServiceAttributeSet; import javax.print.attribute.AttributeSet; import javax.print.attribute.HashPrintServiceAttributeSet; import javax.print.event.PrintServiceAttributeListener; public class SMBPrintService implements PrintService { private final PrinterShare smbPrinter; private final PrintServiceAttributeSet printerAttributes; public SMBPrintService(PrinterShare smbPrinter) { this.smbPrinter = smbPrinter; this.printerAttributes = new HashPrintServiceAttributeSet(); // Add relevant printer attributes here (e.g., printer name) } @Override public String getName() { return smbPrinter.getName(); } @Override public DocFlavor[] getSupportedDocFlavors() { // Return the document formats your Windows printer supports // Common options: PDF, PostScript, or PCL return new DocFlavor[]{ DocFlavor.INPUT_STREAM.PDF, DocFlavor.INPUT_STREAM.POSTSCRIPT }; } @Override public boolean isDocFlavorSupported(DocFlavor flavor) { for (DocFlavor supported : getSupportedDocFlavors()) { if (supported.equals(flavor)) return true; } return false; } @Override public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) { // Implement logic to return unsupported attributes (if needed) return null; } @Override public PrintServiceAttributeSet getAttributes() { return printerAttributes; } @Override public void addPrintServiceAttributeListener(PrintServiceAttributeListener listener) { // Add listener logic if you need to track printer attribute changes } @Override public void removePrintServiceAttributeListener(PrintServiceAttributeListener listener) { // Remove listener logic } @Override public javax.print.PrintJob createPrintJob() { // Return a custom print job that uses the SMB printer share return new SMBPrintJob(smbPrinter); } }
Custom PrintJob Implementation
Finally, create a PrintJob that handles sending the document to the SMB printer:
import com.hierynomus.smbj.share.PrinterShare; import javax.print.Doc; import javax.print.DocPrintJob; import javax.print.PrintException; import javax.print.event.PrintJobAttributeListener; import javax.print.event.PrintJobListener; import java.io.InputStream; public class SMBPrintJob implements DocPrintJob { private final PrinterShare smbPrinter; public SMBPrintJob(PrinterShare smbPrinter) { this.smbPrinter = smbPrinter; } @Override public void print(Doc doc, javax.print.attribute.PrintRequestAttributeSet attributes) throws PrintException { try { // Get the document input stream (e.g., PDF file stream) InputStream docStream = (InputStream) doc.getDocData(); // Send the document to the Windows printer via SMB smbPrinter.print(docStream, doc.getDocFlavor().getMediaType()); } catch (Exception e) { throw new PrintException("Failed to send document to printer", e); } } @Override public void addPrintJobListener(PrintJobListener listener) { // Add print job event listener logic if needed } @Override public void removePrintJobListener(PrintJobListener listener) { // Remove print job listener logic } @Override public void addPrintJobAttributeListener(PrintJobAttributeListener listener) { // Add attribute listener logic if needed } @Override public void removePrintJobAttributeListener(PrintJobAttributeListener listener) { // Remove attribute listener logic } }
In your web app (e.g., during initialization), register the custom SMBPrintServiceLookup and search for your printer:
// Initialize the lookup with your Windows server details SMBPrintServiceLookup smbLookup = new SMBPrintServiceLookup( "Building1Room15", // Replace with your Windows print server hostname/IP "your-windows-username", "your-windows-password" ); // Register the custom lookup with Java's print service system PrintServiceLookup.registerServiceProvider(smbLookup); // Find the printer by name PrintService targetPrinter = null; PrintService[] allServices = PrintServiceLookup.lookupPrintServices(null, null); for (PrintService service : allServices) { if ("Building1Room15".equals(service.getName())) { targetPrinter = service; break; } } // Use the printer to print your document if (targetPrinter != null) { DocPrintJob printJob = targetPrinter.createPrintJob(); // Prepare your document (e.g., load a PDF as InputStream) // Doc doc = new SimpleDoc(pdfInputStream, DocFlavor.INPUT_STREAM.PDF, null); // printJob.print(doc, null); } else { // Handle case where printer wasn't found }
- Credentials: Store Windows credentials securely (e.g., JBoss vault, environment variables) instead of hardcoding them.
- Permissions: Ensure the Windows user account has print access to the
Building1Room15printer share. - Error Handling: Add robust logging and exception handling for connection issues, printer access failures, and unsupported document formats.
- Doc Formats: Verify which document formats your Windows printer supports—some may require converting your output to PCL or PostScript if PDF isn't natively supported.
内容的提问来源于stack exchange,提问作者Jason

