前回までで作成したアプリケーションを Customer エンティティの CRUD 操作をできるようにしていきます。
CustomerResource の変更
前回作成した CustomerResource は以下の内容でした。
@Path("customers") public class CustomerResource { @GET @Path("{id}") @Produces({MediaType.APPLICATION_JSON}) public Customer get(@PathParam("id") Long id) { return Ebean.find(Customer.class, id); } @POST @Consumes({MediaType.APPLICATION_JSON}) public Response createCustomer(Customer customer) { Ebean.save(customer); return Response.created( URI.create("/customers/" + customer.getId())).build(); } }
この CustomerResource に更新と削除のメソッドを追加していきます。
更新は HTTP PUT にて受け付けることにします。
@PUT @Path("{id}") @Consumes({MediaType.APPLICATION_JSON}) public Response update(Customer customer) { Customer current = Ebean.find(Customer.class, customer.getId()); if (current == null) throw new WebApplicationException(Response.Status.NOT_FOUND); current.setFirstName(customer.getFirstName()); current.setLastName(customer.getLastName()); current.setAddress(customer.getAddress()); Ebean.update(current); return Response.noContent().build(); }
PUT にてリソースが更新された場合 Response.ok()
で 200、メッセージボディにメッセージを含めることもできますが、ここでは 204 を返却するようにしました。
続いて同様に削除処理は HTTP DELETE にて受け付けます。
@DELETE @Path("{id}") public Response delete(@PathParam("id") Long id) { int count = Ebean.delete(Customer.class, id); if (count != 1) throw new WebApplicationException(Response.Status.NOT_FOUND); return Response.noContent().build(); }
こちらも同様で 204 を返却するようにしています。
静的コンテンツのハンドラ追加
コマンドラインから curl でリクエストするのではなく、HTML 画面からリクエストできるようにしていきます。
Grizzly に HttpHandler を追加して、静的コンテンツを扱えるようにしましょう。
CLStaticHttpHandler
という出来合いのハンドラがあるため、静的コンテンツの格納場所とパスを指定して登録します。
public static void main(String[] args) throws IOException { setupEbean(); final HttpServer server = GrizzlyHttpServerFactory.createHttpServer( BASE_URI, ResourceConfig.forApplicationClass(RsResourceConfig.class), false); // static assets server.getServerConfiguration().addHttpHandler( new CLStaticHttpHandler(Main.class.getClassLoader(), "/assets/"), "/static"); server.start(); Runtime.getRuntime().addShutdownHook(new Thread(server::shutdownNow)); openBrowser(); log.info("Start grizzly. Press any key to exit."); System.in.read(); System.exit(0); }
クラスローダが見つけられる /assets/
配下を静的コンテンツの格納場所として指定しています。
また、リスエストは /static
というパスをこのハンドラの対象として指定しています。
静的コンテンツとして resources/assets/index.html
を作成しましょう。
Bootstrap の雛形として以下とします。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <title>Bootstrap 101 Template</title> <!-- Bootstrap --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous"> <link href="main.css" rel="stylesheet"> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!-- WARNING: Respond.js doesn't work if you view the page via file:// --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <h2>Hello</h2> </div> <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> <!-- Include all compiled plugins (below), or include individual files as needed --> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script> </body> </html>
同じ場所に main.css
を作ります。
.container { width: auto; padding: 20px; }
リクエスト処理
作成した resources/assets/index.html
の container 以下にリクエスト発行処理を埋めていきます。
JSはライブラリ使わずに vanilla で行きます。
最初は POST 処理です。
<h2>Create Customer</h2> <div class="row"> <div class="col-xs-8"> <textarea id="idPostRequestResult" class="form-control" rows="3">{"firstName":"Michael","lastName":" Stipe","address":{"street":"1016","city":"Hollywood","state":"CA","zip":"90038","country":"US"}}</textarea> </div> </div> <div class="row"> <div class="col-xs-8"> <button type="button" id="idPostRequestButton" class="btn btn-default">POST</button> <font id="idPostResCode" color="red"></font> </div> </div> <script> document.getElementById("idPostRequestButton").addEventListener("click", function(){ var request = new XMLHttpRequest(); request.open('POST', '/customers', true); request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); request.onload = function() { document.getElementById("idPostResCode").textContent = request.status + "[" + request.getResponseHeader("Location")+ "]"; }; request.send(document.getElementById("idPostRequestResult").value); }); </script>
テキストエリアのJSONを POST リクエストするようにしています。
続いて GET と PUT 処理。
<h2>Get Customer & Put Customer</h2> <div class="row"> <div class="col-xs-2"> <input type="text" id="idGetPutRequestId" class="form-control" value="1" placeholder="ID"> </div> <div class="col-xs-8"> <button type="button" id="idGetRequestButton" class="btn btn-default">GET</button> <button type="button" id="idPutRequestButton" class="btn btn-default">PUT</button> <font id="idGetPutResCode" color="red"></font> </div> </div> <div class="row"> <div class="col-xs-8"> <textarea id="idGetRequestResult" class="form-control" rows="3"></textarea> </div> </div> <script> document.getElementById("idGetRequestButton").addEventListener("click", function(){ var request = new XMLHttpRequest(); var path = '/customers/' + document.getElementById("idGetPutRequestId").value request.open('GET', path, true); request.onload = function() { document.getElementById("idGetPutResCode").textContent = request.status; if (request.status >= 200 && request.status < 400) { document.getElementById("idGetRequestResult").value = request.responseText; } }; request.send(); }); document.getElementById("idPutRequestButton").addEventListener("click", function(){ var request = new XMLHttpRequest(); var path = '/customers/' + document.getElementById("idGetPutRequestId").value request.open('PUT', path, true); request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); request.onload = function() { document.getElementById("idGetPutResCode").textContent = request.status; }; request.send(document.getElementById("idGetRequestResult").value); }); </script>
最後に DELETE 処理。
<h2>Delete Customer</h2> <div class="row"> <div class="col-xs-2"> <input type="text" id="idDeleteRequestId" class="form-control" value="1" placeholder="ID"> </div> <div class="col-xs-8"> <button type="button" id="idDeleteRequestButton" class="btn btn-default">GET</button> <font id="idDeleteResCode" color="red"></font> </div> </div> <script> document.getElementById("idDeleteRequestButton").addEventListener("click", function(){ var request = new XMLHttpRequest(); var path = '/customers/' + document.getElementById("idDeleteRequestId").value request.open('DELETE', path, true); request.onload = function() { document.getElementById("idDeleteResCode").textContent = request.status; }; request.send(); }); </script>
いずれもボタン押下のイベントで XMLHttpRequest でリクエスト飛ばしているだけです。
実行
前回までの Index リソースにアクセスした場合に、作成した index.html
にリダイレクトするように処理を変更します。
@Path("/") public class Index { private static Logger log = LoggerFactory.getLogger(Index.class); @GET public Response hello() { return Response.seeOther( UriBuilder.fromPath("/static/index.html").build() ).build(); } }
では実行してみましょう。
./gradlew run
POST ボタン押下すると 201 が返却され登録が行われているようです。
GET ボタン押下すると id が採番されて登録した内容が取得できています。
GETで取得したJSONを編集して PUT ボタン押下すると 204 となり更新が行われました。
ボタン名が間違っていますが、最後に id を指定して DELETEすると 204となり削除が行われます。
以上簡単ですが、JAX-RS からの CRUD 操作を見てみました。
ここまでのソースはGithubを参照してください。