这个问题整天困扰着我,我在这里花了很多时间,在Google上试图找到正确的答案并尝试许多不同的解决方法。
我有一个在这里定义的Spring MVC控制器:
@RequestMapping(value = "/searchAndCount", method = RequestMethod.GET, produces = "application/json", headers =
{ "Accept=application/json", "Content-Type=application/json" }, consumes = "application/json")
public @ResponseBody
RequestResults<?> searchAndCount(@RequestBody SearchInvoiceDTO searchInvoiceDto)
{
RequestResults<?> requestResults = invoiceApprovalService.searchAndCount(searchInvoiceDto);
return requestResults;
}
我知道大多数情况下,简单的参数都可以发送回去,但是在这种情况下,我发现最好将所有搜索条件放在一个对象中并发送过来。这就是为什么我要执行@RequestBody。
根据以前的修复,我确保它具有接受JSON输出可能需要的两个标头。
JSON字符串如下所示:字符串s1 =“ {\” userId \“:3,\” ddUserId \“:301010651,\” customerCode \“:\” QA \“,\” customerId \“:8}”;是的,我已使用Jackson的ObjectMapper工具验证此代码将正确地从此String映射到Object,反之亦然。当我查看POJO时,它确实实现了Serializable,并且确实具有默认构造函数。
Junit测试非常棒,并且确实返回了数据:
MockHttpServletRequestBuilder requestBuilder =
MockMvcRequestBuilders.get("/invoices/searchAndCount").contentType(MediaType.APPLICATION_JSON)
.content(test);
this.mockMvc.perform(requestBuilder).andDo(print());
这确实调用了Controller,从输出中可以看到标头是什么,并且可以看到我实际上返回了很棒的真实数据。因此,我觉得从他的控制者那边我可以做的不多。
对控制器的真正调用来自SmartGWT RestDataSource。
RequestMethod在数据源中定义,这是init方法:
private InvoiceDataSource(String id)
{
setID(id);
setClientOnly(false);
// set up FETCH to use GET requests
OperationBinding fetch = new OperationBinding();
fetch.setOperationType(DSOperationType.FETCH);
fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
fetch.setDataFormat(DSDataFormat.JSON);
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");
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");
// updateProps.setContentType("application/json");
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();
}
[Fetch设置为POSTMESSAGE,这似乎是使用transformReponse传递数据的最佳方法。
@Override
protected Object transformRequest(DSRequest dsRequest)
{
// gets the correct URL - (web-app-root)/rest/invoices/searchAndCount
postProcessTransform(dsRequest);
System.out.println("InvoiceDataSource: transformRequest: START");
dsRequest.setContentType("application/json");
JavaScriptObject jso = dsRequest.getData();
// setting more headers, but this doesn't seem to change anything
dsRequest.setAttribute("Access-Control-Allow-Origin", "*");
dsRequest.setAttribute("Content-Type", "application/json");
dsRequest.setAttribute("Accept", "application/json");
String s1 = JSON.encode(jso);
System.out.println("InvoiceDataSource: transformRequest: FINISH: s1=" + s1);
return s1;
}
由于我知道他有正确的URL,所以我也吐出来变量“ s1”也具有正确的JSON数据,我再次测试了该JSON以确保它能正确命中控制器。
我也确实有pom.xml文件中定义的Jackson依赖项。我还在springmvc-servlet.xml文件中设置了消息转换器。如果这些都不正确,则单元测试将无法进行。但是,如果您需要查看pom.xml文件或springmvc-servlet.xml文件,请告诉我。
我整天都在研究和尝试很多东西,到目前为止……没有运气。希望我提供了足够的信息,但是如果您需要更多信息,请告诉我。最终,我希望可以对SmartGWT RestDataSource进行调整,以将正确的数据传递到此控制器,以实际从中获取数据。
更新:当我在Eclipse中使用Jetty运行此程序时,我正在使用Firefox 23.0.1打开我的Web应用程序。在Eclipse的控制台中,可以看到以下内容:
[WARN] 415 - GET /rest/invoices/searchAndCount (127.0.0.1) 1440 bytes
Request headers
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Cookie: GLog=%7B%0D%20%20%20%20left%3A22%2C%20%0D%20%20%20%20top%3A11%2C%20%0D%20%20%20%20width%3A705%2C%20%0D%20%20%20%20height%3A855%2C%20%0D%20%20%20%20priorityDefaults%3A%7B%0D%20%20%20%20%20%20%20%20Log%3A4%0D%20%20%20%20%7D%2C%20%0D%20%20%20%20defaultPriority%3A3%2C%20%0D%20%20%20%20trackRPC%3Atrue%0D%7D
Connection: keep-alive
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
Response headers
Content-Type: text/html; charset=iso-8859-1
Content-Length: 1440
Accept: application/json
注意,Request标头:接受:text / html,application / xhtml + xml,application / xml; q = 0.9,/; q = 0.8不显示application / json另外,请求标头:“ Content-Type”不存在
当我使用Chrome时,结果是:
[WARN] 415 - GET /rest/invoices/searchAndCount (127.0.0.1) 1440 bytes
Request headers
Host: 127.0.0.1:8888
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.57 Safari/537.36
DNT: 1
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: max-age=0
Response headers
Content-Type: text/html; charset=iso-8859-1
Content-Length: 1440
Accept: application/json
当我从JUnit测试运行时,总是存在“ Content-Type:application / json”。因此,似乎虽然我告诉SmartGWT RestDataSource我在多个地方都使用JSON ...但是Web服务调用并未创建正确的标头。
更新:我将以下代码添加到SmartGWT RestDataSource transformRequest方法中:
Map<String, String> httpHeaders = new HashMap<String, String>();
httpHeaders.put("Accept", "*/*");
httpHeaders.put("Content-Type", "application/json");
dsRequest.setHttpHeaders(httpHeaders);
我可以添加“接受”请求标头,但仍然收到415不支持的媒体错误消息。当我添加“ Content-Type”请求标头时,会收到400 BAD REQUEST错误消息。
我现在在控制台中得到这个:
[WARN] 400 - GET /rest/invoices/searchAndCount (127.0.0.1) 1418 bytes
Request headers
Host: 127.0.0.1:8888
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
If-Modified-Since: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: application/json
Response headers
Content-Type: text/html; charset=iso-8859-1
Content-Length: 1418
[这花了很多工作,但我终于想通了。
动词GET不能满足我的需要...我是个白痴。通过将我的参数作为对象发送到请求数据中,可以使GET正常工作。因此,让我展示一下为完成这项工作而必须更改的代码。
SmartGWT RestDataSource,我更改了;fetchProps.setHttpMethod(“ GET”);到fetchProps.setHttpMethod(“ POST”);我仍然保留:fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
// set up FETCH to use GET requests
OperationBinding fetch = new OperationBinding();
fetch.setOperationType(DSOperationType.FETCH);
fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
fetch.setDataFormat(DSDataFormat.JSON);
// ===========================================
DSRequest fetchProps = new DSRequest();
fetchProps.setHttpMethod("POST");
fetchProps.setContentType("application/json");
fetch.setRequestProperties(fetchProps);
同样也在RestDataSource的“ transformRequest”方法中添加:
Map<String, String> httpHeaders = new HashMap<String, String>();
httpHeaders.put("Content-Type", "application/json");
httpHeaders.put("Accept", "application/json");
dsRequest.setHttpHeaders(httpHeaders);
这可以确保无论我使用的是哪种浏览器,都手动设置了这两个标头。
Spring MVC Controller驻留在同一个Web应用程序中,因此,在我可以对其进行测试之前,这可以避免任何SOP跨站点域问题。同时,我控件的标题如下:
@RequestMapping(value = "/searchAndCount", method = RequestMethod.POST, headers =
{ "Accept=application/json", "Content-Type=application/json" })
public @ResponseBody
ArrayList<?> searchAndCountPOST(@RequestBody SearchInvoiceDTO searchInvoiceDto)
这项工作很受欢迎,它返回了我的数据。我原来的单元测试是在做一个MockMVc.get,并且一直有效。它必须已经识别出经过的数据,并将GET更改为POST才能正常工作。我的单元测试现在已更改为POST,并且效果也很好。
我希望所有这些工作都能为别人带来回报!