Spring 4.x / 3.x(Web MVC)REST API和JSON2 Post请求,如何正确使用它?

在深入细节之前,我知道在Stackoverflow上有很多对话和相关的问题。 他们都以不同的方式帮助我,所以我认为我把所有研究结果放在一起作为一个有组织的FAQ来总结我的发现。

相关概念

当然你知道这些,但我只是写他们作为一个快速审查。 随时编辑,以防万一我失去了一些东西。

HTTP POST请求:

当您愿意将对象发送到Web服务或您的服务器端应用程序时,会使用发布请求。

连载:

是将对象从Web浏览器传递到服务器端应用程序的过程。 可以使用jQuery Ajax调用或Curl post请求。

序列化协议:

这些日子中最受欢迎的是JSON和XML。 XML由于XML标签的性质而变得不太流行,因为序列化的XML对象的大小相对较大。 在这个FAQ中,主要焦点是JSON2序列化。

弹簧:

Spring框架及其强大的注释使得以有效的方式公开Web服务成为可能。 Spring中有很多不同的库。 这里我们关注的是Spring web MVC。

卷曲与JQuery:

这些是您可以用来在您的客户端进行发布请求的工具。 即使您计划使用JQuery ajax调用,我建议您使用Curl进行调试,因为它在发出请求后提供了详细的响应。

@RequestBody vs @ RequestParam / @ PathVariable vs @ModelAttribute:

如果您的Web服务不依赖于您的Java EE模型,则必须使用@RequestBody。 如果您使用模型并将JSON对象添加到模型中,则可以通过@ModelAttribute访问该对象。 只有在您的请求是GET请求或GET和POST请求组合的情况下,您将需要使用@ RequestParam / @ PathVariable。

@RequestBody vs @ResposeBody:

正如您从名字中看到的那样简单,如果您在服务器端方法处理请求后发送客户端的响应,则只需要@ResponseBody。

RequestMappingHandlerAdapter vs AnnotationMethodHandlerAdapter:

RequestMappingHandlerAdapter是自Spring 3.1以来取代AnnotationMethodHandlerAdapter的Spring框架的新映射处理程序。 如果您现有的配置仍然在AnnotationMethodHandlerAdapter中,您可能会觉得这篇文章很有用。 我的文章中提供的配置将为您提供有关如何设置RequestMappingHandlerAdapter的想法。

建立

您将需要设置消息转换器。 这就是您的序列化JSON消息体在您的服务器端转换为本地java对象的方式。

基本配置从这里。 转换器是基本配置示例中的MarshallingHttpMessageConverter和CastorMarshaller,我用MappingJackson2HttpMessageConverter和MappingJacksonHttpMessageConverter替换了它们。

何处放置配置

