質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.78%

フォームで画像データとテキストデータを一度に送受信したいです。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 5,524

sususu

score 86

いつもお世話になります。
javaを勉強している初心者です。
表題の件に関して、前回の質問で同時に送信してゲットパラメータでデータを受け取るのは出来ないという事を教えていただき挑戦中なのですがわからないところが多々ありますのでご教授お願いいたします。

最終的にやりたいことは、「アップデートされた画像のパス」と「ファイルの名前」をテーブルに格納することです。

1.エラー
「upload.parseRequest(request);」に波線が付いてしまいます。
エラー内容は「型 FileUploadBase のメソッド parseRequest(RequestContext) は引数 (HttpServletRequest) に適用できません」となってしまいますがどのように対応したらよいでしょうか?

2.ファイル名の受け取り
jspのformで送信しているされている<input type="text" name="note"><br/>の値の取得の仕方はどのようにすればよいでしょうか?こちらは日本語対応でproperNameなどの変数に入れたいと思っています。

3.保存先のフォルダ
画像を保存するのWEB-INFの中が良いのでしょうか?
その場合WEB-INFの下にpictureフォルダを作成して
String path = getServletContext().getRealPath("WEB-INF/picture");
のように表記をするのでしょうか?

JSP
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="POST" enctype="multipart/form-data" action="UpLoad">
  ファイルを選んでください<input type="file" name="upfile"><br/>
  ファイル名を入れてください<input type="text" name="note"><br/>
  <br/>
  <input type="submit" value="Press"> to upload the file!
</form>
</body>
</html>
サーブレット
package picAndText;

import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

/**
 * Servlet implementation class UpLoad
 */
@WebServlet("/UpLoad")
public class UpLoad extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //保存先ディレクトリを指定(下記の場合picture/fileName)
         String path = getServletContext().getRealPath("picture");
        //様々なファイルデータを受け取れるオブジェクトを生成
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //複数のファイルデータ分割して取得できるオブジェクトを生成
        ServletFileUpload upload = new ServletFileUpload(factory);
        //アップロードする際の基準値を設定
        factory.setSizeThreshold(1024);
        upload.setSizeMax(-1);
        //下記2件は良く分からないからコメントアウト
        //aactory.setRepository();
        //upload.setHeaderEncoding("Windows-31J");

        try{
            //ファイルデータを取得
            List<FileItem> items = upload.parseRequest(request);
            //Iteratorはコレクションフレーム
            Iterator<FileItem> iter = items.iterator();
            //繰り返し処理で次があればtrueを返す
            while (iter.hasNext()) {
                FileItem item = (FileItem)iter.next();
                //アップロードされたファイルのみ対象の処理
                if (!item.isFormField()){
                    //PATHを含むファイル名を取得
                    String fileName = item.getName();
                    //もしファイル名があるなら
                    if((fileName != null) && (!fileName.equals(""))){
                        //PATH名を除くファイル名のみを取得
                        fileName=(new File(fileName)).getName();
                        //ファイルデータを保存
                        item.write(new File(path + "/" + fileName));
                        //ファイル名を取得...したい...
                        String properName = item.getContentType();
                    }
                }
            }
            //うまくいったらupLoadFinishへ
            RequestDispatcher dispatcher = request.getRequestDispatcher("WEB-INF/jsp/upLoadFinish.jsp");
            dispatcher.forward(request, response);
        }catch(FileUploadException e){
              e.printStackTrace();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}


2に関しては

getContentType
java.lang.String getContentType()
リクエストに含まれるメッセージボディの MIME タイプを返しますが、タイプがわからない場合は null を返します。 HTTP Servlet では CGI 環境変数の CONTENT_TYPE の値に相当します。
戻り値:
リクエストの MIME タイプの名前を含む String


というのを見つけたのでgetContentTypeなのかと思ってしまっていますがまったくわかりません。
サイトは下記を参考にさせていただきました。一応翻訳なども使い読んでみましたがいまいちわかりません。
コメントも書きながらなので読みにくくて申し訳ありませんがよろしくお願いいたします。

開発環境
OS windows10
エディション enterprise
言語 java8.0.1310.11
MariaDB10.1
HeidiSQL
eclipse NEON

参考サイト
https://commons.apache.org/proper/commons-fileupload/using.html
http://www.javaroad.jp/servletjsp/sj_servlet12.htm
https://www.javadrive.jp/servlet/fileupload_tutorial/index5.html
http://d.hatena.ne.jp/chaoruko/20090828/1251452593
http://www.jajakarta.org/commons/fileupload-1.0/ja/withoutPrimary/org/apache/commons/fileupload/FileItem.html#getFieldName()

