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 消息转换器。

在某一时刻,我确实看到所有数据都附加到了 URL 中,但我更希望数据不是作为参数在 URL 中,而是在请求正文中。所以,我需要知道这是否可能,以及如何去做。

谢谢你的帮助!!!

4

1 回答 1

0

您可能想要撤消所有这些修改并只实现默认的 RestDataSource 协议,如果您只是调用 RestDataSource.setDataFormat(),该协议已经将请求正文作为 JSON 传递。文档中有示例 JSON 消息:

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

在您创建的其他问题中:

  1. 不同的 CRUD 操作现在转到不同的 URL 并使用不同的 HTTP 动词,因此它们不能再组合成一个队列并一起发送。这意味着您不能做一些基本的事情,例如在事务中同时执行创建和更新操作、保存新订单及其 OrderItems 或保存数据并获取转换到新屏幕所需的相关数据。

  2. 您假设“获取”将基于 HTTP GET,但这需要将嵌套标准结构 (AdvancedCriteria) 笨拙地编码为 URL 参数,这很容易达到最大 URL 长度

由于这些和其他原因,大多数生成的 Java 服务不能满足现代 UI 的需求,因此不应使用自动生成方法。常见问题解答中的更深入解释:

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

于 2013-04-03T01:37:28.010 回答