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

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

ただいまの
回答率

89.07%

Javaサーブレット内のHttp通信Putメソッドでボディー部にKey/Valueパラメータを設定して渡す方法はありますか?

解決済

回答 1

投稿

  • 評価
  • クリップ 2
  • VIEW 6,926

tutttwi

score 20

PutメソッドのHTTP通信を使用してボディーにKey/Valueパラメータを渡す方法を探しています。

BodyにKey/Valueのパラメータを設定して、受け渡し先で

String value = request.get~("Key");

みたいな感じで取得できる様な渡し方ができたらと考えております。。

現在、下記方法でサーブレット内でHttp通信を実装しようとしておりますが、
Key/Valueで取得できる方法が見つからず、困っております。

 【方法】

①ApacheのHttpClientクラス、PutMethodクラスを使用する方法
②HttpURLConnectionを使用する方法

 【実装ソース】

 ①HttpClientクラス、PutMethodクラスを使用する方法

■送信側

public class HttpClientFrom extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        System.out.println(this.getClass().toString() + "▼処理開始▼");

        URL url = new URL("http://localhost:8080/DymmyRenkei/HttpClientTo");

        HttpClient client = new HttpClient();
        PutMethod method = new PutMethod(url);

        // String文字列として&区切りでボディに設定するが受信側でKey/Value形式で取得できない。。。
        String entity = "test=bob&fruits=apples&hoge=こんにちは";
        RequestEntity et = new StringRequestEntity(entity, null, "UTF-8");

        method.setRequestEntity(entity);

        // 複数文字列をKey, Value形式で設定するが受信側の取得方法が不明。。。
        Part[] parts = {
                new StringPart("hogePart","こんにちはパート"),
                new StringPart("testPart","テスト文字列")
        };
        method.setRequestEntity(new MultipartRequestEntity(parts, method.getParams()));

        int statusCode = client.excuteMethod(method);
        System.out.println(statusCode);
        System.out.println(this.getClass().toString() + "▲処理終了▲");
    }
}

■受信側
※略:getInputStreamでBody部を読みこめば、
取得できることは確認できていますが、get~("Key")形式で取得する実装が実現できていない状況

 ②HttpURLConnectionを使用する方法

■送信側

public class ServletFrom extends HttpServlet {

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        System.out.println(this.getClass().toString() + "▼処理開始▼");

        URL url = new URL("http://localhost:8080/DymmyRenkei/To");

        HttpURLConnection con = (HttpURLConnection)url.openConnection();
        con.setRequestMethod("PUT");
        con.setInstanceFollowRedirects(false);
        con.setRequestProperty("Content-Type","application/x-www-form-urlencoded;charset=UTF-8");
        // setRequestPropertyでセットした値は送り先で取得できない... そもそも概念が違う?
        con.setRequestProperty("key", "value");
        con.setDoOutput(true);

        PrintStream ps = new PrintStream(con.getOutputStream());
        // ボディに" &区切りKey=Valued "で設定しても送り先でget系メソッドを使用して取得することはできない?
        ps.print("test=bob&fruits=apples&hoge=こんにちは");

        con.connect();

        int st = con.getResponseCode();
        System.out.println(st);

        System.out.println(this.getClass().toString() + "▲処理終了▲");



    }


}

■受信側

public class ServletTo extends HttpServlet {

    @Override
    public void doPut(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        System.out.println(this.getClass().toString() + "▼処理開始▼");
        BufferedReader in;
        in = new BufferedReader(new InputStreamReader(req.getInputStream()));

        String line;
        // Bodyに書き込んだ文字列がそのまま取れることは確認済み。加工しないとだめ? また、日本語がもじバケる現象
        while((line = in.readLine()) != null){
            System.out.println(line);
        }

        in.close();

        // bodyに&区切りで入れたデータが取れるかと思ったが取れない...
        System.out.println(req.getParameter("test"));
        System.out.println(req.getParameter("fruits"));
        System.out.println(req.getParameter("hoge"));

        // setRequestPropertyで設定した値はこれでは取れない...
        System.out.println(req.getParameter("key"));


        resp.setStatus(200);
        OutputStream out = resp.getOutputStream();
        out.write("★成功★".getBytes());



        System.out.println(this.getClass().toString() + "▲処理終了▲");

    }

}

 分かっていること

  • ヘッダー部であれば①、②の方法でKey/Valueで設定し取得できることを確認
  • HttpClientとPostMechodクラスであれば、addParameter("K","V")があるのでBody部にパラメータとして渡せること(putは無理なのかな)

 質問内容

  1. Putメソッドでボディー部にKey/Valueパラメータを設定して渡す方法があるかどうか(Body部に一定の形式(JSON、区切り文字等)で送ることを受信先と認識合わせしないとダメ?)
  2. ①の実装で受信側で文字化けを起こさない様な送信側、受信側の実装方法が知りたい(Charsetにセットする文字列をあわせるとか?)
  3. ①、②の受信側の実装方法の具体例が知りたい(そもそも一般的に上記の様な実装であってるか不安。。)
  4. 本件、参考になるURLがあれば知りたい。(いろんなサイトを拝見したのですが該当せず、英語のAPIを眺めても解決に至りませんでした。。)

