0

いくつかの単体テストで徹底的にテストしたデータベース バックエンドがあります。コントローラーは次のようになります。

@RequestMapping(value = "/create", method = RequestMethod.POST, produces = "application/json", headers = "content-type=application/json")
public @ResponseBody UserDTO createUser(@RequestBody UserDTO user)
{
    UserEntity userEntity = service.add(user);
    return mappingUser(userEntity);
}

単体テストは次のようになります。

 @Test
    public void testCreateUser() throws Exception
    {
        UserDTO userDto = createUserDto();
        String url = BASE_URL + "/rest/users/create";
        UserDTO newUserDto = restTemplate
        .postForObject(url, userDto, UserDTO.class, new Object[]{});
    }

単体テストがうまく機能し、実際の Web サービスが正しく呼び出され、データがデータベースに入れられることを確認しました。

今、私は SmartGWT RestDataSource を使用しています。RestDataSource を正しく構成して、リクエスト本文で新しいユーザーを渡し、新しいオブジェクトを返すようにしています。データを本文の JSON として送信し、この呼び出しから JSON を返したいと考えています。そのため、データソースと一致するようにコントローラー自体を変更する必要があるかもしれません。

以下は、RestDataSource を拡張する AbstractDataSource です。

import java.util.Map;

import com.google.gwt.http.client.URL;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.OperationBinding;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RestDataSource;
import com.smartgwt.client.types.DSOperationType;
import com.smartgwt.client.types.DSProtocol;

public abstract class AbstractRestDataSource extends RestDataSource
{
    public AbstractRestDataSource(String id)
    {
        setID(id);
        setClientOnly(false);

        // set up FETCH to use GET requests
        OperationBinding fetch = new OperationBinding();
        fetch.setOperationType(DSOperationType.FETCH);
        fetch.setDataProtocol(DSProtocol.GETPARAMS);
        DSRequest fetchProps = new DSRequest();
        fetchProps.setHttpMethod("GET");
        fetch.setRequestProperties(fetchProps);

        // set up ADD to use POST requests
        OperationBinding add = new OperationBinding();
        add.setOperationType(DSOperationType.ADD);
        add.setDataProtocol(DSProtocol.POSTMESSAGE);
        DSRequest addProps = new DSRequest();
        addProps.setHttpMethod("POST");
        addProps.setContentType("application/json");
        add.setRequestProperties(addProps);

        // set up UPDATE to use PUT
        OperationBinding update = new OperationBinding();
        update.setOperationType(DSOperationType.UPDATE);
        update.setDataProtocol(DSProtocol.POSTMESSAGE);
        DSRequest updateProps = new DSRequest();
        updateProps.setHttpMethod("PUT");
        update.setRequestProperties(updateProps);

        // set up REMOVE to use DELETE
        OperationBinding remove = new OperationBinding();
        remove.setOperationType(DSOperationType.REMOVE);
        DSRequest removeProps = new DSRequest();
        removeProps.setHttpMethod("DELETE");
        remove.setRequestProperties(removeProps);

        // apply all the operational bindings
        setOperationBindings(fetch, add, update, remove);

        init();
    }

    @Override
    protected Object transformRequest(DSRequest request)
    {
        super.transformRequest(request);

        // now post process the request for our own means
        postProcessTransform(request);

        return request.getData();
    }

    /*
     * Implementers can override this method to create a 
     * different override.
     */
    @SuppressWarnings("rawtypes")
    protected void postProcessTransform(DSRequest request)
    {
        StringBuilder url = new StringBuilder(getServiceRoot());

        Map dataMap = request.getAttributeAsMap("data");
        if (request.getOperationType() == DSOperationType.REMOVE)
        {
            // in case of remove, append the primary key
            url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
        }
        else if (request.getOperationType() == DSOperationType.UPDATE)
        {
            url.append("update");
            appendParameters(url, request);
        }
        else if (request.getOperationType() == DSOperationType.FETCH && dataMap.size() > 0)
        {
            url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
        }
        else if (request.getOperationType() == DSOperationType.ADD)
        {
            url.append("create");
        }

        System.out.println("AbstractRestDataSource: postProcessTransform: url=" + url.toString());
        request.setActionURL(URL.encode(url.toString()));
    }

