ページ

2015年11月8日日曜日

WebSocketでファイルアップロード

前回WebSocketを少しいじったので、今回は少し拡張してファイルアップロードを実現してみました。

まずサーバ側はファイル名を受け取るようにしてみました。ちと面倒だったのでテキストメッセージでファイル名を受けたときにファイルをオープンして、ファイルのクローズは切断時に行ってます。(ちなみにGlassFish上で動作させてます。)

--------------------------------------------------
package sample; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.logging.Level; import java.util.logging.Logger; import javax.websocket.OnOpen; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/endpoint") public class NewWSEndpoint { private static FileChannel channel = null; @OnOpen public void onOpen(Session session){ System.out.println("OnOpen"); } @OnClose public void onClose(Session session){ try { System.out.println("OnClose"); channel.close(); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnMessage public String onMessage(Session session, String message) { try { System.out.println("OnMessage String = " + message); channel = new FileOutputStream(new File("../logs/" + message)).getChannel(); } catch (FileNotFoundException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } return null; } @OnMessage public void onMessage(Session session, ByteBuffer byteBuffer) { try { System.out.println("OnMessage binary = " + byteBuffer.toString()); channel.write(byteBuffer); } catch (IOException ex) { Logger.getLogger(NewWSEndpoint.class.getName()).log(Level.SEVERE, null, ex); } } @OnError public void onError(Throwable t) { System.out.println("OnError"); } } --------------------------------------------------

HTMLはシンプルにこんな感じ。
ファイルをドラッグ&ドロップして指定する形を取りました。

--------------------------------------------------
<html> <head> <title>JavaEE7 WebSocket Test</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> <script type="text/javascript" src="app.js"></script> </head> <body> <section id="main"> <div id="drop" style="width:500px; height:150px; padding:10px; border:3px solid" ondragover="onDragOver(event)" ondrop="onDrop(event)">ここにファイルをドロップして下さい</div> <div id="disp" ></div> </section> </body> </html> --------------------------------------------------

JavaScriptはこんな感じ。
指定されたファイルを読み込みバイナリとして送信します。

--------------------------------------------------
if (!window.File) { window.alert("このブラウザではFile APIが使えません"); } function onDrop(event) { var files = event.dataTransfer.files; var disp = document.getElementById("disp"); for (var i = 0; i < files.length; i++) { var f = files[i]; var socket = new WebSocket("ws://localhost:8080/TestWebSocket/endpoint"); socket.onopen = function() { var reader = new FileReader(); reader.onload = function(){ var binary = new Uint8Array(reader.result); socket.send(f.name); socket.send(binary.buffer); socket.close(); disp.innerHTML = f.name + "[" + f.size + "byte]" + "アップロード完了"; }; reader.readAsArrayBuffer(f); }; } event.preventDefault(); } function onDragOver(event) { event.preventDefault(); } --------------------------------------------------

あとは大きなファイルでも経過を表示したりできるように分割送信とかするといいでしょうね。