【Android】HttpClient（ HttpURLConnectionのラッパー。メソッドチェーンバージョン。

2017/02/08
POSTが動かなかったので修正しました

# はじめに
最近Androidエンジニアしてるぼく。
アプリ作ってるとHTTPリクエストしたくなるよね。
GETとかPOSTとかPUTとかDELETEとか。
基礎は「HttpURLConnection Android」でググってもらって。

HttpURLConnection使いにくいやんなー
ずっと自作のラッパー使ってたんやけどなー
使い古しすぎ&他クラスとの結合度高すぎやなー
なので、いい加減作り直した。
＊残念ながらmultipart/form-dataのPOST未対応。そのうちやる。
＊残念ながら動作確認はしていません。

・変更点
最近メソッドチェーンがマイブームやねんってことでメソッドチェーンに
マルチスレッド処理をAsyncTask→Thred+Runnableに
コールバックをinterfaceに
パラメータとかを自作のParamクラスで受け取ってたのやめ
レスポンスの加工までHttpClientでやってたのやめた
IxJava導入した
IOUtils発見した

# 下準備
・[【Java】HTTPステータスコード列挙型 Powered by Wikipedia](http://qiita.com/izumaru_akippa/items/f18044a4553e46e57c2d)を実装

・以下、追記

```text:build.gradle
dependencies {
    compile 'com.github.akarnokd:ixjava:0.90.0'
    compile 'org.apache.directory.studio:org.apache.commons.io:2.4'
}
```

```xml:AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />
```

# 実装
Githubに上げるのとかなんかナウくて嫌いなのでここで。

```Java:HttpClient
package com.akippa.akippacore.http;

import android.net.Uri;
import android.text.TextUtils;

import org.apache.commons.io.IOUtils;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

import ix.Ix;
import rx.functions.Action1;
import rx.functions.Func1;

// TODO:クッキーとかセッションとか。schooのソースにあるな。

/**
 * HTTPクライアント
 */
public final class HttpClient {

    public enum HttpMethod {
        GET("GET"),
        POST("POST"),
        DELETE("DELETE"),
        PUT("PUT");

        private final String mValue;

        HttpMethod(String value) {
            mValue = value;
        }

        @Override
        public String toString() {
            return mValue;
        }
    }

    private final Uri.Builder mBuilder;
    private Map<String, String> mRequestParameter = new HashMap<>();
    private String mEncode = "UTF-8";
    private HttpMethod mMethod = HttpMethod.GET;
    private int mConnectTimeout = 5000;
    private int mReadTimeout = 5000;
    private Map<String, String> mRequestProperty = new HashMap<>();
    private Proxy.Type mProxyType;
    private String mProxyServerAddress;
    private int mProxyServerPort;

    private HttpClient() {
        super();
        mBuilder = new Uri.Builder();
    }

    public static HttpClient create() {
        return new HttpClient();
    }

    public HttpClient setScheme(String scheme) {
        mBuilder.scheme(scheme);
        return this;
    }

    public HttpClient setEncodedAuthority(String authority) {
        mBuilder.encodedAuthority(authority);
        return this;
    }

    public HttpClient setPath(String path) {
        mBuilder.path(path);
        return this;
    }

    public HttpClient appendRequestParameter(String key, String value) {
        mRequestParameter.put(key, value);
        return this;
    }

    public HttpClient appendRequestParamter(final Map<String, String> param) {
        Ix.from(param.keySet()).forEach(new Action1<String>() {
            @Override
            public void call(String s) {
                mRequestParameter.put(s, param.get(s));
            }
        });
        return this;
    }

    public HttpClient setEncode(String encode) {
        mEncode = encode;
        return this;
    }

    public HttpClient setMethod(HttpMethod method) {
        mMethod = method;
        return this;
    }

    public HttpClient setConnectTimeout(int connectTimeout) {
        mConnectTimeout = connectTimeout;
        return this;
    }

    public HttpClient setReadTimeout(int readTimeout) {
        mReadTimeout = readTimeout;
        return this;
    }

    public HttpClient setRequestProperty(String key, String value) {
        mRequestProperty.put(key, value);
        return this;
    }

    public HttpClient setRequestProperty(Map<String, String> requestProperty) {
        mRequestProperty = requestProperty;
        return this;
    }

    public HttpClient setProxy(Proxy.Type proxyType, String serverAddress, int serverPort) {
        mProxyType = proxyType;
        mProxyServerAddress = serverAddress;
        mProxyServerPort = serverPort;
        return this;
    }

    private HttpURLConnection createConnection() throws IOException {
        switch (mMethod) {
            case GET:
            case DELETE:
                Ix.from(mRequestParameter.keySet()).forEach(new Action1<String>() {
                    @Override
                    public void call(String s) {
                        mBuilder.appendQueryParameter(s, mRequestParameter.get(s));
                    }
                });
                break;
        }

        final HttpURLConnection httpURLConnection = mProxyServerAddress == null
                ? (HttpURLConnection) new URL(URLDecoder.decode(mBuilder.build().toString(), mEncode)).openConnection()
                : (HttpURLConnection) new URL(URLDecoder.decode(mBuilder.build().toString(), mEncode)).openConnection(new Proxy(mProxyType, new InetSocketAddress(mProxyServerAddress, mProxyServerPort)));
        httpURLConnection.setRequestMethod(mMethod.toString());
        httpURLConnection.setConnectTimeout(mConnectTimeout);
        httpURLConnection.setReadTimeout(mReadTimeout);
        Ix.from(mRequestProperty.keySet()).forEach(new Action1<String>() {
            @Override
            public void call(String s) {
                httpURLConnection.setRequestProperty(s, mRequestProperty.get(s));
            }
        });
        switch (mMethod) {
            case POST:
            case PUT:
                httpURLConnection.setDoOutput(true);
                httpURLConnection.setDoInput(true);
                httpURLConnection.setUseCaches(false);
                final String requestBody = TextUtils.join("&",
                        Ix.from(mRequestParameter.keySet()).map(new Func1<String, String>() {
                            @Override
                            public String call(String s) {
                                try {
                                    return String.format("%s=%s",
                                            URLEncoder.encode(s, "UTF-8"),
                                            URLEncoder.encode(mRequestParameter.get(s), "UTF-8"));
                                } catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                                }
                                return "";
                            }
                        }).toArray(new String[]{}));
                if (requestBody.length() > 0) {
                    final OutputStream outputStream = httpURLConnection.getOutputStream();
                    final BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream, mEncode));
                    bufferedWriter.write(requestBody);
                    bufferedWriter.flush();
                    bufferedWriter.close();
                    outputStream.flush();
                    outputStream.close();
                }
                break;
        }
        return httpURLConnection;
    }

    public void sendRequest(final SendRequestCallBack callBack) {
        new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        final HttpURLConnection httpURLConnection;
                        try {
                            httpURLConnection = createConnection();
                        } catch (IOException e) {
                            e.printStackTrace();
                            return;
                        }

                        HttpStatusCode httpStatusCode;
                        try {
                            httpURLConnection.connect();
                            httpStatusCode = HttpStatusCode.getByStatusCode(httpURLConnection.getResponseCode());
                        } catch (IOException e) {
                            e.printStackTrace();
                            callBack.onFailure(HttpStatusCode.DEFAULT);
                            return;
                        }

                        try {
                            callBack.onSuccess(httpStatusCode, IOUtils.toString(httpURLConnection.getInputStream()));
                        } catch (IOException e) {
                            e.printStackTrace();
                            callBack.onFailure(httpStatusCode);
                        }
                    }
                }
        ).start();
    }

    public interface SendRequestCallBack {

        void onFailure(HttpStatusCode code);

        void onSuccess(HttpStatusCode code, String responseText);
    }
}
```

# 使い方

```Java:sample
HttpClient.create()
        .setScheme("https")
        .setEncodedAuthority("www.google.co.jp")
        .setPath("search")
        .appendRequestParameter("q", "akippa")
        .appendRequestParameter("rct", "j")
        .setMethod(HttpClient.HttpMethod.GET)
        .sendRequest(new HttpClient.SendRequestCallBack() {
            @Override
            public void onFailure(HttpStatusCode code) {
                Log.d("log", String.format("HttpStatusCode:%s", code.toString()));
            }

            @Override
            public void onSuccess(HttpStatusCode code, String responseText) {
                Log.d("log", String.format("HttpStatusCode:%s : Response:%s", code.toString(), responseText));
            }
        });
```