Spring 4.x/3.x (Web MVC) REST API 和 JSON2 Post 请求,如何一劳永逸?
Posted
技术标签:
【中文标题】Spring 4.x/3.x (Web MVC) REST API 和 JSON2 Post 请求,如何一劳永逸?【英文标题】:Spring 4.x/3.x (Web MVC) REST API and JSON2 Post requests, how to get it right once for all? 【发布时间】:2013-05-30 08:54:52 【问题描述】:在详细介绍之前,我知道 *** 上有很多对话和相关问题。所有这些都以不同的方式帮助我,所以我认为我将我的发现作为一个有组织的常见问题解答来总结我的发现。
相关概念
您当然知道这些,但我只是将它们写为快速回顾。如有遗漏,请随时编辑。
HTTP POST 请求:
当您愿意将对象发送到 Web 服务或服务器端应用程序时,使用发布请求。
序列化:
是从您的网络浏览器获取对象到您的服务器端应用程序的过程。可以使用 jQuery Ajax 调用或 Curl post 请求。
序列化协议:
目前最流行的是 JSON 和 XML。由于 XML 标记的性质,序列化的 xml 对象的大小相对较大,因此 XML 变得不那么流行了。在这个常见问题解答中,主要关注的是JSON2 序列化。
春天:
Spring 框架及其强大的注解使得以有效的方式公开 Web 服务成为可能。 Spring中有很多不同的库。这里我们关注的是Spring web MVC。
Curl 与 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 以来取代了 AnnotationMethodHandlerAdapter。如果您现有的配置仍在 AnnotationMethodHandlerAdapter 中,您可能会发现这篇文章很有用。我的帖子中提供的配置将使您了解如何设置 RequestMappingHandlerAdapter。
设置
您需要设置一个消息转换器。这就是您的序列化 JSON 消息体如何在服务器端转换为本地 java 对象的方式。
来自here 的基本配置。转换器是 basic configuration sample 中的 MarshallingHttpMessageConverter 和 CastorMarshaller,我已将它们替换为 MappingJackson2HttpMessageConverter 和 MappingJacksonHttpMessageConverter。
在哪里放置配置
我的项目设置方式,我有两个配置文件:
应用程序上下文 XML: 其中之一是您的 sessionFactory bean、dataSource bean 等所在的应用程序上下文 XML 文件。 MVC 调度程序 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 后调用
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
相关帖子和问题
如果不是针对所有提供以下帖子和问题的人,此常见问题解答是不可能的(如果我遇到有用的相关帖子/问题,此列表将扩大):
-
What is the correct JSON content type?
Spring 3.0 making JSON response using jackson message converter
How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
Posting JSON to REST API
https://github.com/geowarin/spring-mvc-examples
How to post JSON to php with curl
Spring REST | MappingJacksonHttpMessageConverter produces invalid JSON
https://github.com/eugenp/REST
Spring Web MVC - validate individual request params
How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
How do you return a JSON object from a Java Servlet
What MIME type if JSON is being returned by a REST API?
【问题讨论】:
很棒的教程!坚持下去 @Jose,很高兴你喜欢它,伙计 :) 设置部分的小不一致。您第一次使用 MappingJacksonHttpMessageConverter(杰克逊 1.*)和第二次 MappingJackson2HttpMessageConverter(杰克逊 2.* 兼容) @IliasBartolini 请参考我在 XML 设置下的说明:您可以拥有多个消息转换器。在这里,我创建了一个普通的 JSON 以及一个 JSON 2 消息转换器。 XML 文件中的 Ref 和普通 bean 格式都被使用了(我个人更喜欢 ref 标签,因为它更整洁)。 我将把“handlerAdapter”放在哪里?我会把它放在 mvc:annotation-driven 里面吗? 【参考方案1】: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
不同的错误场景:
在这里,我探讨了您在进行 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。 - 取消部署您的网络应用程序或干脆将其删除。 - 重新部署网络应用 - 确保在你的 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 对象。 Nullable 属性不是强制性的,但您必须为所有 NotNullable 属性提供数据。记住 Spring 使用 Java 反射将您的 JSON 文件转换为 Java 对象非常重要,这是什么意思?这意味着变量和方法名称是区分大小写的。如果您的 JSON 文件发送变量“userName”,那么您的 Java 对象中的匹配变量也必须命名为“userName”。如果您有 getter 和 setter,它们也必须遵循相同的规则。 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
根本原因:
您的网络服务不支持 Json 媒体类型。这可能是由于您的注释未指定媒体类型或您未在 Curl post 命令中指定媒体类型。
行动:检查您的消息转换器是否设置正确,并确保 Web 服务注释与上面的示例匹配。如果这些都没问题,请确保在 Curl 发布请求中指定内容类型。
您的网络服务不支持 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。
有关如何设置 spring 结帐的更多详细信息,请查看 spring mvc 指南。
相关帖子和问题
如果不是针对所有提供以下帖子和问题的人,此常见问题解答是不可能的(如果我遇到有用的相关帖子/问题,此列表将扩大):
-
What is the correct JSON content type?
Spring 3.0 making JSON response using jackson message converter
How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
Posting JSON to REST API
https://github.com/geowarin/spring-mvc-examples
How to post JSON to PHP with curl
Spring REST | MappingJacksonHttpMessageConverter produces invalid JSON
https://github.com/eugenp/REST
Spring Web MVC - validate individual request params
How to POST JSON data with Curl from Terminal/Commandline to Test Spring REST?
How do you return a JSON object from a Java Servlet
What MIME type if JSON is being returned by a REST API?
【讨论】:
【参考方案2】:应该很好地注意到一个 bean 类可以不被处理,如果它有 2 个或多个 setter 的一个字段没有 @JsonIgnore
可选的。 Spring/Jackson 抛出 HttpMediaTypeNotSupportedException
和 http 状态 415 Unsupported Media Type。
示例:
@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
。
【讨论】:
以上是关于Spring 4.x/3.x (Web MVC) REST API 和 JSON2 Post 请求,如何一劳永逸?的主要内容,如果未能解决你的问题,请参考以下文章
Spring与Web框架(例如Spring MVC)漫谈——关于Spring对于多个Web框架的支持