struts+jQuery Form Pluginを使ったファイルアップロード①
会社で急遽、おとなりのプロジェクトのお手伝いをすることになりました。
久しぶりのJava。一番経験の長い言語なので大丈夫でしょ
とタカをくくっていたところ、強烈に洗礼を受けました。。。
1.環境
・Java
・Tomcat v7.0
基本のところはこんな感じ。あと、PIE_IE678.jsという
CSSが効かない古いIEに、がんばってCSS適用してくれるjsを使っていました。
2.要件
・ファイル選択ダイアログからファイルを選択する
・ファイルをアップロードし、同じ画面に表示する
・ファイル形式はjpegのみで、200KB以内
・IE8標準対応(!)
3.準備
今回は、form内の一項目として扱うため、jQuery Form Pluginというものを使うことにしました。
jQuery Form Plugin : jQuery Form Plugin
↑からダウンロードして、jspファイルで読み込み。
<script src="js/jquery-1.11.2.min.js" type="text/javascript" charset="utf-8"></script> <script src="js/jquery.form.js" type="text/javascript" charset="utf-8"></script>
4.実装
test.jsp(他の項目や装飾は省略しています)。
<s:form> <input type="file" name="imgFile" onchange="fileupload(event);" accept="image/jpeg" /> <div> <s:if test="imgFileName != null"> <img src="<s:property value="imgFileName" />" /> </s:if> <s:else> <img src="img/img-no-image.png" /> </s:else> </div> </s:form>
ファイル選択ダイアログ表示ボタン<input type="file">と
選択した画像ファイル表示用の<img>があるだけです。
<img>は、Action側が持っている値を判定して、値がなければデフォルト用の画像を表示するようにしました。
file-upload.js
fileupload = function(event) { var $form, target; target = event.target ? event.target : event.srcElement; $form = $(target).closest('form'); return $form.ajaxSubmit({ 'target': "body", 'cache': false, 'beforeSubmit': function(formData, jqForm, options) { // ファイルサイズチェックなどの処理 }, 'success': function(filename) { // アップロード成功時の処理 alert("success"); } }); };
$form.ajaxSubmit で、formの値をAction側へ送ります。このとき、引数でオプションを指定することができます。
主なオプションは以下。
オプション名 | 役割 |
---|---|
beforeSubmit | フォーム送信前の処理を指定。 今回は、ファイルサイズ等のチェックがあるので使用。 |
dataType | レスポンスのデータ型。xml、script、jsonから指定。省略時はnull レスポンスをそのまま表示するだけであれば、指定しなくて大丈夫だと思います。 |
error | エラー時の処理を指定。 |
success | 処理を指定。 |
target | サーバからのレスポンスを出力する箇所。jQueryオブジェクトやDOM要素で指定。 今回は、Action側でページを返していたので「body」を指定。 |
type | リクエストタイプをGETまたはPOSTで指定。省略時はフォームの指定に従う。 |
url | フォームデータを送信先のURL。省略時はフォームでの指定に従う。 |
testAction.java
public class TestAction extends ActionSupport implements ServletResponseAware, ServletRequestAware { private static final long serialVersionUID = 1L; // 画面表示用のファイルパス public String imgFileName; // アップロードファイル格納用 public File imgFile; public String execute() throws Exception { if (imgFile != null) { // リクエスト取得 HttpServletRequest request = (HttpServletRequest) ActionContext.getContext().get(org.apache.struts2.StrutsStatics.HTTP_REQUEST); // 保存するファイル名(一時保存されたファイルは、形式にかかわらず「.tmp」なので「.jpg」に変更) String fileName = imgFile.getName().replace(".tmp", ".jpg"); // 保存用のディレクトリ(/test)をチェックして、存在しなければ作成 File tmpDir = new File(request.getServletContext().getRealPath("/test")); if (!tmpDir.exists()) { tmpDir.mkdir(); } // ファイルを保存 BufferedImage img = null; boolean result = false; File writeFile = new File(request.getServletContext().getRealPath("/test/" + fileName)); try { img = ImageIO.read(imgFile); result = ImageIO.write(img, "jpg", writeFile); } catch (Exception e) { e.printStackTrace(); result = false; } // 保存に成功したら、画面表示用のパスをセットする if (result) { imgFileName = "test/" + fileName; } } return "success"; } ・・・ }
フォームデータが送信されると、Action側の同じ名前のプロパティに格納されます。
execute()は、初回表示時などにも呼ばれるため、もしimgFileがセットされていたら
ファイルアップロードが実行されたとみなしています。
これでOKとかと思いきや、IEのときだけ1回目のアップロードでexecute()が呼ばれない
問題が起きてしまいました。
1回目:呼ばれない、2回目:呼ばれる、3回目:呼ばれない、4回目:呼ばれる・・・
の繰り返し。
IE8とIE11で確認したので、バージョンは関係ないようです。
これを調べるのが結構大変だったので、次回にまとめようと思います。