追加画像
イメージ説明
リンク
https://www.javadrive.jp/servlet/fileupload_tutorial/index5.html

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • asahina1979

    2018/03/14 07:00

    「アップロードされたファイルのみ対象の処理」 この下行理解して入れてる?

    キャンセル

  • sususu

    2018/03/14 08:12

    早いコメントありがとうございます!理解しているかと言いますと正直ほぼ想像になってしまうかもしれないのですが、「パスを含むファイル名を取得」という事とサイトの情報(画像追加させていただきます)からユーザーが画像を保管しているパスが手に入ると思っております。例えばshibakenという名前の画像を持っていたとしてそれをanimalのファイルのdogのファイルの中に持っていたとしたらanimal/dog/shibakenというパスが取得できるのではないかと思っておりましたが違いましたでしょうか?長文失礼いたしました!

    キャンセル

  • asahina1979

    2018/03/14 08:21

    なぜ否定式を利用していると思う?

    キャンセル

  • sususu

    2018/03/14 09:34

    肯定文があるかどうかという認識がなかったのでキチンとは答えられそうにないのですが、送信されてきた画像ファイルとテキストファイルに該当するものを拾うためなのではないかと思っていましたが違いましたでしょうか?

    キャンセル

回答 2

checkベストアンサー

+1

(1)について
importしているクラスが違うようです。参考にされているサイト( https://www.javadrive.jp/servlet/fileupload_tutorial/index5.html ) は、Apache commons-fileUploadを利用しているので、ソースに記載されている以下ではコンパイルエラーが出るでしょう。

import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;

次にすればよいかと。

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

(2)について
アップロード後に、ファイルとパラメータで処理を振り分けて書いている実装例が公式サイトのガイドにもありますので、以下を参考にされると、処理が見やすくなるかと思います。

https://commons.apache.org/proper/commons-fileupload/using.html

// Process the uploaded items
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
    FileItem item = iter.next();

    if (item.isFormField()) {
        processFormField(item);
    } else {
        processUploadedFile(item);
    }
}

....

// 戻り値がvoidのままだと取得したパラメータの内容がサーブレットから参照しにくくなるので、工夫をしてください。
private void processFormField(FileItem item) {
  // Process a regular form field
  if (item.isFormField()) {
    String name = item.getFieldName();
    String value = item.getString("utf-8");  // 文字コードを指定しないとデフォルトはiso-8851で処理しているので文字化けする
    // .....(取得したパラメータについての処理を以下に).......
  }
}

private void processUploadedFile(FileItem item) {
  ......(アップロードの処理)....
}

(3)について
置き場所については、WEB-INF以下に置くとサーブレットやJSP経由でなければ参照できなくなります。
アップロードされたファイルは常に画像取得用のサーブレットなどからレスポンスするものならWEB-INF以下に置いても良いかと思いますが、WEB-INF以下にはおかず、別途別のディレクトリに保管するなり、データベースに保管する場合もあるようですので、実装したい内容にあわせてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • キャンセル

  • 2018/03/14 19:51

    commonsのライブラリを入れないといけないとは知りませんでした!リンクまでありがとうございます!確認してみます!

    キャンセル

+1

取得方法と意味の説明(ドキュメントの意訳、かみ砕いた状態)

FileItem item = (FileItem)iter.next();
Map<String,String> parameter = new HashMap();
// https://tomcat.apache.org/tomcat-7.0-doc/api/org/apache/tomcat/util/http/fileupload/FileItem.html
// isFormField : Determines whether or not a FileItem instance represents a simple form field.
// isFormField : (意訳)<form method="post" ... > 送信時の <input type="file"> は false , それ以外は true
if (!item.isFormField()){
    //PATHを含むファイル名を取得
    String fileName = item.getName();
    //もしファイル名があるなら
    if((fileName != null) && (!fileName.equals(""))){
        //PATH名を除くファイル名のみを取得
        fileName=(new File(fileName)).getName();
        //ファイルデータを保存
                item.write(new File(path + "/" + fileName));
                //ファイル名を取得...したい...
                String properName = item.getContentType();
    }
} else {
    // getFieldName: Returns the name of the field in the multipart form corresponding to this file item.
    // getFieldName: (意訳) <input name="?" > の属性値
    String fieldName = item.getFieldName();
    // getString: Returns the contents of the file item as a String, using the specified encoding.
    // getString: (意訳) <input value="?" > の属性値
    String fieldValue = item.getString();
    parameter.put(fieldName,fieldValue);
}

 追記

ちなみに、古いバージョンの commons-fileupload/commons-io のコピーで依存関係をあいまいにするために以下のコードに変換する必要があります。

import org.apache.tomcat.util.http.fileupload.servlet.ServletRequestContext;
// 中略
ServletRequestContext rc = new ServletRequestContext(/* HttpServletRequest */ request);
List<FileItem> items = upload.parseRequest(rc);

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/03/14 19:52

    コードまでありがとうございます!
    試してみたいと思います!!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る