Tech Sketch Bucket of Technical Chips by TIS Inc.

SAStrutsでJSON形式のデータを返す(検証エラー込み)

Pocket

SAStrutsで実装していたサーバ処理に、RESTfulなAPIを追加する機会がありました。SAStrutsにおいてもJSON形式でレスポンスデータを返すことは簡単に行えますが、ユーザ入力に対する検証処理は別途作りこむ必要があります。
この記事ではその際に行った、SAStrutsが持っている検証処理の仕組みを活かしつつJSON形式でレスポンスデータや検証エラーを返す仕組みを導入する方法をご紹介します。

この方法を使用すると、従来のSAStrutsにおける実装作法はそのままに、JSONデータを返送できる様になります。

SAStrutsでは チュートリアル・アプリケーション が用意されています。チュートリアル・アプリケーションにはさまざまな実装例が含まれていますが、ここではブラウザで入力された2つの数字の和をサーバで計算して返す「足し算」を例に進めていきます。

足し算.png

「足し算」アプリケーションのAction実行メソッドはJSPを返す形で実装されています。

レスポンスを返す(JSP以外の基本形)

JSP以外のデータを返す例は、 SAStrutsのドキュメント にあります。その例を元に「足し算」の実装を書き換えると、以下のようになります。

この実装では、text/plain形式でテキストやHTMLの断片を返すことになります。

レスポンスを返す(JSON形式)

JSON形式でレスポンスを返したい場合、以下のようになります。

responseDataをクライアントへ返したいデータと見立てると、以下のようなJSONデータがクライアントに返送されます。(計算結果が3の場合。)

ただしこのままでは、ブラウザで入力された2つの数字についての検証が行えません。例えば数字以外の入力があると、Integer.valueOf()の箇所でNumberFormatException例外が発生してしまいます。
これを防ぐために実行メソッドの中で入力値の検証を実装する方法もありますが、全てのJSONを返す実行メソッドで検証処理を実装していくのはかなりめんどうです。

もともとSAStrutsには、ActionFormのプロパティに付加されたアノテーションにより入力値の検証を行い、不正な入力があった場合はエラーメッセージを返す処理が用意されています。JSPを返す場合にSAStrutsが担っているこの検証処理を、JSONを返す場合にも利用できるよう改良します。

レスポンスを返す(検証処理を行う)

SAStrutsの検証処理を利用するため、以下のように工夫します。

まず、検証処理を行うために、SAStrutsの仕様に従いActionの実行メソッドの@Executeにinput属性を指定します。これは、検証エラーが発生した際のフォワード先です。フォワード先には、jsp(入力元のjsp)を指定するケースが多いですが、今回は以下のように専用のURL("/ajaxValidateError")を指定します。

合わせて、上述の専用URLに対応したActionクラスと、JSONデータ返送用のインターセプタResponseJsonInterceptorを用意します。それぞれの実装は、以下の通りです。

(1) 検証エラー発生時フォワード用Actionクラス

以下はActionクラスのコードです。
一見すると何もしていないように見えますが、、、実際何もしていません。後程説明しますが、検証エラー発生時にはこのクラスのindex()メソッドに仕掛けられたインターセプタがデータ返送処理を行います。

(2) JSONデータ返送用インターセプタ

続いてインターセプタのコードです。
以下のコードのinvoke()メソッドの中で、'ResponseJsonUtil.getMessages()'という処理を呼び出しています。('ResponseJsonUtil.getMessages()'のコードは、添付するサンプルコードの中に含まれていますのでそちらを参照下さい。)この処理では検証エラーと判定されたプロパティがある場合に、そのプロパティ名とエラーメッセージ(のリスト)をMap>形式で返します。検証エラーが発生すると、SAStrutsではrequestオブジェクトにエラー内容がセットされますので、'ResponseJsonUtil.getMessages()'はrequestオブジェクトからエラー内容を取り出し、Mapにつめなおして返しています。
その他細かい判定処理を除けば、submit2()やsubmit3()と同様に、ResponseUtil.write()メソッドでJSONデータを返送しています。

検証エラーが発生した場合、このコードで返されるデータは、以下のようなJSON形式になります。

「足し算」の例では、arg1やarg2がプロパティ名になります。例えばarg1に数字以外の文字が入力された場合、以下のようなデータが返ります。

(3) customizer.dicon

(1)のindex()メソッドが呼ばれるタイミングで(2)のResponseJsonInterceptorが実行されるように設定を行います。customizer.diconで"actionCustomizer"に"responseJsonInterceptor"を追加します。(下記コード6~8行目)

"responseJsonInterceptor"は、app.diconで以下のように定義しておきます。

以上、(1)~(3)の修正で、検証エラー発生時にもエラー内容がJSON形式でクライアントに送信されます。

なぜうまくいくのか

検証エラーが発生した場合、SAStrutsではエラー内容はrequestオブジェクトに、キーGlobals.ERROR_KEYでセットされます。
続いて@Execute(input = "/ajaxValidateError")の指定で(1)のindex()メソッドに処理がフォワードされます。
index()が呼ばれると、ResponseJsonInterceptorが実行され、このrequestオブジェクトにセットされたエラー内容を、JSON形式に変換して返します。

検証エラー時の処理概要.png

少し改良

実は(3)の設定を行うと、(1)のindex()メソッドだけでなく全ての実行メソッドについてResponseJsonInterceptorが実行されます。
そこで、検証エラーだけでなく通常のレスポンスデータもこのResponseJsonInterceptorで返送するように改良してみます。
submit3()では実行メソッドの中で直接レスポンスデータを返送していましたが、以下のようにレスポンスデータを一旦requestオブジェクトにセットし、これをResponseJsonInterceptorで取り出して返送するようにします。

requestオブジェクトを介したデータの受け渡しも以下のようにResponseJsonUtilに隠蔽しまうことで、コードは更にすっきりします。もとの実装であるsubmit()と比べても、@Executeのinput属性と戻り値に関する書き換えを行うだけで済みます。

ResponseJsonInterceptorのコードは以下のようになります。(下記コード22~24行目を追加)

この改良によって、検証エラーが発生した場合は以下のようなJSONデータが返送され、

正常時には以下のようにレスポンスデータが返送されるようになります。

まとめ

(1)~(3)をフレームワークとして設定しておくことで、実行メソッドの実装は以下のように、JSPを返す場合と比べてわずかな実装の変更でJSONを返すよう切り替えることができ、さらにSAStrutsの持つ検証処理もそのまま利用できます。

また、返送されるデータフォーマットについてもerrorsとresponseDataという決まったキーを持つJSONデータを返すことができます。

もう一歩進める

今回はSAStrutsにおけるJSONデータの送信処理について紹介しましたが、SAStrutsでJSONデータを受け取る方法については、以下の記事で紹介されています。

また、SAStrutsではPUTメソッドやDELETEメソッドを扱えませんが、ActionServletを拡張することでこれらを扱えるようすることが可能です。

これらを組み合わせると、比較的少ないコストでJSONデータの送受信機能をSAStrutsに追加することができ、JSONを用いるクライアント(jQuery.ajax()やBackbone.jsなどを利用したクライアントアプリケーション)との通信も可能となります。
既にSAStrutsで実装された資産があり、且つJSONへの対応が必要になった場合、今回紹介した方法を使ってみては如何でしょうか。

サンプルコードについて

この記事で紹介したソースコードは、 こちら からダウンロードできます。
使用方法については、zipファイル中のReadme.mdファイルを参照して下さい

エンジニア採用中!私たちと一緒に働いてみませんか?