Para llevar a cabo la solución, vamos a utilizar una implementación open source (Project Tyrus) de la especificación JSR 356 - Java API for WebSocket para establecer la comunicación entre la aplicación web y el servidor que deberá estar ejecutándose en la maquina cliente y que recibirá mediante WebSocket el documento a imprimir y enviar este a la impresora. A continuación los pasos a realizar utilizando el IDE IntelliJ IDEA:
PASO 1: Creación del proyecto Tyrus donde se definirá el WebSocket endpoint y el servidor
PASO 2: Agregar las dependencias maven necesarias para la creación de nuestro servidor Tyrus
<dependencies> <dependency> <groupId>org.glassfish.tyrus</groupId> <artifactId>tyrus-server</artifactId> <version>1.13</version> </dependency> <dependency> <groupId>org.glassfish.tyrus</groupId> <artifactId>tyrus-container-grizzly-server</artifactId> <version>1.13</version> </dependency> </dependencies>
PASO 3: Implementación del endpoint server FileServerEndpoint
package ws.serverprinter.server; import java.io.*; import java.nio.ByteBuffer; import javax.websocket.CloseReason; import javax.websocket.EndpointConfig; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/receive/fileserver") public class FileServerEndpoint { static ByteArrayOutputStream baos = null; @OnOpen public void open(Session session, EndpointConfig conf) { System.out.println("FileServerEndpoint is open"); } @OnMessage public void processUpload(ByteBuffer msg, boolean last, Session session) { System.out.println("ByteBuffer message"); while(msg.hasRemaining()) { baos.write(msg.get()); } } @OnMessage public void message(Session session, String msg) { System.out.println("Message: " + msg); if(!msg.equals("end")) { baos = new ByteArrayOutputStream(); }else { try { baos.flush(); baos.close(); } catch (IOException e) { e.printStackTrace(); } } } @OnClose public void close(Session session, CloseReason reason) { System.out.println("WebSocket closed: "+ reason.getReasonPhrase()); } @OnError public void error(Session session, Throwable t) { t.printStackTrace(); } }
PASO 4: Implementación de la aplicación principal y el server Tyrus
package ws.serverprinter.server; import org.glassfish.tyrus.server.Server; import java.io.BufferedReader; import java.io.InputStreamReader; /** * Created by williams on 19-07-16. */ public class MainApp { public static void main(String[] args) { runServer(); } private static void runServer() { Server server = new Server("localhost", 8025, "/websockets", null, FileServerEndpoint.class); try { server.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.print("Press a key to stop the server."); reader.readLine(); } catch (Exception e) { e.printStackTrace(); } finally { server.stop(); } } }
PASO 5: Desarrollo de la aplicación cliente
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Chat</title> </head> <body> <h2>File Upload</h2> Select file <input type="file" id="filename" /> <br> <input type="button" value="Connect" onclick="connect()" /> <br> <input type="button" value="Upload" onclick="sendFile()" /> <script> var ws; function connect() { ws = new WebSocket("ws://localhost:8025/websockets/receive/fileserver"); ws.binaryType = "arraybuffer"; ws.onopen = function() { alert("Connected.") }; ws.onmessage = function(evt) { alert(evt.msg); }; ws.onclose = function() { alert("Connection closed..."); }; ws.onerror = function(e) { alert(e.msg); } } function sendFile() { var file = document.getElementById('filename').files[0]; ws.send('filename:'+file.name); var reader = new FileReader(); var rawData = new ArrayBuffer(); reader.loadend = function() {} reader.onload = function(e) { rawData = e.target.result; ws.send(rawData); alert("file transferred.") ws.send('end'); } reader.readAsArrayBuffer(file); } </script> </body> </html>
PASO 6: Implementación del servicio de impresión
@OnMessage public void message(Session session, String msg) { System.out.println("Message: " + msg); if(!msg.equals("end")) { baos = new ByteArrayOutputStream(); }else { try { baos.flush(); baos.close(); print(baos); } catch (IOException e) { e.printStackTrace(); } catch (PrintException e) { e.printStackTrace(); } } } private void print(ByteArrayOutputStream baos) throws PrintException { PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null); if (services.length > 0) { DocFlavor psInFormat = DocFlavor.INPUT_STREAM.AUTOSENSE; Doc myDoc = new SimpleDoc(new ByteArrayInputStream(baos.toByteArray()), psInFormat, null); DocPrintJob job = services[0].createPrintJob(); job.print(myDoc, null); } }
PASO 7: Iniciamos el server Tyrus
PASO 8: Adjuntamos algún archivo PDF desde nuestra aplicación cliente y lo enviamos al server
Se puede observar como el archivo se envió directamente a la impresora.
Fuentes:
https://tyrus.java.net/documentation/1.13/user-guide.html#standalone-mode http://stackoverflow.com/questions/21769470/file-upload-using-java-websocket-api-and-javascript http://docs.oracle.com/javase/7/docs/api/javax/print/package-summary.html https://java.net/projects/websocket-spec
Github: https://github.com/ghwrivas/server-printer-ws