【问题标题】:Simple restful JSON POST with java as server and jquery as clientjava作为服务器,jquery作为客户端的简单的RESTful JSON POST
【发布时间】:2016-03-30 10:36:18
【问题描述】:

在我问我的问题之前,我必须说我已经阅读了 20 多个关于这个问题的问题和文章,但没有一个可以解决它。

我的问题是我在 java 中有一个这样的宁静服务器:

@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 "错误信息" : "内容类型 '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“错误消息”:“无法为类实例化 JAXBContext [类java.lang.String]:空;嵌套异常是 javax.xml.bind.JAXBException\n - 带有链接 异常:\n[java.lang.NullPointerException", "type" :"HttpMessageConversionError"

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

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

我尝试定义自己的类而不是 JsonNode,但它并没有改变任何东西。

有什么想法吗?

【问题讨论】:

  • 您是否尝试过将 @RequestBody 参数类型更改为 Map 或创建具有单个“名称”属性的类并将其用作类型(如 Vinh Vo 所建议的那样)?
  • @NTyler,我从未尝试过 Map,我现在要尝试。谢谢你的建议
  • Vinh Vo 方法会产生以下错误:Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported.
  • 您可能需要按照 Vinh Vo 的建议使用 POJO 类。将类声明为静态或将其放在单独的文件中,您应该已准备就绪。
  • 赏金应该去Vinh Vo,他的回答是正确的,而且是第一位的。该类只需要是静态的,因为您将其设置为内部类,如果您在自己的文件中创建该类,则不需要静态修饰符。

标签: java jquery json ajax restful-architecture


【解决方案1】:

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

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

如果 spring 不喜欢您发送 ajax 的格式,您将获得 400 - 我过去遇到过很多麻烦,除非必要,否则最好忽略标题类型和内容类型

p>

【讨论】:

  • 感谢您的回答。我已将我的请求正文更改为:public void downloadOrdersByCode(@RequestBody final Map<String, String> requestMap, final HttpServletResponse response) 但是,我仍然收到与上述相同的 400 错误
  • 您还需要我的答案的消耗部分(或者只是将其从您的 ajax 调用中取出) - 这行得通吗?
【解决方案2】:

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

【讨论】:

  • 感谢您的回复,问题是它永远不会到达响应阶段。我的意思是当它尝试接收 json 作为输入时会产生错误。我的响应是一个 CVS 文件,我认为当前代码应该没问题,因为它与 GET 方法完美配合。
【解决方案3】:

使用 Jersey api,您可以尝试: @邮政 public void downloadByCode(String stringRequest)

我想你会在 stringRequest 中找到你的帖子正文。

【讨论】:

  • 谢谢,如果没有额外的 API 无法解决,也许我会试一试。
【解决方案4】:

删除downloadByCode 方法中的@ResponseBody

【讨论】:

  • 没有改变,我认为问题与获取 json 作为输入有关。输出部分看起来不错。
【解决方案5】:

将您的方法 downloadByCode() 返回类型更改为字符串,然后返回字符串

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

【讨论】:

  • 它永远不会到达响应阶段。当它尝试加载 json 作为输入时会产生错误。
【解决方案6】:

我对 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) {

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

【讨论】:

  • 我认为这段代码是基于 GET 方法的,我想用 POST 方法获取 JSON 对象(或 JSON 字符串)。
【解决方案7】:

您可以将请求正文作为字符串,使用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);
    }
}

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

@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 制作了简单的应用程序,并使用了使用 HttpEntity 的建议解决方案以及使用 POJO 的其他示例,以运行您需要拥有 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,您将看到带有简单使用JQuery 发送POST 请求的html 页面,请求和响应的文本将显示在html 页面上,在控制器中我添加了两个处理程序,首先使用HttpEntity 的使用,其次是 POJO 的使用。

控制器:SampleRestController.java

HTML 页面:index.html

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

【讨论】:

  • 我要试一试!谢谢:)
  • 我收到此错误:Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported
  • 我使用这个 jquery ajax:$.ajax({ url:"/downloadByCode", type:"POST", data: JSON.stringify({"name":"value"}) });
  • 尝试在来自 js 选项的请求中使用 contentType: "application/json",就像您之前所做的那样。 $.ajax({ url: "/downloadByCode", contentType: "application/json", type: "POST", data: '{"name":"value"}' }).always(function (data) { alert(data); });
  • 我用 "application/json" contentType 对其进行了测试,我得到了这个错误: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]
【解决方案8】:

请尝试创建新课程:

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"}) });

【讨论】:

  • 感谢您的建议,但我收到此错误:Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported.
【解决方案9】:

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

因此,要解决您的问题,请使用 JSON 消息转换器,例如“MappingJacksonHttpMessageConverter”。注册 JSON 消息转换器后,创建一个 bean 类来保存您的 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' 标头,如下所示:

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

【讨论】:

  • 谢谢回复,我已经有了json转换器:&lt;bean class="org.springframework.http.converter.json.MappingJacksonHttp essageConverter" /&gt;
  • 我创建了与我的 json {"name","value"} 相同结构的 bean 类,但出现此错误:Could not instantiate JAXBContext for class [$InputData]: \r\n Exception Description: $InputData requires a zero argument constructor or a specified factory method. Note that non-static inner classes do not have zero argument constructors and are not supported
  • 实际问题是它在应该使用 Jackson 转换器时尝试使用 JAXB 转换器。
  • 我认为你是绝对正确的。我定义了三个消息转换器&lt;bean class="org.springframework.http.converter.ResourceHttpMessageConverter"/&gt;、&lt;bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"/&gt;和&lt;bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" /&gt; 。现在的问题是为什么它使用 JAXB 而不是 jackson 而我的 contentType 是 application/json。
  • 我注意到我的 json 结构类是一个内联类,它应该是static。将static 添加到我的班级后,现在选择正确的转换器,不需要accept 标签。感谢您为解决此问题所做的努力。
【解决方案10】:

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

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

或者你可以下载jar并把它放在我们的项目类路径中(你也可以使用其他映射器)

那么您应该创建一个模型或 DTO 类,您可以在其中映射您的 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/

【讨论】:

  • 感谢您的帮助。这个答案就是一切都应该“理想地”工作!但是,它会在我的环境中产生错误。
【解决方案11】:

最终的答案是这个问题中许多答案/cmets的组合,我将在这里对其进行总结:

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

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

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

4- 如果您在对象映射器中适当地设置它,您的 POJO 类可能会丢失部分 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"}) });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多