箇条書きでいくつもすみません。

上記ご教示の程宜しくお願い致します。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+2

そうですね、ご明察です。
HttpServletのメソッドではBodyParameterは取得できず、あくまでサーブレット仕様で言うリクエストパラメータで認識できるパラメータしか getParameter() や getParameterValues() で取得できません。

なおHttpClientは現在4.5.2が最新ですので多少お使いのバージョンとは異なりますが、それでも送信側と受信側で文字コードと送信形式を合わせなければならないのは同じです。

文字化けの件については、HttpClientはBodyParameterに設定する際には、以下のコードのように対象文字列の文字コードを指定した上でURLエンコードした状態で送信できますので、受信側もURLDecodeで文字コードを指定して復元すれば文字化けは回避できるでしょう。

package sample;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

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.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/**
 * Servlet implementation class FromServlet
 */
@WebServlet("/FromServlet")
public class FromServlet 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 {
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPut put = new HttpPut("http://127.0.0.1:8080/Chaining/ToServlet");

        List<NameValuePair> nameValuePair = new ArrayList<>();
        nameValuePair.add(new BasicNameValuePair("username", "カピバラ"));
        nameValuePair.add(new BasicNameValuePair("address", "パンタナール一丁目"));

        put.setEntity(new UrlEncodedFormEntity(nameValuePair,"utf-8"));

        CloseableHttpResponse httpresponse = httpclient.execute(put);

        HttpEntity entity = httpresponse.getEntity();
        EntityUtils.consume(entity);

        httpresponse.close();
    }
}
package sample;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

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.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;

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

    /**
     * @see HttpServlet#doPut(HttpServletRequest, HttpServletResponse)
     */
    protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        log("encoding:" + request.getCharacterEncoding());

        Map<String,String[]> parameterMaps =  request.getParameterMap();
        parameterMaps.entrySet().stream().forEach(entry -> {
            log("key :" + entry.getKey() + "=" + entry.getValue());
        });

        BufferedReader in = new BufferedReader(new InputStreamReader(request.getInputStream()));
        String line;
        while((line = in.readLine()) != null){
            // RequestBody
            log(line);

            // URLデコードした内容
            log(URLDecoder.decode(line, "utf-8"));

            // Commons HttpClientのユーティリティで解析
            List<NameValuePair> nameValuePair = URLEncodedUtils.parse(line, Charset.forName("utf-8"));

            nameValuePair.stream().forEach(pair -> {
                log("paremeter: " + pair.getName() + " = " + pair.getValue());
            });
        }
        in.close();

        response.setHeader("responseKey", "received.");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.append("完了しました");

        out.flush();
        out.close();
    }
}

実行結果:

情報: sample.ToServlet: encoding:UTF-8 [土 7 09 23:33:53 JST 2016]
情報: sample.ToServlet: username=%E3%82%AB%E3%83%94%E3%83%90%E3%83%A9&address=%E3%83%91%E3%83%B3%E3%82%BF%E3%83%8A%E3%83%BC%E3%83%AB%E4%B8%80%E4%B8%81%E7%9B%AE [土 7 09 23:33:53 JST 2016]
情報: sample.ToServlet: username=カピバラ&address=パンタナール一丁目 [土 7 09 23:33:53 JST 2016]
情報: sample.ToServlet: paremeter: username = カピバラ [土 7 09 23:33:53 JST 2016]
情報: sample.ToServlet: paremeter: address = パンタナール一丁目 [土 7 09 23:33:53 JST 2016]

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/07/10 17:57

    ご回答ありがとう御座います。
    そうですよね。。

    サンプルのご提供ありがとう御座います。!

    >HttpServletのメソッドではBodyParameterは取得できない
    >エンコード指定は送受信で合わせる必要がある

    実行環境の記載ができておらず申し訳ございません、、
    開発環境として、
    ・Java1.5
    ・commons-httpclient-3.1.jar
    ・etc..
    で開発しておりますので、Commons時代のhttpclientしか使用できないような状況です。
    (Value部だけエンコードしてくれる便利なUtilもなく、不便です。。
    これだったらHttpURLConnectionでいいのかなと感じてます)

    ですので、①、②どちらかの方法でボディ部に
    ---Body
    key01=%Value02%&key02&%Value02%&...

    ---
    %~% はURLEncodeしている状態

    の様な形で実装しようかなと思っております*
    ありがとうございます。

    【commons-httpclient-3.1.jar】バージョンで実装
    https://github.com/tutttuwi/MyCat

    【参照API】
    https://hc.apache.org/httpclient-3.x/apidocs/overview-summary.html

    キャンセル

  • 2016/07/11 10:43

    d(・ω・

    キャンセル

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

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

関連した質問

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

  • トップ
  • Javaに関する質問
  • Javaサーブレット内のHttp通信Putメソッドでボディー部にKey/Valueパラメータを設定して渡す方法はありますか?