Spring 4.x/3.x (Web MVC) REST API 和 JSON2 Post 请求,如何一劳永逸地正确运行?相关帖子和问题相关帖子和问题

2022-09-01 01:40:22

在详细介绍之前,我知道在Stackoverflow上有很多对话和相关问题。他们都以不同的方式帮助我,所以我认为我把我的发现放在一起,作为一个有组织的常见问题解答来总结我的发现。

相关概念

当然你知道这些,但我只是把它们写成一个快速的评论。随意编辑,以防我错过了什么。

HTTP POST 请求:

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

序列化:

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

序列化协议:

现在最受欢迎的是JSON和XML。XML 正变得越来越不受欢迎,因为由于 XML 标记的性质,序列化的 xml 对象的大小相对较大。在本常见问题解答中,主要关注点是 JSON2 序列化。

春天:

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

Curl vs JQuery:

这些是可用于在客户端发出发布请求的工具。即使您打算使用JQuery ajax调用,我也建议您使用Curl进行调试,因为它会在发出post请求后为您提供详细的响应。

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

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

@RequestBody与@ResposeBody:

从名称中可以看出,它很简单,只有在服务器端方法处理请求后向客户端发送响应时,才需要@ResponseBody。

RequestMappingHandlerAdapter vs AnnotationMethodHandlerAdapter:

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

设置

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

从这里开始基本配置。转换器在基本配置示例中是MarshallingHttpMessageConverter和CastorMarshaller,我用PingJackson2HttpMessageConverter和MapingJacksonHttpMessageConverter替换了它们。

配置放置位置

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

  • 应用程序上下文 XML:一个是应用程序上下文 XML 文件,您的会话网站 Bean、dataSource Bean 等所在的位置。
  • 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 发布请求的 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 -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

相关帖子和问题

如果不是所有提供以下帖子和问题的人都无法使用此常见问题解答(如果我遇到有用的相关帖子/问题,此列表将扩展):

  1. 什么是正确的 JSON 内容类型?
  2. Spring 3.0 使用 jackson 消息转换器进行 JSON 响应
  3. 如何使用Curl从终端/命令行发布JSON数据以测试Spring REST?
  4. 将 JSON 发布到 REST API
  5. https://github.com/geowarin/spring-mvc-examples
  6. 如何使用 curl 将 JSON 发布到 PHP
  7. 弹簧休息|MappingJacksonHttpMessageConverter 生成无效的 JSON
  8. https://github.com/eugenp/REST
  9. Spring Web MVC - 验证单个请求参数
  10. 如何使用Curl从终端/命令行发布JSON数据以测试Spring REST?
  11. 如何从 Java Servlet 返回 JSON 对象
  12. 如果 REST API 返回 JSON,则什么 MIME 类型?

答案 1

卷发帖子呼叫

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

不同的错误场景:

在这里,我将探讨您在进行curl呼叫后可能遇到的不同错误,以及可能出错的错误。

方案一:

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应用程序或直接删除它。- 重新部署网络应用程序 - 确保在您的 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

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

根源:

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

行动:

请确保以正确的格式提供 JSON 对象,并提供正确数量的参数。可为 null 的属性不是必需的,但您必须为所有 NotNullable 属性提供数据。记住Spring正在使用Java反射将你的JSON文件变成Java对象,这是什么意思?这意味着变量和方法名称是CasE SensItiVe。如果您的 JSON 文件发送变量“userName”,则 Java 对象中的匹配变量也必须命名为 “userName”。如果你有 getter 和 setters,他们也必须遵循相同的规则。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 媒体类型。

塞纳里奥 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指南。

相关帖子和问题

如果不是所有提供以下帖子和问题的人都无法使用此常见问题解答(如果我遇到有用的相关帖子/问题,此列表将扩展):

  1. 什么是正确的 JSON 内容类型?
  2. Spring 3.0 使用 jackson 消息转换器进行 JSON 响应
  3. 如何使用Curl从终端/命令行发布JSON数据以测试Spring REST?
  4. 将 JSON 发布到 REST API
  5. https://github.com/geowarin/spring-mvc-examples
  6. 如何使用 curl 将 JSON 发布到 PHP
  7. 弹簧休息|MappingJacksonHttpMessageConverter 生成无效的 JSON
  8. https://github.com/eugenp/REST
  9. Spring Web MVC - 验证单个请求参数
  10. 如何使用Curl从终端/命令行发布JSON数据以测试Spring REST?
  11. 如何从 Java Servlet 返回 JSON 对象
  12. 如果 REST API 返回 JSON,则什么 MIME 类型?

答案 2

应该注意到,如果一个bean类有2个或更多个字段的setter而没有可选的,则不能处理它。弹簧/杰克逊投掷和 http 状态 415 不支持的媒体类型。@JsonIgnoreHttpMediaTypeNotSupportedException

例:

@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