ファイルアップロードサンプル(using JSON with JAX-RS and JAXB)
前回2015-11-01 - tomoTakaの日記とは、違ってファイルをJSON形式でアップしてみたかったのちょっと実装してみました。
クライアント側(JavaScript)で選択したファイルを読み込んで、Base64encodeした文字列をサーバにXMLHttpRequestを使って送信。クライアントとサーバ側のJSONデータのバインドは「@XmlRootElement」を「FileInfo.java」クラスにつけて簡単に実現できました。そもそもこの方法がどうかは別として、とにかく動作してので嬉しいです!
クライアント側
- fileupload.html
<h3>file upload (json)</h3> <input type="file" id="fileJson"> <label class="label-info">Destination:</label> <input type="text" value="/tmp" id="destinationJson"> <button class="btn btn-primary" id="uploadBtn">upload</button> <output id="uploadMsg"></output>
- fileupload.js
'use strict'; (function(){ // ファイルアップ(json) var files = []; // アップ対象のファイルを取得 var fileJson = document.getElementById('fileJson'); fileJson.addEventListener('change', function(){ files = this.files; }); // uploadボタンをクリック時 var upbtn = document.getElementById('uploadBtn'); upbtn.addEventListener('click', function(){ if (files.length === 0) { var msg = document.getElementById('uploadMsg'); msg.innerHTML = 'ファイルを選択してください'; msg.classList.add('label-warning'); return; } // 選択したファイルを読み込み var file = files[0]; var reader = new FileReader(); var p = new Promise(function(resolve, reject){ // 1秒以上かかった場合、エラーとする window.setTimeout(function(){ reject('timeout'); }, 1000); reader.onload = (function(){ return function(e){ // 「data:text/plain;base64,xxxxx」がresult、なのでカンマで区切って内容を取得 var fileBase64 = e.target.result.split(',')[1]; resolve(fileBase64); }; })(); }); // 選択したファイルを読込む reader.readAsDataURL(file); // サーバに非同期通信 var XHR = new XMLHttpRequest(); XHR.open('POST', '/FileUploadWeb/webresources/upload'); XHR.setRequestHeader('Content-Type', 'application/json; charset="UTF-8"'); XHR.addEventListener('load', function(e){ var msg = document.getElementById('uploadMsg'); msg.innerHTML = XHR.responseText; msg.classList.add('label-success'); }); p.then( function(fileBase64){ var destination = document.getElementById('destinationJson').value; var data = { 'destination' : destination, 'fileName' : file.name, 'fileType' : file.type, 'file' : fileBase64 }; // ファイル読み込みが終了してから、通信開始 XHR.send(JSON.stringify(data)); }, function(errMsg){ var msg = document.getElementById('uploadMsg'); msg.innerHTML = errMsg; msg.classList.add('label-warning'); }); }); }());
サーバ側
JavaEEのドキュメント「using JSON with JAX-RS and JAXB」の箇所を参考に実装。
- FileInfo.java
@XmlRootElement public class UploadInfo { String destination; String fileName; String fileType; String file; public String getDestination() { return destination; } public void setDestination(String destination) { this.destination = destination; } ...
- ApplicationConfig.java
UploadResource.javaを実装している時に「@javax.ws.rs.Path」アノテーションを指定するとNetBeansが自動でこのクラスを作成。
@javax.ws.rs.ApplicationPath("webresources") public class ApplicationConfig extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> resources = new java.util.HashSet<>(); addRestResourceClasses(resources); return resources; } private void addRestResourceClasses(Set<Class<?>> resources) { resources.add(UploadResource.class); }
- UploadResource.java
サーバ側でのアップされたファイルの保存処理。「@Consumes(MediaType.APPLICATION_JSON)」を指定して引数に上記で作成した「UploadInfo」を指定することで、クライアントで送信した情報を取得。
@javax.ws.rs.Path("/upload") public class UploadResource { @POST @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.TEXT_PLAIN) public String uploadFile(UploadInfo info) throws IOException{ String returnMsg = ""; String fileType = info.getFileType(); Path path = Paths.get(info.getDestination() + File.separator + info.getFileName()); if (fileType.equals("text/plain")){ // ファイルに保存 saveFile(path, info.getFile()); returnMsg = String.format("%sに保存しました", path.toAbsolutePath().toString()); } else if(fileType.startsWith("image")) { // イメージをして保存 saveImage(path, info.getFile()); returnMsg = String.format("%sに保存しました", path.toAbsolutePath().toString()); } else { // 保存エラー returnMsg = "保存に失敗しました。"; } return returnMsg; } private void saveFile(Path path, String base64String) throws IOException { Files.deleteIfExists(path); Base64.Decoder decoder = Base64.getDecoder(); byte[] decode = decoder.decode(base64String); try (BufferedWriter writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);){ writer.write(new String(decode)); } } private void saveImage(Path path, String base64String) throws IOException { Files.deleteIfExists(path); byte[] bytes = org.apache.commons.codec.binary.Base64.decodeBase64(base64String); try (FileOutputStream x = new FileOutputStream(path.toFile());){ x.write(bytes); } } }
プロジェクトはNetBeansで作成してここtomoTaka01/FileUploadWeb · GitHubにアップ。
まだまだ勉強不足です、、、