ページの先頭行へ戻る
 Apcoordinatorユーザーズガイド

F.5.4 クライアントのファイルをサーバへアップロードしたい

クライアントのファイルをサーバにアップロードすることができます。 アップロードされたファイルは com.fujitsu.uji.util.MimeSourceクラスから取り出すことができます。

例として、以下のような画面を作成します。

  1. "参照"ボタンを押すと、クライアント側のファイル選択ダイアログが出力されます。

  2. "アップロード"ボタンを押すと、filenameで示されるファイルがサーバへアップロードされます。

以下の3つの定義が必要です。

定義場所

定義内容

1. 入出力ページ(JSP)

送信するファイルの指定と送信ボタンの追加
1.1 uji:formタグのenctype="multipart/form-data"アトリビュート指定
1.2 "参照"ボタン付の入力領域
1.3 サーバへの送信ボタン

2. データBean

送信されたファイルを受け取るMimeSource型のプロパティを追加

3. ビジネスロジック

送信されたファイルをMimeSourceクラスから取得する処理を追加
3.1 データBeanから、MimeSourceの取得
3.2 MimeSourceから、InputStreamとファイル名の取得
3.3 InputStreamから、アップロードされたファイルの読み込み
3.4 リソースを解放可能にするためプロパティにnullを設定

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. アップロードファイルの定量制限について

ファイルをアップロードする場合には、以下の定量制限があります。

これらの定量制限を超えた場合は、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;
    }

}

関連項目