我有一个数据库后端,我已经通过几个单元测试对其进行了彻底的测试。控制器如下所示:
@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 中,而是在请求正文中。所以,我需要知道这是否可能,以及如何去做。
谢谢你的帮助!!!