简单 restful JSON POST,java 作为服务器,jquery 作为客户端

Simple restful JSON POST with java as server and jquery as client

在我问我的问题之前,我必须说我已经阅读了 20 多篇关于这个问题的问题和文章,其中 none 可以解决它。

我的问题是我在 java 中有一个 restful 服务器,如下所示:

@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(@RequestBody final String stringRequest, final HttpServletResponse response)
{
    try
    {
        final ObjectMapper objectMapper = new ObjectMapper();
        final JsonNode jsonRequest = objectMapper.readValue(stringRequest, JsonNode.class);

        // ...
        // some processings here to create the result
        // ....

        final ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result);
        // Flush the result
        outputStream.flush();
    }
    catch (final Exception exception)
    {
        LOG.debug("Exception Thrown [downloadByCode]", exception);
    }
}

而且我尝试了不同的方法来使用 jquery 将 json 发送到此服务器(但它们都会产生错误):

$.ajax({
   url:"/downloadByCode",
   type:"POST",
   data: JSON.stringify({"name":"value"}) });

415 "errors message" : "Content type 'application/x-www-form urlencoded;charset=UTF-8' not supported", "type" : "HttpMediaTypeNotSupportedError"

所以我尝试通过添加 contentType 来修复它:

$.ajax({
   url:"/downloadByCode",
   contentType:"application/json",
   type:"POST",
   data: JSON.stringify({"name":"value"}) });

400 "errors message" : "Could not instantiate JAXBContext for class [class java.lang.String]: null; nested exception is javax.xml.bind.JAXBException\n - with linked exception:\n[java.lang.NullPointerException", "type" :"HttpMessageConversionError"

我试图直接发送 json 对象而不是 JSON.stringify,它给出了相同的 400 错误。

我尝试向@requestMapping 添加不同的消费,但仍然没有成功。

我试图定义我自己的 class 而不是 JsonNode 但它没有改变任何东西。

有什么想法吗?

尝试@RequestBody final Map<String, String> stringRequest

您还需要在 @RequestMapping 上使用 consumes = "application/json",因为您在 AJAX 调用中有它

如果 spring 不喜欢您发送 ajax 的格式,您将获得 400 - 我过去在这方面遇到过很多麻烦,现在似乎更好除非必要,否则忽略 header 类型和内容类型

您可以尝试将响应作为 ResponseEntity 发回,而不是直接使用 HttpServletResponse。我的直觉是第二个参数,即 HttpServletRequest 参数,是导致问题的原因。我从来没有用过那个。我总是使用 spring mvc api 发回我的回复。

使用 Jersey api 你可以尝试: @POST public void downloadByCode(String stringRequest)

我认为您会在 stringRequest 中找到 post 的正文。

删除 downloadByCode 方法中的 @ResponseBody

将您的方法 downloadByCode() return 类型更改为 String,然后 return String

响应主体会自动将returned String 转换为JSON,然后适当地使用数据

我不太熟悉 java,但据我所知,您的 java 代码一定是这样的。

