一尘不染

Spring 4.x / 3.x(Web MVC)REST API和JSON2 Post请求,如何一次全部正确?

spring

在详细讨论之前,我知道关于Stackoverflow的讨论和相关问题很多。所有这些都以不同的方式为我提供了帮助,因此我认为我将所有发现汇总为一个有组织的常见问题,以总结我的发现。

相关概念
你当然知道这些,但我只是将它们写为快速评论。如有任何遗漏,请随时进行编辑。

HTTP POST请求:
当你愿意将对象发送到Web服务或服务器端应用程序时,将使用发布请求。

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

序列化协议:
如今,最受欢迎的是JSON和XML。由于XML标记的性质,随着序列化xml对象的大小相对较大,XML变得不那么受欢迎。在此FAQ中,主要重点是JSON2序列化。

Spring:

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

Curl vs JQuery:

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

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

@RequestBody与@ResposeBody:
从名称中可以看到,就这么简单,只要在服务器端方法处理了请求之后向客户端发送响应,就只需要@ResponseBody。

RequestMappingHandlerAdapter与AnnotationMethodHandlerAdapter:
RequestMappingHandlerAdapter是Spring框架的新映射处理程序,从Spring 3.1开始取代了AnnotationMethodHandlerAdapter。如果你现有的配置仍在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的示例控制器。

The controller

这是用于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;
    }
}

The Java Object

@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 Post call

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

阅读 293

收藏
2020-04-15

共1个答案

一尘不染

CURL Post call

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

Different Error Scenarios:

在这里,我探讨了进行curl调用后可能遇到的各种错误以及可能出了什么问题。

Scenario One:

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的一个版本

Scenario Two:

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对象。可空属性不是强制性的,但你必须为所有NotNullable属性提供数据。重要的是要记住,Spring正在使用Java反射将你的JSON文件转换为Java对象,这是什么意思?这意味着变量和方法名称是CasE SensItiVe。如果你的JSON文件正在发送变量“ userName”,则Java对象中的匹配变量也必须命名为“ userName”。如果你有getter和setter,则它们也必须遵循相同的规则。getUserName和setUserName匹配我们前面的示例。

Senario Three:

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。

2020-04-15