わたしの日記だよ

ー生きる厳しさと哀しさを鮮烈に謳うー

struts+jQuery Form Pluginを使ったファイルアップロード①

会社で急遽、おとなりのプロジェクトのお手伝いをすることになりました。

久しぶりのJava。一番経験の長い言語なので大丈夫でしょ

とタカをくくっていたところ、強烈に洗礼を受けました。。。

 

1.環境

 ・Java

 ・Struts2

 ・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で確認したので、バージョンは関係ないようです。

これを調べるのが結構大変だったので、次回にまとめようと思います。 

 

struts+jQuery Form Pluginを使ったファイルアップロード②

http://s31o3.hatenablog.com/entry/2015/03/24/154330