JavaでJSONをPOSTする方法　～OkHttp3を使った方法とHttpUrlConnectionを使った方法～

# 概要
JavaでJSONをHTTP POSTしたりHTTP GETしたりする方法をまとめます。
JavaでJSON→Java、Java→JSON するやり方については**[前稿](https://qiita.com/riversun/items/cdd990e96c2bbf9cb043)**でまとめています

- <b>【本稿】JavaでHTTP通信でJSONをPOSTしたり、GETする方法についてまとめます</b>
    - JavaでHTTP通信をするやり方も2通り説明します
        - OkHttp3を使ったやり方
        - Java標準パッケージである**HttpUrlConnection**を使ったやり方

- [【前稿】JavaでJSONを扱う方法についてまとめます](https://qiita.com/riversun/items/cdd990e96c2bbf9cb043)
    - JSONをJavaに変換(デシリアライズ)、JavaをJSONに変換(シリアライズ)するやり方は2通り説明します
        - ライブラリにGSONを使うやり方
        - ライブラリにJacksonを使うやり方

# 準備
HTTP通信をする前にJava→JSON(シリアライズ)やJSON→Java(デシリアライズ)ができるようにする必要がある。
それをお手軽にやる方法は、[**こちらの記事**](https://qiita.com/riversun/items/cdd990e96c2bbf9cb043)にまとめているので、ここではスキップする。

サーバーからGETしたり、サーバーにPOSTするJSONは以下の形式としてコードを考える。

```json:サンプルのJSON文字列：example.json
{
    "person": {
        "firstName": "John",
        "lastName": "Doe",
        "address": "NewYork",
        "pets": [
            {"type": "Dog", "name": "Jolly"},
            {"type": "Cat", "name": "Grizabella"},
            {"type": "Fish", "name": "Nimo"}
        ]
    }
}
```

本稿では、HTTP通信するところにフォーカスする

# JavaでHTTP通信する方法

2通りのアプローチを説明する

- ライブラリ(OkHttp3)を使った方法
HTTP通信できるライブラリはたくさんあるが、本稿では OkHttp3 をとりあげる。

- ライブラリを使わない方法
外部のライブラリを使わずJava標準パッケージ HttpUrlConnection を使う方法をとりあげる。


# OkHttp3を使ってJSONをPOST、GETする

## OkHttp3のライブラリ依存関係

OkHttp3のライブラリ指定方法は以下のとおり

■ OkHttp3の最新ライブラリ(mavenリポジトリ)
https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp

■ OkHttp3の**maven**設定例

```xml:pom.xml
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.14.1</version>
</dependency>
```

■ OkHttp3の**gradle**設定例

```groovy:build.gradle
compile 'com.squareup.okhttp3:okhttp:3.14.1'
```

## OkHttp3を使ってJSONをHTTP POSTする

JSON文字列をPOSTして、結果の文字列を受け取るHTTPクライアントのサンプルは以下のとおり

```java:OkHttpPostClient.java
/**
 * HTTPライブラリに「OkHttp3」、GSON操作ライブラリに「GSON」をつかって、
 * サーバーにJSONを「POST」するサンプル
 */
public class OkHttpPostClient {

    public static void main(String[] args) throws IOException {
        OkHttpPostClient client = new OkHttpPostClient();
        String result = client.callWebAPI();
        System.out.println(result);
    }

    private static final String WEB_API_ENDPOINT = "http://localhost:8080/api";

    public String callWebAPI() throws IOException {

        final String postJson = "{" +
                "    \"person\": {" +
                "        \"firstName\": \"John\"," +
                "        \"lastName\": \"Doe\"," +
                "        \"address\": \"NewYork\"," +
                "        \"pets\": [" +
                "            {\"type\": \"Dog\", \"name\": \"Jolly\"}," +
                "            {\"type\": \"Cat\", \"name\": \"Grizabella\"}," +
                "            {\"type\": \"Fish\", \"name\": \"Nimo\"}" +
                "        ]" +
                "    }" +
                "}";

        final Map<String, String> httpHeaders = new LinkedHashMap<String, String>();
        final String resultStr = doPost(WEB_API_ENDPOINT, "UTF-8", httpHeaders, postJson);

        return resultStr;
    }

    public String doPost(String url, String encoding, Map<String, String> headers, String jsonString) throws IOException {
        final okhttp3.MediaType mediaTypeJson = okhttp3.MediaType.parse("application/json; charset=" + encoding);

        final RequestBody requestBody = RequestBody.create(mediaTypeJson, jsonString);

        final Request request = new Request.Builder()
                .url(url)
                .headers(Headers.of(headers))
                .post(requestBody)
                .build();

        final OkHttpClient client = new OkHttpClient.Builder()
                .build();
        final Response response = client.newCall(request).execute();
        final String resultStr = response.body().string();
        return resultStr;
    }
}
```

## OkHttp3を使ってJSONをHTTP GETする

**GET**するコードは以下の部分がポイントとなる。
以下ではurlとheaderを指定して、**GET**を実行する。
結果をテキストとして取得するには **response.body().string()**のようにする。

```java
public String doGet(String url, Map<String, String> headers) throws IOException {
    final Request request = new Request.Builder()
            .url(url)
            .headers(Headers.of(headers))
            .build();
    final OkHttpClient client = new OkHttpClient.Builder().build();
    final Response response = client.newCall(request).execute();
    final String resultStr = response.body().string();
    return resultStr;
}
```

以下はフルソースコード。
http://localhost:8080/api　にアクセスする例となる。
実験用にサーバー側のコードも下に掲載する。


```java:OkHttpGetClient.java(ソースコード)

public class OkHttpGetClient {

    public static void main(String[] args) throws IOException {
        OkHttpGetClient client = new OkHttpGetClient();
        Model result = client.callWebAPI();
        System.out.println("Firstname is " + result.person.firstName);
    }

    private static final String WEB_API_ENDPOINT = "http://localhost:8080/api";
    private final Gson mGson = new Gson();

    public Model callWebAPI() throws IOException {
        final Map<String, String> httpHeaders = new LinkedHashMap<String, String>();
        final String resultStr = doGet(WEB_API_ENDPOINT, httpHeaders);
        final Model model = mGson.fromJson(resultStr, Model.class);
        return model;
    }

    public String doGet(String url, Map<String, String> headers) throws IOException {
        final Request request = new Request.Builder()
                .url(url)
                .headers(Headers.of(headers))
                .build();
        final OkHttpClient client = new OkHttpClient.Builder().build();
        final Response response = client.newCall(request).execute();
        final String resultStr = response.body().string();
        return resultStr;
    }

}
```

## サーバー側のソースコード

実験用にサーバー側としてJettyをつかった簡易Web APIサーバーのコードを示す

```java
/**
 * ・GETされると、JSON文字列を返す<br>
 * ・JSONをPOSTされると、JSONを解析して結果を返す<br>
 * HTTPサーバー
 */
public class JsonApiServer {
    public static void main(String[] args) {
        final int PORT = 8080;
        final Class<? extends Servlet> servlet = ExampleServlet.class;
        ServletContextHandler servletHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
        servletHandler.addServlet(new ServletHolder(servlet), "/api");

        final Server jettyServer = new Server(PORT);
        jettyServer.setHandler(servletHandler);
        try {
            jettyServer.start();
            jettyServer.join();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @SuppressWarnings("serial")
    public static class ExampleServlet extends HttpServlet {

        private final Gson mGson = new Gson();

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

            Model model = new Model();
            model.person = new Person();
            model.person.firstName = "ジョン";
            model.person.lastName = "ドゥ";
            model.person.address = "ニューヨーク";
            model.person.pets = new ArrayList<Pet>();
            Pet pet1 = new Pet();
            pet1.type = "犬";
            pet1.name = "ジョリー";
            model.person.pets.add(pet1);
            Pet pet2 = new Pet();
            pet2.type = "猫";
            pet2.name = "グリザベラ";
            model.person.pets.add(pet2);
            Pet pet3 = new Pet();
            pet3.type = "魚";
            pet3.name = "ニモ";
            model.person.pets.add(pet3);

            String json = mGson.toJson(model);

            resp.setContentType("text/html; charset=UTF-8");
            resp.setCharacterEncoding("UTF-8");
            final PrintWriter out = resp.getWriter();
            out.println(json);
            out.close();

        }

        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            final StringBuilder sb = new StringBuilder();
            String line = null;
            try {
                BufferedReader reader = req.getReader();
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (Exception e) {
            }
            final String body = sb.toString();
            final Model model = mGson.fromJson(body, Model.class);
            resp.setContentType("text/html; charset=UTF-8");
            resp.setCharacterEncoding("UTF-8");
            final PrintWriter out = resp.getWriter();
            out.println("Server Generated Message");
            out.println("Firstname is " + model.person.firstName);
            out.close();
        }
    }
}
```

ソースコード一式は以下となる
https://github.com/riversun/java-json-gson-jackson-http

# HttpUrlConnectionを使ってJSONをPOST、GETする

## 依存ライブラリ

HttpUrlConnectionはJavaの標準パッケージなので、外部のライブラリなどは**不要**。

ライブラリは便利で洗練されている場合も多いが、例えば、Android環境のDEXファイル64Kの壁など、多機能なライブラリ導入による依存ライブラリ数増大・総メソッド数増大を回避をしたい場合など、まだ活用の余地がある。

## HttpUrlConnectionを使ってJSONをHTTP POSTする

前述した通り、Android等Javaベースの環境でも幅広く使えるよう、記法は**Java1.6 Compliant**とした。

```UrlConnHttpPostClient.java
/**
 * HTTP通信にはJava標準の「HttpUrlConnection」、GSON操作ライブラリに「GSON」をつかって、
 * サーバーからJSONを「POST」するサンプル
 */
public class UrlConnHttpPostClient {

    public static void main(String[] args) throws IOException {
        UrlConnHttpPostClientclient = new UrlConnHttpPostClient();
        String result = client.callWebAPI();
        System.out.println(result);
    }

    private static final String WEB_API_ENDPOINT = "http://localhost:8080/api";

    public String callWebAPI() throws IOException {

        final String postJson = "{" +
                "    \"person\": {" +
                "        \"firstName\": \"John\"," +
                "        \"lastName\": \"Doe\"," +
                "        \"address\": \"NewYork\"," +
                "        \"pets\": [" +
                "            {\"type\": \"Dog\", \"name\": \"Jolly\"}," +
                "            {\"type\": \"Cat\", \"name\": \"Grizabella\"}," +
                "            {\"type\": \"Fish\", \"name\": \"Nimo\"}" +
                "        ]" +
                "    }" +
                "}";

        final Map<String, String> httpHeaders = new LinkedHashMap<String, String>();
        final String resultStr = doPost(WEB_API_ENDPOINT, "UTF-8", httpHeaders, postJson);

        return resultStr;
    }

    private String doPost(String url, String encoding, Map<String, String> headers, String jsonString) throws IOException {

        final int TIMEOUT_MILLIS = 0;// タイムアウトミリ秒：0は無限

        final StringBuffer sb = new StringBuffer("");

        HttpURLConnection httpConn = null;
        BufferedReader br = null;
        InputStream is = null;
        InputStreamReader isr = null;

        try {
            URL urlObj = new URL(url);
            httpConn = (HttpURLConnection) urlObj.openConnection();
            httpConn.setConnectTimeout(TIMEOUT_MILLIS);// 接続にかかる時間
            httpConn.setReadTimeout(TIMEOUT_MILLIS);// データの読み込みにかかる時間
            httpConn.setRequestMethod("POST");// HTTPメソッド
            httpConn.setUseCaches(false);// キャッシュ利用
            httpConn.setDoOutput(true);// リクエストのボディの送信を許可(GETのときはfalse,POSTのときはtrueにする)
            httpConn.setDoInput(true);// レスポンスのボディの受信を許可

            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpConn.setRequestProperty(key, headers.get(key));// HTTPヘッダをセット
                }
            }

            final OutputStream os = httpConn.getOutputStream();
            final boolean autoFlash = true;
            final PrintStream ps = new PrintStream(os, autoFlash, encoding);
            ps.print(jsonString);
            ps.close();

            final int responseCode = httpConn.getResponseCode();

            String _responseEncoding = httpConn.getContentEncoding();
            if (_responseEncoding == null) {
                _responseEncoding = "UTF-8";
            }

            if (responseCode == HttpURLConnection.HTTP_OK) {
                is = httpConn.getInputStream();
                isr = new InputStreamReader(is, _responseEncoding);
                br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
            } else {
                // ステータスがHTTP_OK(200)以外の場合
                throw new IOException("responseCode is " + responseCode);
            }

        } catch (IOException e) {
            throw e;
        } finally {
            // Java1.6 Compliant
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                }
            }
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }
        return sb.toString();
    }
}
```

## HttpUrlConnectionを使ってJSONをHTTP GETする

```java:UrlConnHttpGetClient.java
package com.example.http_client.urlconnection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.LinkedHashMap;
import java.util.Map;

import com.example.jackson.Model;
import com.google.gson.Gson;

/**
 * HTTP通信にはJava標準の「HttpUrlConnection」、GSON操作ライブラリに「GSON」をつかって、
 * サーバーからJSONを「GET」するサンプル
 */
public class UrlConnHttpGetClient {

    public static void main(String[] args) throws IOException {
        UrlConnHttpGetClient client = new UrlConnHttpGetClient();
        Model result = client.callWebAPI();
        System.out.println("Firstname is " + result.person.firstName);
    }

    private static final String WEB_API_ENDPOINT = "http://localhost:8080/api";
    private final Gson mGson = new Gson();

    public Model callWebAPI() throws IOException {
        final Map<String, String> httpHeaders = new LinkedHashMap<String, String>();
        final String resultStr = doGet(WEB_API_ENDPOINT, httpHeaders);
        final Model model = mGson.fromJson(resultStr, Model.class);
        return model;
    }

    public String doGet(String url, Map<String, String> headers) throws IOException {
        final int TIMEOUT_MILLIS = 0;// タイムアウトミリ秒：0は無限
        final StringBuffer sb = new StringBuffer("");

        HttpURLConnection httpConn = null;
        BufferedReader br = null;
        InputStream is = null;
        InputStreamReader isr = null;

        try {
            URL urlObj = new URL(url);
            httpConn = (HttpURLConnection) urlObj.openConnection();
            httpConn.setConnectTimeout(TIMEOUT_MILLIS);// 接続にかかる時間
            httpConn.setReadTimeout(TIMEOUT_MILLIS);// データの読み込みにかかる時間
            httpConn.setRequestMethod("GET");// HTTPメソッド
            httpConn.setUseCaches(false);// キャッシュ利用
            httpConn.setDoOutput(false);// リクエストのボディの送信を許可(GETのときはfalse,POSTのときはtrueにする)
            httpConn.setDoInput(true);// レスポンスのボディの受信を許可

            if (headers != null) {
                for (String key : headers.keySet()) {
                    httpConn.setRequestProperty(key, headers.get(key));// HTTPヘッダをセット
                }
            }

            final int responseCode = httpConn.getResponseCode();

            String encoding = httpConn.getContentEncoding();
            if (encoding == null) {
                encoding = "UTF-8";
            }

            if (responseCode == HttpURLConnection.HTTP_OK) {
                is = httpConn.getInputStream();
                isr = new InputStreamReader(is, encoding);
                br = new BufferedReader(isr);
                String line = null;
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }
            } else {
                // ステータスがHTTP_OK(200)以外の場合
                throw new IOException("responseCode is " + responseCode);
            }

        } catch (IOException e) {
            throw e;
        } finally {
            // Java1.6 Compliant
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                }
            }
            if (isr != null) {
                try {
                    isr.close();
                } catch (IOException e) {
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
            if (httpConn != null) {
                httpConn.disconnect();
            }
        }
        return sb.toString();
    }
}
```

# まとめ
- JavaでHTTP通信をするやり方も2通り紹介しました
    - **OkHttp3**を使ったやり方
    - Java標準パッケージである**HttpUrlConnection**を使ったやり方

- 全ソースコードは[こちら](https://github.com/riversun/java-json-gson-jackson-http)にあります