public class downloadByCode{
  @GET
  @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
  public Response downloadByCode(@QueryParam("paramater1") final String parameter 1, @Context HttpServletRequest httpRequest) {

如果这没有帮助,您可以将您的代码保存在某个地方并共享它。

您可以将请求正文作为字符串,使用 org.springframework.http.HttpEntity<String> 作为请求类型,这里是您的代码作为基础的示例:

@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public void downloadByCode(final HttpEntity<String> request, final HttpServletResponse response)
{
    try
    {
        final ObjectMapper objectMapper = new ObjectMapper();
        final JsonNode jsonRequest = objectMapper.readValue(request.getBody(), JsonNode.class);

        // ...
        // some processings here to create the result
        // ....

        final ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result);
        // Flush the result
        outputStream.flush();
    }
    catch (final Exception exception)
    {
        LOG.debug("Exception Thrown [downloadByCode]", exception);
    }
}

但是,如果您打算将 return 结果作为字符串值,那么将字符串也用作 return 类型可能会更好,如下所示:

@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public String downloadByCode(HttpEntity<String> request) {
    String requestBody = request.getBody();
    String result;

    // ...
    // some processings here to create the result text
    // ....

    return result;
}

我使用 Spring Boot with usage of proposed solutions using HttpEntity and also additional example of usage POJO, to run application you need to have Maven 和 JDK >= 1.7 制作了简单的应用程序。

#clonning repository with sample
git clone git@github.com:mind-blowing/samples.git

#change current folder to sample application root
cd samples/spring-boot/rest-handler-for-plain-text

#running application using maven spring-boot plugin
mvn spring-boot:run

应用程序启动后,您可以打开 http://localhost:8080,您将看到 html 页面,其中简单地使用 JQuery 发送 POST 请求,请求文本和响应将在 html 页面上可见,在控制器中我添加了两个处理程序,第一个使用 HttpEntity,第二个使用 POJO。

控制器:SampleRestController.java

HTML 页面:index.html

项目:https://github.com/mind-blowing/samples/tree/master/spring-boot/rest-handler-for-plain-text

请尝试创建新的 class :

public class InputData{
   private String name;
   public String getName(){
      return name;
   }
   public void setName(String name){
      this.name = name;
   }
}

然后

public void downloadByCode(@RequestBody InputData stringRequest, final HttpServletResponse response)

$.ajax({
   url:"/downloadByCode",
   contentType:"application/json",
   type:"POST",
   data: JSON.stringify({"name":"value"}) });

查看您的错误,很明显您在 spring 配置中配置了 'Jaxb2RootElementHttpMessageConverter' 或类似的 XML 转换器。由于您已经注册了一个 XML 转换器,@RequestBody 和 @ResponseBody 将基于已注册的消息转换器工作。

因此,要解决您的问题,请使用 JSON 消息转换器,例如 'MappingJacksonHttpMessageConverter'。一旦你注册了一个 JSON 消息转换器,创建一个 bean class 来保存你的 json 数据并将它与 RequestBody 一起使用,如下所示:

// It has to meet the json structure you are mapping it with
public class YourInputData {
    //properties with getters and setters
}

更新 1:

由于您定义了多个消息转换器,Spring 尝试使用默认情况下可用的第一个。为了使用特定的消息转换器(在本例中为 Jackson 转换器),您应该从客户端指定 'Accept' header,如下所示:

$.ajax({     
          headers: {          
                 "Accept" : "application/json; charset=utf-8",         
                "Content-Type": "application/json; charset=utf-8"   
  }     
  data: "data",    
  success : function(response) {  
       ...  
   } })

首先,如果你使用的是 maven,你应该为 jackson 添加依赖项

 <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.4.1</version>
    </dependency>

或者你可以下载jar包放到我们项目的class路径下(你也可以用其他的mapper)

那么您应该创建一个模型或 DTO class,您可以在其中映射您的 json

 public class Data{
     private String name;

     pubilc Data(){}

    //getter and setter

 }

然后你控制器

@RequestMapping (value = "/downloadByCode", method = RequestMethod.POST)
@ResponseBody
public Data downloadByCode(@RequestBody final Data data, final HttpServletResponse response)
{
//your code
    return data;
}

AJAX 通话

$.ajax({
   url:"/downloadByCode",
   contentType:"application/json",
   type:"POST",
   data: JSON.stringify({"name":"value"}) });

(可选)您可以通过如下定义 bean 告诉对象映射器不要在缺少属性时失败来覆盖行为:

 @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setObjectMapper(new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false));
        return converter;
    }

http://websystique.com/springmvc/spring-mvc-requestbody-responsebody-example/

最后的答案是这个问题中许多answers/comments的组合,我将在这里总结它们:

1- 你必须确保在你的 spring 配置中有一个合适的 json 转换器,例如 MappingJacksonHttpMessageConverter (感谢@java Anto)

2- 您必须创建一个与您的 json 对象具有相同结构的 POJO class(参见@Vinh Vo 的回答)

3- 你的 POJO class 不能是内联的 class 除非它是静态的 class。这意味着它应该有自己的 java 文件或者它应该是静态的。 (感谢@NTyler)

4- 如果您在对象映射器中适当地设置它,您的 POJO class 可能会遗漏部分 json 对象(参见@Aman Tuladhar 的回答)

5- 您的 ajax 调用需要 contentType:"application/json",您应该使用 JSON.stringify

发送数据

这是完美运行的最终代码:

public static class InputData
{
    private String name

    public String getName()
    {
        return name;
    }

    public void setName(final String name
    {
        this.name = name;
    }
}

@RequestMapping(value = "/downloadByCode", method = RequestMethod.POST)

@ResponseBody
public void downloadByCode(@RequestBody final InputData request, final HttpServletResponse response)
{
    try
    {
        String codes = request.getName();

        // ...
        // some processings here to create the result
        // ....

        final ServletOutputStream outputStream = response.getOutputStream();
        outputStream.write(result);
        // Flush the result
        outputStream.flush();
    }
    catch (final Exception exception)
    {
        LOG.debug("Exception Thrown [downloadByCode]", exception);
    }
}

这是 jquery Ajax 请求:

$.ajax({
   url:"/downloadByCode",
   contentType:"application/json",
   type:"POST",
   data: JSON.stringify({"name":"value"}) });