クライアントのファイルをサーバーにアップロードすることができます。 アップロードされたファイルは com.fujitsu.uji.util.MimeSourceクラスから取り出すことができます。
例として、以下のような画面を作成します。
"参照"ボタンを押すと、クライアント側のファイル選択ダイアログが出力されます。
"アップロード"ボタンを押すと、filenameで示されるファイルがサーバーへアップロードされます。
以下の3つの定義が必要です。
定義場所 | 定義内容 |
---|---|
1. 入出力ページ(JSP) | 送信するファイルの指定と送信ボタンの追加 |
2. データBean | 送信されたファイルを受け取るMimeSource型のプロパティを追加 |
3. ビジネスロジック | 送信されたファイルをMimeSourceクラスから取得する処理を追加 |
1. 入出力ページ(JSP)
以下の3つの定義を追加します。
1.1 uji:formタグのenctypeアトリビュート指定
uji:formタグには、enctype="multipart/form-data"アトリビュートを指定します。
<uji:form method="post" name="mainForm" enctype="multipart/form-data" beanId="body" beanCls="upfile.BodyBean" verbs="upload" >
....
</uji:form>
1.2 "参照"ボタン付の入力領域
INPUTタグのtype="FILE"アトリビュートは、フォームのデータとして送信するファイル を選択するボタンと入力域を表します。
name="file"で示されるのは、サーバーでファイルを受け取るプロパティの名前と対応しています。
詳細は“2. データBean”を参照してください。
<INPUT type="FILE" name="file" />
1.3 サーバーへの送信ボタン
サーバーへの送信ボタンをINPUTタグで作成します。 この例ではボタンを押すと"upload"というコマンドを発行しています。 コマンドは、INPUTタグのnameアトリビュートに指定しています。
<uji:form method="post" name="mainForm" enctype="multipart/form-data" beanId="body" beanCls="upfile.BodyBean" verbs="upload" >
....
<INPUT type="submit" name="upload" value="アップロード">
最終的に作成されるJSPは以下のようになります。
<%@ page contentType="text/html; charset=shift_jis" %> <%@ taglib uri="uji-taglib" prefix="uji" %> <uji:useBean id="body" cls="upfile.BodyBean" request="true" /> <uji:form method="post" name="mainForm" enctype="multipart/form-data" beanId="body" beanCls="upfile.BodyBean" verbs="upload" > <uji:controlState/> <INPUT type="FILE" name="file"/><BR>
<INPUT type="submit" name="upload" value="アップロード" > </uji:form>
2. データBean
送信されたファイルを受け取るMimeSource型のプロパティを追加します。
このプロパティの名前は、“1.2 "参照"ボタン付の入力領域”で指定したプロパティと対応しています。
import com.fujitsu.uji.DataBean;
import com.fujitsu.uji.util.MimeSource;
public class BodyBean extends DataBean
{
protected MimeSource file;
public MimeSource getFile() {
return file;
}
public void setFile(MimeSource file) {
this.file = file;
}
}
3. ビジネスロジック
送信されたファイルをMimeSourceクラスから取得する処理を追加します。
以下の4つの処理を追加します。
3.1 データBeanから、MimeSourceの取得
データBeanから、MimeSource型のプロパティを取得します。
MimeSource source=dataBean.getFile();
3.2 MimeSourceから、InputStreamとファイル名の取得
MimeSourceから、InputStreamと送信されたファイル名を取得します。 それぞれ、変数is, fnameへ格納しています。
InputStream is = source.getInputStream(); String fname = source.getFileName();
3.3 InputStreamから、アップロードされたファイルの読み込み
InputStreamからアップロードされたファイルを読み込みます。 この例では、サーバーのフォルダにファイルとして書き出します。
// 格納するサーバーのフォルダを求めます。 // ここでは、アプリケーションの配置と同じフォルダとします。 String name = "/"; if(context instanceof HttpDispatchContext) { ServletContext svc = ((HttpDispatchContext)context).getServletContext(); name = svc.getRealPath(name); } // 格納するファイル名を決定します。 File savename = new File(getRealFolder(context), fname); // 実際にファイルへ書き出します。 try { FileOutputStream os = new FileOutputStream(savename); byte buffer[] = new byte[1024]; int size; while((size = is.read(buffer)) > 0) os.write(buffer, 0, size); os.close(); } catch(Exception e) { e.printStackTrace(); }
3.4 リソースを解放可能にするためプロパティにnullを設定
アップロードの処理が終了したら、MimeSource型のプロパティにnullを設定します。このようにしてMimeSourceへの参照を削除することにより、ガーベジコレクタがMimeSourceを破棄できるようになります。MimeSourceが破棄された時点でリソースが解放されます。
dataBean.setFile(null);
最終的に作成されるJSPは以下のようになります。
import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import javax.servlet.ServletContext; import com.fujitsu.uji.util.MimeSource; import com.fujitsu.uji.GenericHandler; import com.fujitsu.uji.DispatchContext; import com.fujitsu.uji.http.HttpDispatchContext; .... public class UploadHandler extends GenericHandler { public void upload(DispatchContext context, BodyBean dataBean) { MimeSource source=dataBean.getFile(); InputStream is = source.getInputStream(); String fname = source.getFileName(); // 格納するサーバーのフォルダを求めます。 // ここでは、アプリケーションの配置と同じフォルダとします。 String name = "/"; if(context instanceof HttpDispatchContext) { ServletContext svc = ((HttpDispatchContext)context).getServletContext(); name = svc.getRealPath(name); } // 格納するファイル名を決定します。 File savename = new File(getRealFolder(context), fname); // 実際にファイルへ書き出します。 try { FileOutputStream os = new FileOutputStream(savename); byte buffer[] = new byte[1024]; int size; while((size = is.read(buffer)) > 0) os.write(buffer, 0, size); os.close(); } catch(Exception e) { e.printStackTrace(); } dataBean.setFile(null); .... } .... }
4. アップロードファイルの定量制限について
ファイルをアップロードする場合には、以下の定量制限があります。
アップロードヘッダ長は1024バイト以内です。
アップロードヘッダには、項目名とファイル名の情報が含まれます。利用するブラウザによって多少異なりますが、項目名長とファイル名長を合わせて、970バイト程度を指定可能です。
アップロードファイルサイズの上限はデフォルトで16MB (16*1024*1024バイト)です。このサイズは、アプリケーションクラスでgetMimeTransferSizeLimitメソッドをオーバライドすることで変更できます。getMimeTransferSizeLimitメソッドの詳細は、“15.2 バイナリファイルの送受信”を参照してください。
これらの定量制限を超えた場合は、IOException例外が発生します。発生した例外はDispatchExceptionクラスでラップされ、セションクラスに実装したhandleExceptionメソッド、アプリケーションクラスに実装したhandleExceptionメソッドに通知されます。なお、handleExceptionメソッドを使用するには、Postprocessorインターフェイスをセションクラスまたはアプリケーションクラスに実装する必要があります。 handleExceptionメソッドの使用方法については、“4.2 エラー処理”を参照してください。
以下は、セションクラスのhandleExceptionメソッドで、アップロードヘッダ長が制限を越えた場合の例外を受け取る例です。
import com.fujitsu.uji.http.HttpControlStateProfile; import com.fujitsu.uji.DispatchContext; import com.fujitsu.uji.log.NestedException; import com.fujitsu.uji.DispatchException; public class UpdownSession extends HttpControlStateProfile { public Object handleException(DispatchContext context, Throwable th) throws Throwable { if (th instanceof DispatchException) { Throwable rootCause = th; // 原因となった例外を取得します。 while(rootCause instanceof NestedException) { rootCause = ((NestedException)rootCause).getRootCause(); } String errorMessage = rootCause.getMessage(); if (errorMessage != null && errorMessage.startsWith("UJI075:")) { // エラーメッセージが "UJI075:" で始まっていれば ヘッダデータ長が // 制限を越えた場合の例外だと判断します。 // 以下でアップロードヘッダ長が制限を越えた時の処理を実行します。 .... } else { // それ以外の例外の処理です。 .... // このメソッドで処理しない場合は、throw文を使って例外を // 再度スローします。 // throw th; } } else { // DispatchException以外の例外の処理です。 .... // このメソッドで処理しない場合は、throw文を使って例外を再度スローします。 // throw th; } return null; } }
関連項目