わたしの日記だよ

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

VirtualBox + CentOS6 ホストオンリーアダプターの設定

会社のプロジェクトが大炎上したり、第一子をリリースしたりしていたら

前回の投稿から1年以上経っていました。

時の経つのは、ほんとうにあっという間ですね。。。

 

最近、ちょっとしたお手伝い作業で環境構築をしているので、色々メモしていきたいと思います。

子の世話しかしてなかったので、何もかも忘れ去ってしまった。

…というか、ど忘れに次ぐど忘れが認知症を疑うレベルで、恐怖におののいています。。。

1.準備

 ◯CentOS6の仮想環境を作る

  isoファイルはこちらから↓↓↓。minimal.isoってやつです。

  Index of /pub/Linux/CentOS/6.8/isos/x86_64

 

2.設定

  VirtualBoxマネージャーから、[設定] - [ネットワーク] - [アダプター2]を開いて

  ・割り当て:ホストオンリーアダプター

  ・名前:vboxnet0

  を設定。

  ※ [MACアドレス] の値を後で使うのでメモっておきます(①)。

f:id:s31o3:20160630092634p:plain

  続いて、VirtualBox の [環境設定] - [ネットワーク] - [ホストオンリーネットワーク] から

  vboxnet0 を開きます。

f:id:s31o3:20160630093659p:plain

  [アダプター] - [IPv4アドレス] の値もメモりましょう(②)。

f:id:s31o3:20160630093733p:plain

  

  ここからは、ゲストOSにログインして作業します。

$ cd /etc/sysconfig/network-scripts
$ vi ifcfg-eth1

 

   ifcfg-eth1 ファイルの中身は↓↓↓こんなかんじ。

DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
HWADDR=08:00:27:9D:62:60
IPADDR=192.168.33.2
NETMASK=255.255.255.0
NETWORK=192.168.33.0

  HWADDRには、 ①の値(2文字ずつ、「:」区切りで)

  IPADDRには、②の値の末尾を任意の値に変えたもの

  NETWORKには、②の値を入れます。

 

 

  ネットワークを起動。

$ ./ifup eth1

 

 

2.確認

  ホストOSから pingssh 接続をしてみてつながればOKです。

$ ssh root@192.168.33.2

 

 

 

 

 

JavaScriptで<input type="file">で選択されたファイルサイズを取得する〜IE編〜

先日作った、画像ファイルが選択されたら、ファイルアップロードを行う処理↓↓

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

ですが、JavaScriptでファイルサイズをチェックする処理を入れていたものの

IE8だとチェックが効かないよ!と言われてしまいました。

 

1.現在の実装

