わたしの日記だよ

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

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

前回、タイトルの通り、画像ファイルをアップロードして

元の画面に表示するという処理を書きました。

struts+jQuery Form Pluginを使ったファイルアップロード① - わたしの日記だよ

 

ただ、IEのときだけActionが呼ばれないことがあったので

以下のように確認してみました。

 

1.レスポンスの確認

まず、ieHTTPHeaders使って、そもそも応答が来てるかどうか調べます。

IE8だと、元々は入ってないので、別途インストールが必要です。

使い方は、IEブラウザの

Tools → Explorer Bars → ieHTTPHeaders を選択後、確認したい通信を実行するだけです。

今回は、HTTPステータス200:OKが返ってきていました。

一応、正常に返ってきたことにはなっているのか。。。

 

2.Actionの前に呼ばれる処理

Struts2にはインターセプターという仕組みがあり、リクエストが投げられると

このインターセプターが呼ばれた後、Actionへ処理が渡ります。

たくさん種類がありますが、

Validationインターセプター(名前のとおり、バリデーション処理を行う)

Servlet Configインターセプター(サーブレット関連の値をセットする)

なんかが、イメージが湧きやすいでしょうか。

自前で用意することも可能です。

 

まずは、Servlet Configインターセプターが呼ばれているか、確認します。

Actionクラスで「なんとかAware」インターフェースを実装して使用します。

今回は

ServletRequestAware、ServletResponseAware、SessionAware

の3つを使っていたので、ServletRequestAwareのメソッドブレークポイント

置いて、アップロードを実行してみました。

 

f:id:s31o3:20150324130550p:plain

他のAwareのメソッドも含め、ちゃんと呼ばれていました。

 

次に、その他のインターセプターを確認します。

Actionクラスにアノテーションで指定されています。

@InterceptorRefs({
		@InterceptorRef(value = "myDefaultStack")
})
public class TestAction extends ActionSupport {
 ・・・

 こんな感じ。@InterceptorRefの値「myDefaultStack」はstruts.xmlの中で

設定されています。

<package name="attend-reserve" extends="struts-default">
	<interceptors>
		<interceptor name="myInterceptor" class="xx.xxx.MyInterceptor" />

		<interceptor-stack name="myDefaultStack">
			<interceptor-ref name="defaultStack" />
			<interceptor-ref name="myInterceptor" />
		</interceptor-stack>
	</interceptors>
	・・・
</package>

Actionクラスで指定している「myDefaultStack」では、

defaultStack(struts2のデフォルトインターセプター)と

myInterceptor(自前のインターセプター)を呼ぶよう指定しています。

myInterceptorの最初と最後でログを吐くようにしてみましたが、全然出力されませんでした。

そこで、myInterceptorとdefaultStackの順番を入れ替えたところ

ログ出力されたので、defaultStackで引っかかってるみたい!!

 

しかし、defaultStackを削除して、アップロードを実行しても

Action側に処理は渡ってきません。

defaultStackの中に、必須のインターセプターが居るのかな??

 

↓↓↓のページによると、あらかじめ用意されているインターセプターは

struts-default.xmlに定義されていて、defaultStackで使用しているのはそのうち17ほどだそう。

Struts2入門(4)〜インターセプターという仕組み〜:http://codezine.jp/article/detail/3264

多い。。。今回は時間の都合で、これ以上追うのは諦めてしまいました。

 

3.対策

リクエストが届いていることはわかったので、正常に呼ばれるところで

なんとかすることにしました。

struts2http://blog.pionet.co.jp/experience/archives/43

formから送信された値がActionの同名フィールドに入ってくるんだな、とは思ってたのですが

<s:property value="フィールド名">などがgetterの呼び出し

<input>タグや<s:textfield>がsetterの呼び出し(name属性=フィールド名)

だったのですね。

getter/setterなしの、publicフィールドを使っていたので気付きませんでした。

 

前回作ったActionクラスを、以下のように修正しました。

public class TestAction extends ActionSupport implements ServletResponseAware, ServletRequestAware {

  private static final long serialVersionUID = 1L;

  // 画面表示用のファイルパス
  public String imgFileName;
  // アップロードファイル格納用
  private File imgFile;

  public void setImgFile(File imgFile) {

    this.imgFile = imgFile;

    // リクエスト取得
    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;
    }
  }

  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");

      // 保存ファイルの存在チェック
      File writeFile = new File(request.getServletContext().getRealPath("/test/" + fileName));
      if (writeFile.exists()) {
        // ファイルが存在していたら、画面表示用のパスをセットする
        imgFileName = "test/" + fileName;
      }
    }

    return "success";
  }

  ・・・
  
}

画像ファイルが送信されてきたときの処理を、まるまるsetterに移して

念のため、execute()でも画像表示用のパスのセットだけ行っています。

これで、IEでも毎回画像のアップロード〜表示が行えるようになりました。

あんまりすっきりしないけど、めでたし②!!

 

それにしても、今さらstruts入門することになるとは。。。