Apache HttpClient は Java で HTTP 通信を使ったプログラムを開発するときに便利なクラスライブラリです。HTTP/1.0 および HTTP/1.1 規格に基づいており、すべての HTTP メソッド (GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE) をサポートしています。
ここでは2017年4月時点で最新の HttpClient 4.5 を使ったサンプルコードを紹介します。
次のリクエストを送信するようにします。
PUT /wagby/rest/session HTTP/1.1 Content-Type: application/x-www-form-urlencoded user=admin&pass=admin
次のリクエストを送信するようにします。
GET /wagby/rest/customer/entry/1000 HTTP/1.1
次のリクエストを送信するようにします。
DELETE /wagby/rest/session HTTP/1.1
コードは次のとおりです。
/* * Copyright (C) Since 2006 JasmineSoft Inc. All Rights Reserved. */ package jp.jasminesoft.wagby.sample; import java.io.IOException; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CookieStore; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; /** * HttpClient を使って REST API へアクセスを行うサンプルコードです。 * * @author JasmineSoft */ public class HttpClientSample { /** * メインメソッド * @param args コマンドライン引数 */ public static void main(String[] args) { // CAUTION: 以下のコードはエラーハンドリングを行っていません。 // 各処理で発生した Exception を適切に処理するようにして下さい。 BasicCookieStore cookieStore = new BasicCookieStore(); String baseUrl = "http://localhost:8921/wagby/rest"; // ログオン HttpUriRequest request = RequestBuilder.put() .setUri(baseUrl + "/session") //.setHeader("Content-Type", "application/x-www-form-urlencoded") // HttpClient では省略可 .addParameter("user", "admin") .addParameter("pass", "admin") .build(); String content = execute(request, cookieStore); // 顧客データを取得(主キー:1000) request = RequestBuilder.get() .setUri(baseUrl + "/customer/entry/1000") .build(); content = execute(request, cookieStore); // 顧客データを取得(主キー:1001) request = RequestBuilder.get() .setUri(baseUrl + "/customer/entry/1001") .build(); content = execute(request, cookieStore); // ログオフ request = RequestBuilder.delete() .setUri(baseUrl + "/session") .build(); content = execute(request, cookieStore); } /** * Executes HTTP request. * @param request the request to execute * @param cookieStore CookieStore * @return String containing the content. */ private static String execute(HttpUriRequest request, CookieStore cookieStore) { System.out.println("Executing request " + request.getRequestLine()); try (CloseableHttpClient client = createDefaultClient(cookieStore); CloseableHttpResponse response = client.execute(request)) { //// Set-Cookie ヘッダをコンソールへ出力する。 //for (Header header : response.getHeaders("Set-Cookie")) { // System.out.println( // header.getName() + " : " + header.getValue()); //} int status = response.getStatusLine().getStatusCode(); if (status >= 200 && status < 300) { // HTTP ステータスコードが 200 番台の場合のみ処理を行う。 HttpEntity entity = response.getEntity(); if (entity != null) { String content = EntityUtils.toString(entity); System.out.println(content); return content; } throw new IllegalStateException( "Successful request, but response is empty!"); } else { throw new ClientProtocolException( "Unexpected response status: " + status); } } catch (IOException e) { throw new RuntimeException(e); } } /** * create Http client. * @param cookieStore CookieStore * @return Http client */ private static CloseableHttpClient createDefaultClient( CookieStore cookieStore) { return HttpClients.custom() .setDefaultCookieStore(cookieStore) .build(); } }
cookie には JSESSIONID が格納されます。これが正しく動作することで、セッション(ログオン状態)を維持します。
上のサンプルコードをベースに、一覧取得、登録、更新、削除を行う例を加えます。
次のリクエストを送信するようにします。
GET /wagby/rest/customer/list HTTP/1.1
顧客名「ジャスミン太郎」で検索する例です。次のリクエストを送信するようにします。
POST /wagby/rest/customer/list HTTP/1.1 Content-Type: application/x-www-form-urlencoded customer_cp%24002fname=%E3%82%B8%E3%83%A3%E3%82%B9%E3%83%9F%E3%83%B3%E5%A4%AA%E9%83%8E
同じく顧客名「ジャスミン太郎」で検索する例です。パラメータを JSON 形式で用意します。次のリクエストを送信するようにします。
POST /wagby/rest/customer/list HTTP/1.1 Content-Type: application/json { "name": {"content":"ジャスミン太郎"}}
最初に新規登録を開始します。初期値が埋まった状態のデータを取得することができます。
GET /wagby/rest/customer/new HTTP/1.1
得られたデータを編集し、保存します。
POST /wagby/rest/customer/new HTTP/1.1 Content-Type: application/json { ... ,"name_":{"content_":"ジャスミン三郎" ... },"kananame_":{"content_":"ジャスミンサブロウ" ... } ... }
主キー (pkey) を指定して、更新処理を開始します。このとき、更新対象データはロックされます。(注:Wagbyの標準である悲観ロックを利用した、という場合です。)
GET /wagby/rest/customer/edit/{pkey} HTTP/1.1
得られたデータを編集し、保存します。
PUT /wagby/rest/customer/edit/{pkey} HTTP/1.1 Content-Type: application/json { ... "deptname_":{"content_":"営業部" ... } ... }
主キー (pkey) を指定して、削除を行います。
DELETE /wagby/rest/customer/edit/{pkey} HTTP/1.1
コードは次のとおりです。
/* * Copyright (C) Since 2006 JasmineSoft Inc. All Rights Reserved. */ package jp.jasminesoft.wagby.sample; import java.io.IOException; import java.util.Map; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import jp.jasminesoft.jfc.app.JAXBJacksonModule; import jp.jasminesoft.wagby.model.customer_p.CustomerP; import jp.jasminesoft.wagby.model.customer_p.Deptname; import jp.jasminesoft.wagby.model.customer_p.Kananame; import jp.jasminesoft.wagby.model.customer_p.Name; import org.apache.http.Consts; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CookieStore; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.RequestBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; /** * HttpClient を使って REST API へアクセスを行うサンプルコードです。 * * @author JasmineSoft */ public class HttpClientSample { /** * メインメソッド * @param args コマンドライン引数 */ public static void main(String[] args) { // CAUTION: 以下のコードはエラーハンドリングを行っていません。 // 各処理で発生した Exception を適切に処理するようにして下さい。 BasicCookieStore cookieStore = new BasicCookieStore(); String baseUrl = "http://localhost:8921/wagby/rest"; // ログオン HttpUriRequest request = RequestBuilder.put() .setUri(baseUrl + "/session") //.setHeader("Content-Type", "application/x-www-form-urlencoded") // HttpClient では省略可 .addParameter("user", "admin") .addParameter("pass", "admin") .build(); String content = execute(request, cookieStore); // ログオン状態の確認 request = RequestBuilder.get() .setUri(baseUrl + "/session") .build(); content = execute(request, cookieStore); // 顧客一覧を取得(検索条件なし) request = RequestBuilder.get() .setUri(baseUrl + "/customer/list") .build(); content = execute(request, cookieStore); // 顧客一覧を取得(顧客名「ジャスミン太郎」で検索) request = RequestBuilder.post() .setUri(baseUrl + "/customer/list") //.setHeader("Content-Type", "application/x-www-form-urlencoded") // HttpClient では省略可 .addParameter("customer_cp$002fname", "ジャスミン太郎") .build(); content = execute(request, cookieStore); // json:顧客一覧を取得(顧客名「ジャスミン太郎」で検索) String json = "{ \"name\": {\"content\":\"ジャスミン太郎\"}}"; request = RequestBuilder.post() .setUri(baseUrl + "/customer/list") .setHeader("Content-Type", "application/json") .setEntity(new StringEntity(json, Consts.UTF_8)) .build(); content = execute(request, cookieStore); // 顧客データを取得(主キー:1000) request = RequestBuilder.get() .setUri(baseUrl + "/customer/entry/1000") .build(); content = execute(request, cookieStore); // 顧客データの新規登録開始(初期値が埋まった状態のデータが取得できる)。 request = RequestBuilder.get() .setUri(baseUrl + "/customer/new") .build(); content = execute(request, cookieStore); // 取得した json データの entityp フィールドを CustomerP に変換 CustomerP customer_p = toObject( toJsonNode(content).get("entityp"), CustomerP.class); // name 項目に「ジャスミン三郎」を指定 Name name = new Name(); name.setContent("ジャスミン三郎"); customer_p.setName(name); //customer_p.setName(new Name()); //customer_p.getName().setContent("ジャスミン三郎"); // kananame 項目に「ジャスミンサブロウ」を指定 Kananame kananame = new Kananame(); kananame.setContent("ジャスミンサブロウ"); customer_p.setKananame(kananame); //customer_p.setKananame(new Kananame()); //customer_p.getKananame().setContent("ジャスミンサブロウ"); // 顧客データの新規登録(保存)。 request = RequestBuilder.post() .setUri(baseUrl + "/customer/new") .setHeader("Content-Type", "application/json") .setEntity(new StringEntity(toJson(customer_p), Consts.UTF_8)) .build(); content = execute(request, cookieStore); // 登録時に自動採番された主キーを取得。 // 取得した json データの pkey フィールドが主キー値となっている。 String pkey = toJsonNode(content).get("pkey").textValue(); // 顧客データの更新開始。 request = RequestBuilder.get() .setUri(baseUrl + "/customer/edit/" + pkey) .build(); content = execute(request, cookieStore); // 取得した json データの entityp フィールドを CustomerP に変換 customer_p = toObject( toJsonNode(content).get("entityp"), CustomerP.class); // deptname 項目に「営業部」を指定 Deptname deptname = new Deptname(); deptname.setContent("営業部"); customer_p.setDeptname(deptname); //customer_p.setDeptname(new Deptname()); //customer_p.getDeptname().setContent("営業部"); // 顧客データの更新(保存)。 request = RequestBuilder.put() .setUri(baseUrl + "/customer/edit/" + pkey) .setHeader("Content-Type", "application/json") .setEntity(new StringEntity(toJson(customer_p), Consts.UTF_8)) .build(); content = execute(request, cookieStore); // 顧客データを取得(正しく更新されているか確認) request = RequestBuilder.get() .setUri(baseUrl + "/customer/entry/" + pkey) .build(); content = execute(request, cookieStore); // 顧客データを削除(主キー:1000) request = RequestBuilder.delete() .setUri(baseUrl + "/customer/edit/" + pkey) .build(); content = execute(request, cookieStore); // ログオフ request = RequestBuilder.delete() .setUri(baseUrl + "/session") .build(); content = execute(request, cookieStore); } /** * Executes HTTP request. * @param request the request to execute * @param cookieStore CookieStore * @return String containing the content. */ private static String execute(HttpUriRequest request, CookieStore cookieStore) { System.out.println("Executing request " + request.getRequestLine()); try (CloseableHttpClient client = createDefaultClient(cookieStore); CloseableHttpResponse response = client.execute(request)) { //// Set-Cookie ヘッダをコンソールへ出力する。 //for (Header header : response.getHeaders("Set-Cookie")) { // System.out.println( // header.getName() + " : " + header.getValue()); //} int status = response.getStatusLine().getStatusCode(); if (status >= 200 && status < 300) { // HTTP ステータスコードが 200 番台の場合のみ処理を行う。 HttpEntity entity = response.getEntity(); if (entity != null) { String content = EntityUtils.toString(entity); System.out.println(content); return content; } throw new IllegalStateException( "Successful request, but response is empty!"); } else { throw new ClientProtocolException( "Unexpected response status: " + status); } } catch (IOException e) { throw new RuntimeException(e); } } /** * create Http client. * @param cookieStore CookieStore * @return Http client */ private static CloseableHttpClient createDefaultClient( CookieStore cookieStore) { return HttpClients.custom() .setDefaultCookieStore(cookieStore) .build(); } /** * Java オブジェクトを JSON 文字列に変換します。 * @param value 変換対象の Java オブジェクト * @return Java オブジェクトを変換した JSON 文字列 */ private static String toJson(Object value) { ObjectMapper mapper = new ObjectMapper(); try { return mapper.writeValueAsString(value); } catch (JsonProcessingException e) { throw new RuntimeException(e); } } /** * JSON 文字列を JsonNode に変換します。 * @param json JSON 文字列 * @return JsonNode */ private static JsonNode toJsonNode(String json) { try { ObjectMapper mapper = new ObjectMapper(); return mapper.readTree(json); } catch (JsonParseException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } /** * JsonNode を clazz のインスタンスに変換します。 * @param <P> 変換後のクラスの型 * @param node JsonNode * @param clazz 変換後のクラス * @return clazz のインスタンス */ private static <P> P toObject(JsonNode node, Class<P> clazz) { return toObject(node.toString(), clazz); } /** * JSON 文字列を clazz のインスタンスに変換します。 * @param <P> 変換後のクラスの型 * @param json JSON 文字列 * @param clazz 変換後のクラス * @return clazz のインスタンス */ private static <P> P toObject(String json, Class<P> clazz) { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JAXBJacksonModule()); // JAXB のアノテーションを利用した変換ルール try { return mapper.readValue(json, clazz); } catch (IOException e) { throw new RuntimeException(e); } } }