- PR -

JSF にてファイルアップロード方法

投稿者投稿内容
小僧
大ベテラン
会議室デビュー日: 2005/06/24
投稿数: 122
投稿日時: 2007-05-30 15:24
またわからない事が出てきましたので、
お知恵を拝借出来れば嬉しく思います。

【環境】
OS:Windows 2000
Web サーバ:Tomcat 5.0
JDK:1.4
JSF:1.1

【やりたいこと】
ファイルのアップロードをしたいと思っています。

ファイルをアップロードするためには、
from のコンテントタイプを「multipart/form-data」にする必要があると思います。
具体的なコードのサンプルとしては
コード:

<h:form id="upload" enctype="multipart/form-data" >
<h:commandButton id="button1" value="Upload" action="#{File.upFile}" /><BR><BR>
</h:form>


で良いと思っております。
この状態でボタン「Upload」を押下しても何もアクションが起きません。

「enctype」を記述しないと正常にメソッドはコール出来ますが、
そうするとファイル転送が出来ません。
( コンテントタイプを application/x-www-form-urlencoded と認識しているため。当然ですが。。。 )

ちなみに、メソッドタイプを「Post」にする必要があると思いますが、
当該 JSP ファイルを HTML に展開した場合の form タグは「Post」になっております。

Upload 自体は Servlet でロジックを作ってみて、そちらで成功しましたので
後は呼び出し部分の所だけだと認識しています。

他に何か入れないといけないのでしょうか?
宜しくお願いいたします。


[ メッセージ編集済み 編集者: 小僧 編集日時 2007-05-30 15:47 ]
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-30 15:56
生成されたHTMLはどうなっていますか?
どのようなURLにPOSTしようとしているのでしょうか。
サーバ側ではそのURLでのアクセスが記録されていますか?
小僧
大ベテラン
会議室デビュー日: 2005/06/24
投稿数: 122
投稿日時: 2007-05-30 16:07
返信ありがとうございます。

生成された HTML の抜粋を記述しますね。
コード:
<form id="resultDetail" method="post" action="XXX.jsp" enctype="multipart/form-data">
	<input id="resultDetail:button6" type="submit" name="resultDetail:button6" value="File" /><BR><BR>
	<input type="hidden" name="resultDetail" value="resultDetail" />
</form>



idは前回投稿と異なると思います。
また、action が指している JSP も書き直しました。
それ以外は生成されたものになります。

> サーバ側ではそのURLでのアクセスが記録されていますか?
ちょっとこの意味がわからないのですが。。。
ボタン押下された事がサーバ側で認識しているか?という事でしょうか?
それが出来ないので質問しているのですけど。。。

ちなみに、前回投稿でも書きましたが「enctype」を外すとメソッドはコールされるので
記述ミスなどではないと思っていますし、コードは動くものだと思っています。

宜しくお願いいたします。
だっちょ
大ベテラン
会議室デビュー日: 2006/12/05
投稿数: 115
投稿日時: 2007-05-30 16:55
最近JSFのファイルアップロードを調べたことがあるのですが、JSFでやってくれないみたいなので、HTMLのform使って、直接受けたデータを自分で解析してます。実績0ですが、問題なさそうです。
問題や無駄なところがあったら、誰か指摘してもらえるとうれしいな。

コード:
import javax.mail.*;
import javax.mail.util.*;
import javax.mail.internet.*;

String type = request.getContentType();
if ((type!=null) && type.startsWith("multipart/form-data")) {
    // form入力でmultipartの場合
    ByteArrayDataSource src = new ByteArrayDataSource(request.getInputStream(), type);
    MimeMultipart mmp = new MimeMultipart(src);
// form入力でheaderが無いデータだとmmp.getCount()で例外となる
//    int len = mmp.getCount();
    BodyPart part = null;
    boolean end = false;
    int count = 0;
    while (true) {
        Properties props = null;
        Object content = null;
        try {
            part = mmp.getBodyPart(count);
            content = part.getContent();
            Enumeration en = part.getAllHeaders();
            while (en.hasMoreElements()) {
                Header header = (Header)en.nextElement();
                if (header.getName().equals("Content-Disposition")) {
                    props = parseDisposition(header.getValue());
                }
            }
        }
        catch (MessagingException me) {
            end = true;
            break;
        }
        catch (IndexOutOfBoundsException ie) {
            end = true;
            break;
        }
        catch (Exception e) {
            throw e;
        }
        count++;

        String temp = props.getProperty("name");
        if (temp==null) {
throw new IllegalArgumentException("Unknown part:props" + props);
        }
        else if (temp.startsWith(MY_FILEPREFIX)) {
            String filepath = props.getProperty("filename");
            InputStream ins = null;
            if (content==null) {
                throw new IllegalArgumentException("body[" + (count-1) + "] content=null");
            }
            else if (content instanceof InputStream) {
                ins = (InputStream)content;
            }
            else if (content instanceof byte[]) {
                ins = new ByteArrayInputStream((byte[])content);
            }
            else if (content instanceof String) {
                m_parameters.put(temp, content);
            }
            else throw new IllegalArgumentException("unknonw body[" + (count-1) + "] content:" + content.getClass());

            if (ins!=null) {
                byte[] b = new byte[0x4000];
                ByteArrayOutputStream bous = new ByteArrayOutputStream();
                int n;
                while ((n=ins.read(b))!=-1) {
                    bous.write(b, 0, n);
                }
                m_parameters.put(temp, bous.toByteArray());
            }
        }
        else if (temp.startsWith(MY_PREFIX)) {
             m_parameters.put(temp, part.getContent());
        }
    }
}



nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-30 17:00
引用:

小僧さんの書き込み (2007-05-30 16:07) より:
> サーバ側ではそのURLでのアクセスが記録されていますか?
ちょっとこの意味がわからないのですが。。。
ボタン押下された事がサーバ側で認識しているか?という事でしょうか?
それが出来ないので質問しているのですけど。。。



404だろうがアクセスログに記録されているならパケットは飛んでいるけど
Servletなどの起動ができていない、つまり設定ミスってことです。
TomcatにアクセスログのValveなどが設定されてるならServletを叩くレベルと
別にアクセスに対してログが取れますし、Apache-Tomcat連携している場合でも
途中段階でいろいろログがだせますよね。

そもそもサーバにパケットが飛んでいないならHTMLの時点でのミスなり
URLの記述がおかしい(docbaseが別のサーバとかローカルとか)なり
そういうことになるので、その切り分けをしましょうよ、と。
端折って端的に書いたので誤解を招いたかもしれません。


さて、通常ファイルのアップロードをする場合、HTML的にはinputのtype="file"を利用します。
該当formのinputはtype="hidden"ですが、そもそもフォームの作り方がまずいように思えますね。

引用:

ちなみに、前回投稿でも書きましたが「enctype」を外すとメソッドはコールされるので
記述ミスなどではないと思っていますし、コードは動くものだと思っています。


そうなんですか。
前回投稿について触れられていませんでしたのでその点を配慮することが出来ませんでした。
小僧
大ベテラン
会議室デビュー日: 2005/06/24
投稿数: 122
投稿日時: 2007-05-30 17:43
返信ありがとうございます。

> 最近JSFのファイルアップロードを調べたことがあるのですが、
> JSFでやってくれないみたいなので
えーと、記載頂いたソースは Java ( Bean ) ですよね?
こちらは私のほうも上手く行きました。

問題はクライアント ( HTML ) にて
multipart/form-data
でアクションが出来ない、という事になっております。

> そもそもサーバにパケットが飛んでいないならHTMLの時点でのミスなり
ぇぇ、それは理解しています。
が、最初の投稿で
「「enctype」を記述しないと正常にメソッドはコール出来ますが」
と書いているので、記述ミスではないと思っていますが如何でしょうか?

> さて、通常ファイルのアップロードをする場合、HTML的にはinputのtype="file"を利用します。
仰るとおり、提示したサンプルにはありませんが、
ファイルをinput type=file で取得するのは理解しています。

問題はボタンを押下した際、Bean のメソッドが呼ばれないことですので、
掲載は割愛しました。

> 前回投稿について触れられていませんでしたのでその点を配慮することが出来ませんでした。
「前回投稿」とは最初の投稿のことを指しています。
( 別のスレッドのことではないのです。この発言の趣旨がちょっと理解出来なかったので補足させて頂きました )

再度繰り返しますが、解決したい問題は
「form に「multipart/form-data」を設定すると、Bean のメソッドをコールしない」
です。

宜しくお願いいたします。
だっちょ
大ベテラン
会議室デビュー日: 2006/12/05
投稿数: 115
投稿日時: 2007-05-30 17:56
h:formでなく普通のformを使ってBeanを呼び出したのではだめということなのなら、特にいうことはありません。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2007-05-30 18:35
引用:

> さて、通常ファイルのアップロードをする場合、HTML的にはinputのtype="file"を利用します。
仰るとおり、提示したサンプルにはありませんが、
ファイルをinput type=file で取得するのは理解しています。

問題はボタンを押下した際、Bean のメソッドが呼ばれないことですので、
掲載は割愛しました。



あー。すいません。何か勘違いしてました。的外れな回答をして申し訳ない。
enctypeがあるとupFile()が呼び出されない、なければ呼び出される、と。

とりあえず、だっちょさんもおっしゃってますが、Sunの参照実装では提供されていないようですね。
kodersで検索すると、ほとんどがmyfacesを使用してのアップロードになっています。
http://www.koders.com/default.aspx?s=JSF+enctype+multipart%2Fform-data&la=*&li=*

myfacesのタグライブラリを使っていないものでは
http://www.koders.com/jsp/fid70A301B8C6A5D441935550F868317D00A82AFD22.aspx?s=JSF+enctype+multipart%2fform-data
などが見つかりましたが、なにやらかなり強引な方法を使っているように見えます。
formタグもinput type="file"も自前で書いてますから強引にJSFのイベント部分だけを使っている感じですね。

スキルアップ/キャリアアップ(JOB@IT)