    /*
     * This simply appends parameters that have changed to the URL
     * so that PUT requests go through successfully. This is usually
     * necessary because when smart GWT updates a row using a form,
     * it sends the data as form parameters. Most servers cannot
     * understand this and will simply disregard the form data
     * sent to the server via PUT. So we need to transform the form
     * data into URL parameters.
     */
    @SuppressWarnings("rawtypes")
    protected void appendParameters(StringBuilder url, DSRequest request)
    {
        Map dataMap = request.getAttributeAsMap("data");
        Record oldValues = request.getOldValues();
        boolean paramsAppended = false;

        if (!dataMap.isEmpty())
        {
            url.append("?");
        }

        for (Object keyObj : dataMap.keySet())
        {
            String key = (String) keyObj;
            if (!dataMap.get(key).equals(oldValues.getAttribute(key)) || isPrimaryKey(key))
            {
                // only append those values that changed or are primary keys
                url.append(key).append('=').append(dataMap.get(key)).append('&');
                paramsAppended = true;
            }
        }

        if (paramsAppended)
        {
            // delete the last '&'
            url.deleteCharAt(url.length() - 1);
        }
    }

    private boolean isPrimaryKey(String property)
    {
        return getPrimaryKeyProperty().equals(property);
    }

    /*
     * The implementer can override this to change the name of the
     * primary key property.
     */
    protected String getPrimaryKeyProperty()
    {
        return "id";
    }

    protected abstract String getServiceRoot();

    protected abstract void init();
}

そして、AbstractRestDataSource を拡張する UserDataSource は次のとおりです。

import java.util.Map;

import com.google.gwt.http.client.URL;
import com.opensource.restful.shared.Constants;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.fields.DataSourceBooleanField;
import com.smartgwt.client.data.fields.DataSourceDateField;
import com.smartgwt.client.data.fields.DataSourceIntegerField;
import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.types.DSDataFormat;
import com.smartgwt.client.types.DSOperationType;

public class UserDataSource extends AbstractRestDataSource
{
    private static UserDataSource instance = null;

    public static UserDataSource getInstance()
    {
        if (instance == null)
        {
            instance = new UserDataSource("restUserDS");
        }

        return instance;
    }

    private UserDataSource(String id)
    {
        super(id);
    }

    private DataSourceIntegerField userIdField;
    private DataSourceBooleanField userActiveField;
    private DataSourceTextField usernameField;
    private DataSourceTextField passwordField;
    private DataSourceTextField firstnameField;
    private DataSourceTextField lastnameField;
    private DataSourceTextField emailField;
    private DataSourceTextField securityQuestion1Field;
    private DataSourceTextField securityAnswer1Field;
    private DataSourceTextField securityQuestion2Field;
    private DataSourceTextField securityAnswer2Field;
    private DataSourceDateField birthdateField;

    private DataSourceIntegerField positionIdField;

    protected void init()
    {
        setDataFormat(DSDataFormat.JSON);
        setJsonRecordXPath("/");

        // set the values for the datasource
        userIdField = new DataSourceIntegerField(Constants.USER_ID, Constants.TITLE_USER_ID);
        userIdField.setPrimaryKey(true);
        userIdField.setCanEdit(false);

        userActiveField = new DataSourceBooleanField(Constants.USER_ACTIVE, Constants.TITLE_USER_ACTIVE);

        usernameField = new DataSourceTextField(Constants.USER_USERNAME, Constants.TITLE_USER_USERNAME);
        passwordField = new DataSourceTextField(Constants.USER_PASSWORD, Constants.TITLE_USER_PASSWORD);

        firstnameField = new DataSourceTextField(Constants.USER_FIRST_NAME, Constants.TITLE_USER_FIRST_NAME);
        lastnameField = new DataSourceTextField(Constants.USER_LAST_NAME, Constants.TITLE_USER_LAST_NAME);

        emailField = new DataSourceTextField(Constants.USER_EMAIL, Constants.TITLE_USER_EMAIL);

        securityQuestion1Field =
            new DataSourceTextField(Constants.USER_SECURITY_QUESTION_1, Constants.TITLE_USER_SECURITY_QUESTION_1);
        securityAnswer1Field =
            new DataSourceTextField(Constants.USER_SECURITY_ANSWER_1, Constants.TITLE_USER_SECURITY_ANSWER_1);
        securityQuestion2Field =
            new DataSourceTextField(Constants.USER_SECURITY_QUESTION_2, Constants.TITLE_USER_SECURITY_QUESTION_2);
        securityAnswer2Field =
            new DataSourceTextField(Constants.USER_SECURITY_ANSWER_2, Constants.TITLE_USER_SECURITY_ANSWER_2);

        birthdateField = new DataSourceDateField(Constants.USER_BIRTHDATE, Constants.TITLE_USER_BIRTHDATE);

        positionIdField = new DataSourceIntegerField(Constants.USER_POSITION_ID, Constants.TITLE_USER_POSITION_ID);
        // positionActiveField = new DataSourceBooleanField(Constants.USER_ACTIVE, Constants.TITLE_USER_ACTIVE);
        // positionCodeField;
        // positionDescriptionField;

        setFields(userIdField, userActiveField, usernameField, passwordField, firstnameField, lastnameField,
            emailField, birthdateField, securityQuestion1Field, securityAnswer1Field, securityQuestion2Field,
            securityAnswer2Field, positionIdField);
    }