我的项目设置的方式,我有两个配置文件:

  • 应用程序上下文XML:一个是sessionFactory bean,dataSource bean等所在的应用程序上下文XML文件。
  • MVC Dispatcher Servlet XML:这是您拥有视图解析器bean并导入应用程序上下文XML的地方。
  • hadlerAdapter bean必须位于MVC Dispatcher XML文件的后面。

    <bean name="handlerAdapter"
    class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
        <property name="messageConverters">
            <list>
                <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
                <ref bean="jsonConverter"/>
    
            </list>
    
        </property>
        <property name="requireSession" value="false"/>
    
    </bean>
    <bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
        <property name="supportedMediaTypes" value="application/json"/>
    </bean>
    

    你可以有多个消息转换器。 在这里,我创建了一个普通的JSON以及一个JSON 2消息转换器。 已经使用XML文件中的Ref和正常bean格式(我个人比较喜欢ref标签)。

    REST API

    这是一个暴露REST API的示例控制器。

    控制器

    这是您的HTTP POST请求的REST API公开的地方。

    @Component
    @Controller
    @RequestMapping("/api/user")
    public class UserController {
    @RequestMapping(value = "/add", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public String insertUser(@RequestBody final User user) {
        System.out.println(user.toString());
        userService.insertUser(user);
        String userAdded = "User-> {" + user.toString() + "} is added";
        System.out.println(userAdded);
            return userAdded;
        }
    }
    

    Java对象

    @JsonAutoDetect
    public class User {
    
    private int id;
    private String username;
    private String name;
    private String lastName;
    private String email;
    
    public int getId() {
        return externalId;
    }
    
    public void setId(final int id) {
        this.id = id;
    }
    
    public String getName() {
        return name;
    }
    
    public void setName(final String name) {
        this.name = name;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(final String email) {
        this.email = email;
    }
    public String getUsername() {
        return username;
    }
    
    public void setUsername(final String username) {
        this.username = username;
    }
    
    public String getLastName() {
        return lastName;
    }
    
    public void setLastName(final String lastName) {
        this.lastName = lastName;
    }
    
    @Override
    public String toString() {
        return this.getName() + " | " + this.getLastName()  + " | " + this.getEmail()
                + " | " + this.getUsername()  + " | " + this.getId()  + " | ";
        }
    
    }
    

    CURL邮政电话

    curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"JohnBlog@user.com"}' http://localhost:8080/[YOURWEBAPP]/api/user/add
    

    相关的帖子和​​问题

    如果不是所有提供以下帖子和问题的人都可以访问此FAQ(如果我遇到有用的相关帖子/问题,此列表将会扩展):

  • 什么是正确的JSON内容类型?
  • Spring 3.0使用杰克逊消息转换器进行JSON响应
  • 如何使用终端/命令行中的Curl来发布JSON数据以测试Spring REST?
  • 将JSON发布到REST API
  • https://github.com/geowarin/spring-mvc-examples
  • 如何使用curl将JSON发布到PHP
  • Spring REST | MappingJacksonHttpMessageConverter产生无效的JSON
  • https://github.com/eugenp/REST
  • Spring Web MVC - 验证各个请求参数
  • 如何使用终端/命令行中的Curl来发布JSON数据以测试Spring REST?
  • 你如何从Java Servlet中返回一个JSON对象
  • REST API返回JSON的MIME类型是什么?

  • CURL邮政电话

    curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"JohnBlog@user.com"}' http://localhost:8080/[YOURWEBAPP]/api/user/add
    

    不同的错误情景:

    在这里,我会探索在进行卷曲调用之后可能遇到的不同错误,以及可能发生错误的错误。

    情景一:

    HTTP/1.1 404 Not Found
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=utf-8
    Content-Length: 949
    Date: Tue, 04 Jun 2013 02:59:35 GMT
    

    这意味着您提供的URL中不存在REST API。

    根本原因:
  • 您的请求可能有错字(相信我会发生这种情况)!
  • 这可能是因为你的弹簧配置不正确。 如果是这种情况,需要进一步深入研究实际出现的问题,但在开始更复杂的调查之前,我已经提供了一些您需要做的初始操作。
  • 操作:

    在你确定所有事情都完全正确完成之后,你的配置和你的URL都没有错: - 运行一个maven clean。 - 取消部署您的Web应用程序或直接删除它。 - 重新部署Web应用程序 - 确保在Maven / Gradle中只使用一个版本的Spring

    情景二:

    HTTP/1.1 400 Bad Request
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=utf-8
    Content-Length: 968
    Date: Tue, 04 Jun 2013 03:08:05 GMT
    Connection: close
    

    背后的唯一原因是,您的请求格式不正确。 如果您签出详细的卷曲响应,您应该能够看到“客户发送的请求在语法上不正确。”。

    根本原因:

    您的JSON格式不正确,或者您缺少JAVA对象的必需参数。

    操作:

    确保以正确的格式和正确数量的参数提供JSON对象。 可为空的属性不是强制性的,但您必须为所有NotNullable属性提供数据。 记住Spring使用Java反射将JSON文件转换为Java对象非常重要,这意味着什么? 这意味着变量和方法名称是CasE SensItiVe。 如果您的JSON文件正在发送变量“userName”,那么您的Java对象中的匹配变量也必须命名为“userName”。 如果你有吸气者和安装者,他们也必须遵循相同的规则。 getUserName和setUserName匹配我们前面的示例。

    塞纳里奥三:

    HTTP/1.1 415 Unsupported Media Type
    Server: Apache-Coyote/1.1
    Content-Type: text/html;charset=utf-8
    Content-Length: 1051
    Date: Wed, 24 Aug 2011 08:50:17 GMT
    
    根本原因:

    您的Web服务不支持Json媒体类型。 这可能是由于您的注释未指定媒体类型,或者您未在Curl post命令中指定媒体类型。

    操作:

    检查您的消息转换器是否设置正确,并确保Web服务注释符合上述示例。 如果这些都很好,请确保您在Curl发布请求中指定了内容类型。

    您的Web服务不支持json媒体类型。

    Senario N(!):

    HTTP/1.1 200 OK 
    Server: Apache-Coyote/1.1 
    Content-Type: application/json;charset=UTF-8 
    Transfer-Encoding: chunked 
    Date: Tue, 04 Jun 2013 03:06:16 GMT 
    

    恭喜用户实际发送到您的服务器端REST API。

    有关如何设置弹簧mvc指南的更多详细信息。

    相关的帖子和​​问题

    如果不是所有提供以下帖子和问题的人都可以访问此FAQ(如果我遇到有用的相关帖子/问题,此列表将会扩展):

  • 什么是正确的JSON内容类型?
  • Spring 3.0使用杰克逊消息转换器进行JSON响应
  • 如何使用终端/命令行中的Curl来发布JSON数据以测试Spring REST?
  • 将JSON发布到REST API
  • https://github.com/geowarin/spring-mvc-examples
  • 如何使用curl将JSON发布到PHP
  • Spring REST | MappingJacksonHttpMessageConverter产生无效的JSON
  • https://github.com/eugenp/REST
  • Spring Web MVC - 验证各个请求参数
  • 如何使用终端/命令行中的Curl来发布JSON数据以测试Spring REST?
  • 你如何从Java Servlet中返回一个JSON对象
  • REST API返回JSON的MIME类型是什么?

  • 应该很好地注意到,如果一个Bean的类有两个或更多的setter,而没有@JsonIgnore ,那么就不能处理一个bean类。 Spring / Jackson抛出HttpMediaTypeNotSupportedException和http状态415不支持的媒体类型。

    示例:

    @JsonGetter
    public String getStatus() {
        return this.status;
    }
    
    @JsonSetter
    public void setStatus(String status) {
        this.status = status;
    }
    
    @JsonIgnore
    public void setStatus(StatusEnum status) {
        if (status == null) {
            throw new NullPointerException();
        }
    
        this.status = status.toString();
    }
    

    更新:在这种情况下,我们还必须指定@JsonGetter@JsonSetter在返回类型时不会有问题。

    刚刚用Spring 3.2.2和Jackson 2.2进行了测试。 它可以很好地作为参数( @RequestBody )和/或作为返回类型( @ResponseBody )。

    更新2:

    如果指定@JsonGetter@JsonSetter@JsonIgnore似乎不是必需的。

    链接地址: http://www.djcxy.com/p/1323.html

    上一篇: Spring 4.x/3.x (Web MVC) REST API and JSON2 Post requests, how to get it right once for all?

    下一篇: How do I parse a string to a float or int in Python?