今の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) {
      // ファイルサイズチェックなどの処理
      for (var i = 0; i < formData.length; i++) {
        if (formData[i]["name"] == "imgFile") {
	  var file = formData[i]["value"];
          if (file.size > 200000) {
	    alert("画像は200KB以内のファイルを選択してください。");
	    return false;
	  }
        }
} }, 'success': function(filename) { // アップロード成功時の処理 alert("success"); } }); };

 jsp側は、前回のエントリ参照。と言っても、ただformの中にtype="file" name="imgFile"のinputタグがあるだけです。

 

上記のコードだと、File APIに対応しているブラウザでないとダメなのですね。

こちら↓↓によると、IEだと対応しているのは10以降。

JavaScriptでローカルファイルを自在に操る - File API | Think IT(シンクイット)

 

2.回避策・・・imgオブジェクトを使用して取得する

こんなページを見つけました。

任意のファイルのファイルサイズを取得する

選択されたファイルを、一度imgオブジェクトにセットするとサイズが取得できるらしい!

↑↑のページでは、画面に実際にちいさーく表示されるimgを置いていたのですが

なるべく余計な要素を追加したくないので、newしてなんとかならないか、試してみます。

変更後のjsはこんな感じ。

(赤字だった部分だけ。「formname」部分は実際のformのname属性です)

  // File APIチェック
  if (window.File) {
    // File API対応
    var file = formData[i]["value"];
  } else {
    // File API非対応
    var file = new Image();
    file.src = document.formname.imgFile.value;
  }
  alert("file size=" + file.size);

結果は△でした。

type='file'のvalueプロパティには、セキュリティ上の理由により制約が設けられていて

「document.formname.imgFile.value」で取れるパスは

f:id:s31o3:20150414114941p:plain

こんな風に途中がダミーになってしまいます。

該当のサイトを信用済みサイトに登録すれば、本物のパスを取得できるようになりますが

お客さんにそんなこと言えないので実質×ですね。。。><

 

この後、画面にimgタグを置くパターンも試してみましたが、同じ結果になってしまいました。

リンク先のページをIE8で開いた場合は、取得できるのに何で!?

 

今回は、時間の都合でphp側でチェックするように切り替えちゃいますが

また追って調査したいと思います。

 

 

 

 

 

 

Xcode6+swift アプリのディレクトリ構成とディレクトリパスの取得

アプリに同梱した画像のzipファイルを、初回起動時に解凍する処理を作っています。

iOSのときは、同梱するファイルや解凍したファイル、どこに置くんだっけ?と思ったので調べてみました。

ついでに、各ディレクトリパスの取得方法も。

 

1.ディレクトリ構成について

いきなり、わかりやすいまとめがありました。

参考:今こそ復習したい、iOSアプリのディレクトリ構成 - Qiita

・zipファイル・・・MyApp.app/(普通の画像と同じ扱い)

・解凍したファイル・・・Library/

に置けば良さそうです。

 

2.各ディレクトリパス取得方法

主なディレクトリパスの取得方法は、MyApp.app/、tmp/、その他のディレクトリ

で分かれています。

 

①MyApp.app/

NSHomeDirectory()

 

②tmp/

NSTemporaryDirectory()

 

③その他は、NSSearchPathForDirectoriesInDomains() メソッドか、NSFileManagerクラスの

URLsForDirectory() または URLForDirectory()メソッドで取得します。

NSFileManagerのほうを検討するように、とあったので、今回はそちらを使用します。

参考:Foundation Functions Reference

URLsForDirectory(directory:NSSearchPathDirectory, 
inDomains domainMask:NSSearchPathDomainMask) -> [AnyObject]

URLForDirectory(directory:NSSearchPathDirectory,
inDomain domain:NSSeatchPathDomainMask,
appropriateForURL url:NSURL?,
create shouldCreate:Bool,
error error:NSErrorPointer) -> NSURL?

 

パラメータ名役割
directory検索したいディレクトリ。NSSearchPathDirectoryを使って指定。
domain検索したい場所。NSSearchPathDomainMaskを使って指定。
urldirectoryにNSItemReplacementDirectory、domainにNSUserDomainMaskが指定されているとき以外は、無視される何か。(わたしの理解力の限界)
shouldCreateディレクトリが存在しなかった場合、作成するかどうか。trueで作成する。
errorエラー情報用のポインタ

 

どちらのメソッドもだいたい一緒ですが

・URLsForDirectoryは戻りが配列になっていること

・URLForDirectoryのほうは、戻りがひとつなので、複数の場所を指定するdomain(NSAllDomainMask)は使えないこと

がポイントかなと思います。

 

使い方は、こんな感じ。

        // MyApp.app/
        let homeDir = NSHomeDirectory()
        println("homeDir: \(homeDir)")
        
        // tmp/
        let tmpDir = NSTemporaryDirectory()
        println("tmpDir: \(tmpDir)")
        
        // NSFileManager取得
        var mgr = NSFileManager.defaultManager()
        
        // Documents/
        let documentDir:AnyObject = mgr.URLsForDirectory(.DocumentDirectory,
            inDomains: .UserDomainMask)[0]
        println("documentDir: \(documentDir)")
        
        // Library/ ディレクトリがなかったら作成する、エラー情報は使用しない
        let libraryDir = mgr.URLForDirectory(.LibraryDirectory,
            inDomain: .UserDomainMask,
            appropriateForURL: nil,
            create: true,
            error: nil)
        println("libraryDir: \(libraryDir)")
        
        // Library/Caches ディレクトリがなかったら作成しない、エラー情報を使用する
        var error:NSError?
        let cachesDir = mgr.URLForDirectory(.CachesDirectory,
            inDomain: .UserDomainMask,
            appropriateForURL: nil,
            create: false,
            error: &error)
        println("cachesDir: \(cachesDir)")
        
        if (error != nil) {
            println("error: \(error)")
        }

 

そして、実行結果はこんな感じでした。

homeDir: /Users/[user name]/Library/Developer/CoreSimulator/Devices/[device ID]/data/Containers/Data/Application/[App ID]
tmpDir: /Users/[user name]/Library/Developer/CoreSimulator/Devices/[device ID]/data/Containers/Data/Application/[App ID]/tmp/
documentDir: [file:///Users/[user name]/Library/Developer/CoreSimulator/Devices/[device ID]/data/Containers/Data/Application/[App ID]/Documents/]
libraryDir: Optional(file:///Users/[user name]/Library/Developer/CoreSimulator/Devices/[device ID]/data/Containers/Data/Application/[App ID]/Library/)
cachesDir: Optional(file:///Users/[user name]/Library/Developer/CoreSimulator/Devices/[device ID]/data/Containers/Data/Application/[App ID]/Library/Caches/)

 

NSSearchPathDirectoryの値は、上記以外にもPicturesDirectory(~/Pictures)とか

使いそうなものがたくさんありました。

やっぱり、Reference読むのが一番ですね。

 

 

Xcodeのグループと、実際のディレクトリ構成を合わせるツール Synx

以前、一度だけiOSのプロジェクトに入ったことがあるのですが

Xcode上でせっせとグループ分けをしたのに、実際のファイルはプロジェクト名のディレクトリ直下に

ばーっと入っていて、とてもびっくりしました。

 

それ以来、個人でアプリを作るときは、グループ作ったらディレクトリも作って・・・と

気をつけていたものの、気を抜くと忘れちゃう。

 

Synxはコマンドひとつで、Xcodeプロジェクト上のグループに実際のディレクトリ構成を

合わせてくれる便利ツールです。

 

1.インストール

ターミナルから

$ gem install synx

おわりー!!

 

2.使い方

使い方もとっても簡単です。

$ synx [プロジェクトファイルのパス(XX/XXX/XXX.xcodeproj)]

※cocoapodsを使用している場合は、上記コマンドの後に

$ pod install

したほうが良いようです。

(私の環境では、しなくても大丈夫でした)

 

もし、pod install してもうまく動かなくなってしまった場合は、一度pod関係を削除してからsynxするのが良いようです。

参考:cocoapods使用環境でsynxすると動かなくなる - Qiita

 

3.オプション

オプション役割
--prune, -pXcodeプロジェクトから参照されていないソースファイルと画像ファイルを削除
--no-colorログ出力をカラーにしない(指定しないと色分けして出力されます)
--no-default-exclusionsデフォルトの除外(/Libraries、/Frameworks、/Products)を使用しない
--quiet, -qログを出力しない
--exclusion, -e対象外のディレクトリを指定する

 -p、-eあたりはよく使いそうです。

 

 

jQuery.ajaxSubmit()実行後、元画面が表示された時にPIE_IE678.js内でエラーが出る

以前、jQuery Form Pluginで画像ファイルをアップロードするプロジェクトを作りました。

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

 

このプロジェクトは、CSSでボタンの角を丸くする処置が入っていて

かつ、IE8標準対応だったので、CSS3 PIEという

CSS非対応のブラウザに対して、がんばってCSSの表示を再現してくれるライブラリ(JavaScript版)を使っていました。

 

CSS3 PIEについてはこちら:CSS3 PIE: CSS3 decorations for IE

 

初回読み込み時は、問題ないのですが

jQuery.ajaxSubmit()実行後、元の画面が再読み込みされると

1242行目のel.getBoundingClientRect()のところでUnspecifiedエラーが出てしまいます。

 

◯解決方法

jQuery.ajaxSubmit()が実行される前に、PIE.attachを

jQuery.ajaxSubmit()実行後に、PIE.detachを呼んであげるだけでOKでした。

例えばこんな感じ。

$('form').ajaxSubmit({
  'target': "body",
  'beforeSubmit': function(formData, jqForm, options) {
    // 送信前に、PIEの適用をはずす
    $('.btn').each(function(){
      PIE.detach(this);
    });
  },
  'success': function(filename) {
    // 戻ってきたら、PIEの適用する
    $('.btn').each(function(){
      PIE.attach(this);
    });
  }
});

最初、target(サーバからのレスポンス出力先)を指定しているため、

普通にページ読み込みしたときと違って、PIEの処理のタイミングがずれてしまっているのかなと思い

PIEライブラリの読み込みを<header>ではなく<body>でしてみたり、

ライブラリ内でログを出しまくってページ読み込み時との差分を探したり、

見当外れなことばかりしていました。

 

使い方調べろ!!って話だった。。。

 

 

 

フォームデータ送信後、DB更新に成功したら印刷プレビューを開く

画面から、任意の項目を選択→確認画面へ移行→OKボタン押下でサーバへ送信した後

DB更新に成功したら、元のページで印刷プレビューを開いてほしいな、と言われました。

ちなみに、struts2のプロジェクトです。

 

当初、ajax使って〜とのことだったので、jQuery.ajax()でasync:falseを指定して

実装してみたのだけど、jQuery1.8以降非推奨らしいし、エラーも出てしまう。

(Choromeで確認)

Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.

これはちょっと嫌な感じなので、今回はformを使うことを考えてみました。

 

1.フォーム送信〜DB更新するところまで

 まず、jsp側(抜粋)。

<div class="print-off">
  <s:form>
    <input id="printStatus" type="hidden" value='<s:property value="printStatus" />'/>
    <s:iterator status="st" value="idList">
      <input type="hidden" 
             name='idList[<s:property value="#st.index" />]' 
             value='<s:property value="idList[#st.index]" />' />
    </s:iterator>
    <s:submit method="updateStatus" value="一括印刷"/>
  </s:form>
</div>

<div class="print-on">
・・・
</div>

「print-on」クラスを持つ要素は、通常はCSSで非表示にしておいて

印刷プレビューを表示するときだけ表示。

「print-off」クラスを持つ要素は、その逆です。

(印刷のときに、ボタンとか余計なものを入れないための処置)

 

また、hiddenの<input>タグは、以下の用途に使います。

 ・printStatus・・・DB更新結果を保持する

 ・idList[<s:property value="#st.index" />]・・・印刷したいIDの配列要素

 

 

Action側(抜粋)。jsp側の<s:submit>タグで指定した「updateStatus」メソッドを作り

その中でDB更新するだけです。抜粋っていうか、日本語しか書いていない。。。

public class TestAction extends ActionSupport {

  // 印刷したいID
  public List<string> idList = new ArrayList<string>();
  // DB更新結果フラグ
  public String printStatus = "";

  ・・・

  public String updateStatus() throws Exception {

    // idListを使って、DBテーブルの「印刷したよ」フラグを更新する処理・・・☆

    // ☆に成功したらprintStatusに"SUCCESS"、失敗したら"FAIL"をセットする

    ・・・
  }

  ・・・
}

 

2.printStatusの更新をチェックする

フォーム送信後、レスポンスを受け取ったときに、window.loadのイベントが呼ばれるので

そこでprintStatusの値をチェックすることにします。

 

jsファイル側。

$(window).load(function(){

  // 印刷フラグのチェック
  var status = $("#printStatus");
  if (!status && !status.val()) {

    var val = status.val();

    if (val === "SUCCESS") {

      // 印刷フラグ更新成功ー>印刷プレビュー表示
      showPrintPreview();

    } else if (val === "FAIL") {

      // 印刷フラグ更新失敗
      alert("DBの更新に失敗しました。");

    }
  }

})

function showPrintPreview() {
  
  // 印刷しない要素を非表示にする
  var printOff = document.getElementsByClassName("print-off");
  for(var i = 0; i < printOff.length; i++) {
    printOff[i].style.display = "none";
  }

  // 印刷する要素を表示する
  var printOn = document.getElementsByClassName("print-on");
  for(var i = 0; i < printOn.length; i++) {
    printOn[i].style.display = "block";
  }

  // 印刷プレビュー表示
  if (isIE()) {

    // IEの場合
    var sWebBrowserCode = '<object width="0" height="0" classid="CLSID:8856F961-340A-11D0-A96B-00C04FD705A2"></object>';
    document.body.insertAdjacentHTML( 'beforeEnd', sWebBrowserCode );

    var objWebBrowser = document.body.lastChild;
    if(objWebBrowser == null) {
      return;
    }

    objWebBrowser.ExecWB( 7, 1 );
    document.body.removeChild( objWebBrowser );

  } else {

    // IE以外
    window.print();

  }

  // 印刷しない要素を再表示する
  for(var i = 0; i < printOff.length; i++) {
    printOff[i].style.display = "block";
  }

  // 印刷する要素を非表示に戻す
  for(var i = 0; i < printOn.length; i++) {
    printOn[i].style.display = "none";
  }

}

function isIE(){

	if(!window.ActiveXObject){
		if(!document.documentMode){
			return false;
		}
	}
	return true;
	
}

ちょっと長いですが、

印刷したい部分のみを表示する→印刷プレビューを開く→表示を元に戻す

としているだけです。

IEのみ、印刷プレビューを表示するのにActiveXObjectを使わないとうまくいかないので

そこだけポイントです。

 

こちらを参考にしました。

ブラウザーに印刷プレビューボタン作成

 

3.印刷プレビューが表示される前に、表示を戻す処理が走ってしまう

上記のjsは、試しに<s:submit>タグのonclickイベントから呼んでいたときには

期待通りに動作していましたが、いざwindow.loadから呼んでみると

印刷プレビューを表示する前に、表示を戻す処理が走ってしまうようになってしまいました。

 

onclickから呼ぶのと何が違うのか、まだわかってないのですが

JavaScriptは非同期処理なのですね。

[JavaScript] JavaScriptはシングルスレッド:非同期処理の仕組み | Ouka Studio

 

だったら、表示を戻す処理は、印刷プレビューが閉じるタイミングで実行すればいいかな。

印刷プレビューが閉じて、元画面の描画が完了すると

window.onafterprintというイベントが呼ばれるので、こちらを使います。

jsファイル側(表示を戻す処理のみ抜粋)。

var afterPrint = function() {
  // 印刷しない要素を表示する
  var printOff = document.getElementsByClassName("print-off");
  for(var i = 0; i < printOff.length; i++) {
    printOff[i].style.display = "block";
  }

  // 印刷する要素を非表示に戻す
  var printOn = document.getElementsByClassName("print-on");
  for(var i = 0; i < printOn.length; i++) {
    printOn[i].style.display = "none";
  }
}

// Chorome・safari
if (window.matchMedia) {
	var mediaList = window.matchMedia('print');
	mediaList.addListener(function(mql) {
		if (!mql.matches) {
			afterPrint();
		}
	})
}

// IE・Firefox
window.onafterprint = afterAllPrint;

onafterprintイベントをサポートしていないブラウザもあるので

window.matchMediaを判定してごにょごにょする処理も加えておきます。

Operaはどっちもサポートしていないようです。。。困った!

(今回は、対象ブラウザじゃないのでパス)

 

JavaScript、いつもなんとなくで書いていたので

早急に入門しなおさなくては・・・

 

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入門することになるとは。。。