DEV Community

KOGA Mitsuhiro
KOGA Mitsuhiro

Posted on • Originally published at qiita.com

SAStrutsとJSON

今更感がありますが、SAStrutsでJSONを処理できるようにしてみました。

JSONリクエスト

SAStrutsはS2RequestProcessor.javaでHTTPリクエストをアクションフォームにコピーしているので、JSONリクエストの処理はその直前で行います。
JSONデータの読み込みはJacksonを使いました。

package sample.sastruts.json.action;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.seasar.framework.beans.util.Beans;
import org.seasar.framework.util.ReaderUtil;
import org.seasar.struts.action.S2RequestProcessor;
import org.seasar.struts.util.S2ActionMappingUtil;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class S2JSONRequestProcessor extends S2RequestProcessor {

    @Override
    protected void processPopulate(HttpServletRequest request,
            HttpServletResponse response, ActionForm form, ActionMapping mapping)
            throws ServletException {

        if (form == null) {
            return;
        }

        String contentType = request.getContentType();
        String method = request.getMethod();
        if (contentType != null && contentType.startsWith("application/json")
                && "POST".equalsIgnoreCase(method)) {

            form.setServlet(servlet);
            form.setMultipartRequestHandler(null);
            processExecuteConfig(request, response, mapping);
            form.reset(mapping, request);

            Object actionForm = S2ActionMappingUtil.getActionMapping()
                    .getActionForm();
            try {
                ObjectMapper  mapper = new ObjectMapper();
                mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

                String postBody = ReaderUtil.readText(request.getReader());
                Object value = mapper.readValue(postBody, actionForm.getClass());

                Beans.copy(value, actionForm).execute();

            } catch (IOException e) {
                log.error(e.getMessage(), e);
                throw new ServletException(e.getMessage(), e);
            }

        } else {

            super.processPopulate(request, response, form, mapping);

        }
    }

}

一番キモとなっているのは以下の部分です。
JSONリクエストをactionForm.getClass()型としてvalueに読み込んでいるので、actionFormに値をコピーできます。

ObjectMapper  mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

String postBody = ReaderUtil.readText(request.getReader());
Object value = mapper.readValue(postBody, actionForm.getClass());

Beans.copy(value, actionForm).execute();

このクラスをstruts-config.xmlprocessorClassに設定すると利用できます。

<controller
    maxFileSize="1024K"
    bufferSize="1024"
    processorClass="sample.sastruts.json.action.S2JSONRequestProcessor"
    multipartClass="org.seasar.struts.upload.S2MultipartRequestHandler"/>

JSONレスポンス

SAStrutsのアクションは遷移先のパスを戻り値に書いてJSP等と連携しますがnullを返却すると遷移しません。これを利用しつつアクションからHTTPレスポンスに直接JSONを書き出します。
JavaオブジェクトからJSONの変換もJacksonを使っています。

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.util.ResponseUtil;

public class XXXAction {
    @Execute(validator = false)
    public String xxx() throws JsonProcessingException {
        String[] result = {"foo", "bar"};
        ObjectMapper mapper = new ObjectMapper();
        ResponseUtil.write(mapper.writeValueAsString(result), "application/json", "UTF-8");

        return null;
    }
}

追記

スマートなJSONレスポンスの実装方法の解説がありましたので、そちらもご覧下さい。
SAStrutsでJSON形式のデータを返す(検証エラー込み)

JSONサンプルアプリ

SAStrutsの足し算チュートリアルでJSONを利用するように修正したサンプルアプリを作りました。
こちらでは更にBean Validationをバリデータに利用しています。

https://bitbucket.org/shiena/sample-sastruts-json-webapps

Top comments (0)