    protected String getServiceRoot()
    {
        return "rest/users/";
    }

    protected String getPrimaryKeyProperty()
    {
        return "userId";
    }

    /*
     * Implementers can override this method to create a 
     * different override.
     */
    @SuppressWarnings("rawtypes")
    protected void postProcessTransform(DSRequest request)
    {
        // request.setContentType("application/json");

        StringBuilder url = new StringBuilder(getServiceRoot());

        Map dataMap = request.getAttributeAsMap("data");
        if (request.getOperationType() == DSOperationType.REMOVE)
        {
            // in case of remove, append the primary key
            url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
        }
        else if (request.getOperationType() == DSOperationType.UPDATE)
        {
            url.append("update");
            System.out.println("UserDataSource: postProcessTransform: update: url=" + url.toString());
        }
        else if (request.getOperationType() == DSOperationType.FETCH && dataMap.size() > 0)
        {
            url.append(getPrimaryKeyProperty()).append("/").append(dataMap.get(getPrimaryKeyProperty()));
        }
        else if (request.getOperationType() == DSOperationType.ADD)
        {
            url.append("create");
        }

        System.out.println("UserDataSource: postProcessTransform: url=" + url.toString());
        request.setActionURL(URL.encode(url.toString()));
    }
}

UserDTO を JSON として requestBody に入れる方法がわかれば、すべての問題が解決したと思います。知っておくべき追加情報については、Spring 3.2 と springmvc-servlet.xml ファイルで構成された Jackson Message Converters を使用しています。

ある時点で、すべてのデータが URL に追加されるのを確認しましたが、データがパラメーターとして URL に含まれているのではなく、リクエストの本文に含まれていればよかったと思います。SO、これが可能かどうか、およびその方法を知る必要があります。

助けてくれてありがとう!!!

4

1 に答える 1

0

おそらく、これらの変更をすべて元に戻し、RestDataSource.setDataFormat() を呼び出すだけでリクエスト本文が JSON として渡されるデフォルトの RestDataSource プロトコルを実装することをお勧めします。ドキュメントに JSON メッセージのサンプルがあります。

http://www.smartclient.com/smartgwtee/javadoc/com/smartgwt/client/data/RestDataSource.html

あなたが作成した他の問題の中で:

  1. さまざまな CRUD 操作が個別の URL に送られ、さまざまな HTTP 動詞が使用されるようになったため、単一のキューに結合して一緒に送信することはできなくなりました。つまり、トランザクションで作成操作と更新操作を組み合わせて実行したり、新しい Order をその OrderItem と共に保存したり、データを保存したり、新しい画面への移行に必要な依存データをフェッチしたりするなどの基本的なことは実行できません。

  2. 「フェッチ」は HTTP GET に基づいていると想定していますが、これにはネストされた基準構造 (AdvancedCriteria) を URL パラメーターにエンコードする必要があり、URL の最大長に簡単に達する可能性があります。

これらの理由やその他の理由から、生成された Java サービスのほとんどは最新の UI のニーズを満たしていないため、自動生成アプローチは使用しないでください。FAQ のより深い説明:

http://forums.smartclient.com/showthread.php?t=8159#aExistingRest

于 2013-04-03T01:37:28.010 に答える