1

这个问题整天困扰着我,我在这里花了很多时间,在谷歌上试图找到正确的答案并尝试了很多不同的修复。

我有一个在这里定义的 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 字符串如下所示: String s1 = "{\"userId\":3, \"ddUserId\":301010651, \"customerCode\":\"QA\", \"customerId\":8}"; 是的,我使用了 Jackson ObjectMapper 工具来验证此代码是否可以正确地从该字符串映射到一个对象,反之亦然。当我查看 POJO 时,它确实实现了 Serializable,并且它确实有一个默认构造函数。

Junit 测试效果很好,并且确实返回了数据:

MockHttpServletRequestBuilder requestBuilder =
        MockMvcRequestBuilders.get("/invoices/searchAndCount").contentType(MediaType.APPLICATION_JSON)
        .content(test);

    this.mockMvc.perform(requestBuilder).andDo(print());

这确实调用了控制器,我可以从输出中看到标头是什么,并且我可以看到我实际上得到了很棒的真实数据。所以我觉得在控制器方面我能做的不多。

对控制器的真正调用来自 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 打开我的网络应用程序。在 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

注意请求头:Accept: 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-services 调用没有创建正确的标题。

更新:我将以下代码添加到 SmartGWT RestDataSource transformRequest 方法:

    Map<String, String> httpHeaders = new HashMap<String, String>();
    httpHeaders.put("Accept", "*/*");
    httpHeaders.put("Content-Type", "application/json");
    dsRequest.setHttpHeaders(httpHeaders);

我可以添加“接受”请求标头,但仍然收到 415 Unsupported Media 错误消息。当我添加“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
4

1 回答 1

2

这花了很多工作,但我终于弄明白了。

动词 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 控制器驻留在同一个 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,效果也很好。

我希望所有这些工作都能为别人带来回报!

于 2013-08-27T18:30:06.460 回答