画面
# ソースコード ### Java ### API1.javaRESTful API サーバプログラムの開発 pic.twitter.com/qLK16NBesn
— いまむら たくま (@Imamuuu5) May 15, 2023
package App28;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/api1")
public class API1 extends HttpServlet {
// GET 処理(GET メソッドで HTTP リクエストが送られてくるたびに実行される)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// レスポンスの設定(毎回この設定)
response.setHeader("Cache-Control", "no-cache"); // キャッシュを利用しない
response.setHeader("Pragma", "no-cache"); // キャッシュを利用しない(下位互換性用)
response.setDateHeader("Expires", 0); // キャッシュ有効期限0
response.setCharacterEncoding("UTF-8"); // レスポンス文字コード UTF-8 設定
response.setContentType("application/json"); // レスポンスタイプ application/json 設定
// レスポンスボディ作成処理
PrintWriter out = response.getWriter(); // レスポンス書き込み用 PrintWriter 取得
out.println("{\"value\": \"こんにちは\"}"); // レスポンス書き込み {"name": "こんにちは"}
out.flush(); // フラッシュ処理(強制送信のようなもの)
out.close(); // PrintWriterのクローズ(これ以降書き込めない)
}
}
説明
RESTful API について
RESTとは Representational State Transfer(リプレゼンテーショナル、ステート、トランスファー) の略で、直訳すると 代表的な状態の転送 となる。
REST には、こういう設計をすべきという制約がいくつか存在し、それらの制約を満たしたものを RESTful と呼んでおり、**RESTの要件を満たしたアプリケーションインタフェース(API) **という事で RESTful API と呼んでいる。(単に REST や REST API とも言う)
Servletについて
Servlet を用いて RESTful API を作成したい場合、必ず 「HttpServlet」 を継承したクラスを作成しなければいけない。
HttpServlet を継承することにより、ネットを通じてこのプログラムにアクセスが可能となる。
public class API1 extends HttpServlet {
}
classの上にある @WebServlet("/api1") という部分は WebServletアノテーション と呼ばれるもので、このプログラムを呼ぶためのアドレス を記述する命令になっており、これを記述しないとプログラムを実行することができない。
今回の場合 /api1 と指定しているため、URLが以下のように設定されたことになる。
http://localhost:8080/App28/api1
Servletにおけるアドレス(URL)の意味
プロトコル :// ホストドメイン : ポート番号 / プロジェクト名 / パス
項目 | 値 |
---|---|
プロトコル | http |
ホストドメイン | localhost |
ポート番号 | 8080 |
プロジェクト名 | App28 |
パス | api1 |
WebServlet アノテーションでは、このパスに当たる部分のみを指定するのだが、値は何でも良い。
仮に以下のような設定の場合、API1を実行するアドレスはこのようになる
@WebServlet("/taro")
public class API1 extends HttpServlet {
}
http://localhost:8080/App28/taro
このアドレスになる。
「doGet()」 メソッドについて
実行させたい処理本体は 「doGet()」 メソッドに書く必要があり、これはAndroid におけるonCreate()メソッドのようなものに当たる。
@WebServlet("/api1")
public class API1 extends HttpServlet {
// GET 処理(GET メソッドで HTTP リクエストが送られてくるたびに実行される)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
doGet()の先頭に書かれた5つの処理
response.setHeader("Cache-Control", "no-cache"); // キャッシュを利用しない
response.setHeader("Pragma", "no-cache"); // キャッシュを利用しない(下位互換性用)
response.setDateHeader("Expires", 0); // キャッシュ有効期限0
response.setCharacterEncoding("UTF-8"); // レスポンス文字コード UTF-8 設定
response.setContentType("application/json"); // レスポンスタイプ application/json 設定
これらは全て処理結果の設定をしている命令になる。
上3つは結果を保存するかしないかの設定であり、今回は全て保存しないという設定をしている。
仮にこれが **設定されていない場合、プログラムを更新しても、以前の結果が返されてしまう **という事が発生する可能性がある。
これらの値はHTTPプロトコルにより決まっている設定値であるため、何が設定できるかはHTTPプロトコルの仕様が書かれているRFC(Request for Comments)を読む必要がある。
(例)
RFC 9110 — HTTP Semantics
https://triple-underscore.github.io/http-semantics-ja.html
4番目の設定値
response.setCharacterEncoding("UTF-8");
これは、返却するデータの文字コードを設定している。(変えたい場合は何でも良い)
5番目の設定値
response.setContentType("application/json");
これは、返却するデータの形式を設定している。
RESTful API では JSON と呼ばれるデータを返却するため 「application/json」 と設定する。
(JSONについては後述する)
説明 RESTにおけるメイン処理
PrintWriter out = response.getWriter(); // レスポンス書き込み用 PrintWriter 取得
out.println("{\"value\": \"こんにちは\"}"); // レスポンス書き込み {"name": "こんにちは"}
out.flush(); // フラッシュ処理(強制送信のようなもの)
out.close(); // PrintWriterのクローズ(これ以降書き込めない)
Servletはこの PrintWriter というクラスに println() で文字列を書き込むだけで、通信相手にデータを送ることができる。
response.getWriter() を使う事で PrintWriter を取得できるが、 response は doGet()メソッドの引数で貰える。
// ↓ ここ
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
}
今回の通信相手には
{"value": "こんにちは"}
このテキストを送っている。 ( { から } までの空白含む18文字)
これが JSON(JavaScript Object Notation) と呼ばれるデータである。
Javaの命令では以下の部分が送信処理になっており
out.println("{\"value\": \"こんにちは\"}");
Stringデータを書き込むだけになっている。
JSONの構造について
{ 項目名 : 値 }
となっており 項目名、値共に自由に設定が出来る。
out.flush(); //強制送信をする命令
この命令は、強制送信の命令になっている。
out.println() を実行すればデータが送信されるのだが、送バッファと呼ばれる容量がいっぱいになるまで送信が溜められてしまう事がある。
flush() 命令はバッファがいっぱいだろうが、なかろうがその時点で強制送信をする命令なので、書き込み処理の最後に必ず記述する。
out.close();
最後に close() 命令だが、これは 書き込みを終了する命令であり、最後の最後に記述する。
throws 命令について
``java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
の末尾である
``` java
throws ServletException, IOException
このメソッド内(今回はdoGet())内で発生する以下の例外(今回はServletException と IOException)を 呼び出し元で try chatch させる という命令になっている。
DB処理などでも try catch を書かなければコンパイルエラーとなってしまうように、PrintWriter を使う時も IOException を catch しなければエラーとなってしまう。