RESTとServlet その2
突然ですが、昨年に書いた↓の日記の続きです。
http://d.hatena.ne.jp/da-yoshi/20061115/1163545695
自分はRailsの簡単さとかには正直あまり興味が無いのですが、1.2で目指されている「RESTfulなWebアプリケーションフレームワーク」という部分にもの凄く惹かれています。この機能の詳細を知る為にRailsを学びたいと思ってます。ただ、自分が今までやってきたJavaにはHttpServletという古くて枯れたフレームワークがあります。Railsに行く前に、もう一度この慣れ親しんだServletでRESTを実現できないか考えてみたい・・・ということを、ことあるごとに思っていました。
・・・で、こんなサンプルを書いてみました。
/** * */ package test; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class TestServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 5222793251610509039L; /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doDelete(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("DELETE"); execute(request, response); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("GET"); execute(request, response); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("POST"); execute(request, response); } /* (non-Javadoc) * @see javax.servlet.http.HttpServlet#doPut(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("PUT"); execute(request, response); } private void execute(HttpServletRequest request, HttpServletResponse response) throws IOException { PrintWriter writer = response.getWriter(); BufferedReader reader = request.getReader(); try { String str; while ((str = reader.readLine()) != null) { writer.println(str); } } finally { reader.close(); } } }
単純に、送られてきたRequestのBODYをReaderで受け取って、Writerで返すだけのServletです。
これをweb.xmlで登録。
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4"> <display-name>test</display-name> <servlet> <servlet-name>TestServlet</servlet-name> <servlet-class>test.TestServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>TestServlet</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping> </web-app>
そして以下のHTMLでアクセスします。
<html> <head> <script type="text/javascript"> var req; function createXMLHttpRequest() { try { return this.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); } } function execute() { var select = document.getElementById("meth"); var meth = select.options[select.selectedIndex].value; req = createXMLHttpRequest(); var url = "/testWeb/test"; req.onreadystatechange = readyStateChangeHandler; req.open(meth, url, true); req.send("Hello World!"); } function readyStateChangeHandler() { if (req.readyState == 4) { if (req.status == 200) { var data = req.responseText; alert(data); } } } </script> </head> <body> <form action="" id="form"> <select id="meth"> <option value="GET">GET</option> <option value="POST">POST</option> <option value="PUT">PUT</option> <option value="DELETE">DELETE</option> </select> <input type="button" value="送信" onclick="execute()"> </form> </body> </html>
結果は・・・GET以外はalertで「Hello World!」が表示されました(GETは空白のALERT)。GETは普通にパラメータ使えばいいとして・・・そうか・・・PUTでどうやってパラメータ受け取ればいいんだろう? とか馬鹿なことを考えていましたが、Readerで受け取りゃよかったのですね・・・
まぁ全然RESTでも無くなんでもない、単にメソッドの動作を確認しただけの例なんですが・・・これだけでも、AjaxとServletの組み合わせで、RESTfulなアプリを組める可能性は十分にありそうな気がしました。Reader・Writerでやりとり出来るってことは、JSONを使えばAjaxのリッチクライアントとServletで複雑なやりとりだって出来てしまうってことですし(JDK6使えばJSONからJavaBean変換だって出来そうな気がするし)。後は、RESTで最も重要な、URLを解析するサーバサイド側の仕掛けだけですね。調べてませんが、おそらくRails1.2はそこまで含めてフルのRESTfulなWeb「アプリケーション」環境を提供しているんじゃないかと思います。そこらへんは是非勉強して調べてみたい。
・・・そういえば・・・すっかり過去のものとなってしまった、InvokerServletって、Servletの自動マッピング用途に使えたりはしないかな? 今やStrutsのActionもJSFのManagedBeanも規約で自動登録する時代ですから、「Servletはweb.xmlでマッピングしなきゃならん」ってのも過去の話のような気がしないでもありません。
あとは、サーブレットコンテナがServletを生成する仕組みに、DIをかませることが出来れば完璧なんですが・・・ここら辺も、InvokerServlet調べたら何かヒントがあるかも?
・・・というわけで、次はいつになるかわかりませんが(汗)、TomcatのInvokerServletを調べてみたいと思ってます。