json 如何将复杂对象作为参数传递给 RESTful 服务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6061292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I pass complex objects as arguments to a RESTful service?
提问by oligofren
I have successfully set up a quick test of creating a "REST-like" service that returns an object serialized to JSON, and that was quite easy and quick (based on this article).
我已经成功地设置了一个快速测试来创建一个“类似 REST 的”服务,该服务返回一个序列化为 JSON 的对象,这非常简单快捷(基于本文)。
But while returning JSON-ified objects was easy as peach, I have yet to see any examples dealing with input parameters that are not primitives. How can I pass in a complex object as an argument? I am using Apache CXF, but examples using other frameworks like Hymanson are welcome too :)
但是,虽然返回 JSON 化的对象像桃子一样容易,但我还没有看到任何处理非基元输入参数的示例。如何将复杂对象作为参数传递?我正在使用 Apache CXF,但也欢迎使用其他框架(如 Hymanson)的示例:)
Client side would probably be something like building a javascript object, pass it into JSON.stringify(complexObj), and pass that string as one of the parameters.
客户端可能类似于构建 javascript 对象,将其传递到 JSON.stringify(complexObj),然后将该字符串作为参数之一传递。
The service would probably look something like this
该服务可能看起来像这样
@Service("myService")
class RestService {
@GET
@Produces("application/json")
@Path("/fooBar")
public Result fooBar(@QueryParam("foo") double foo, @QueryParam("bar") double bar,
@QueryParam("object") MyComplex object) throws WebServiceException {
...
}
}
Sending serialized objects as parameters would probably quickly touch the 2KB URL-limit imposed by Internet Explorer. Would you recommend using POST in these cases, and would I need to change much in the function definitions?
将序列化对象作为参数发送可能会很快触及 Internet Explorer 强加的 2KB URL 限制。在这些情况下,您是否建议使用 POST,我是否需要对函数定义进行很多更改?
采纳答案by oligofren
After digging a bit I quickly found out there are basically two options:
经过一番挖掘,我很快发现基本上有两种选择:
Option 1
选项1
You pass a "wrapper object" containing all the other parameters to the service. You might need to annotate this wrapper class with JAXB annotations like @XmlRootElement in order for this to work with the Jettison based provider, but if you use Hymanson in stead there is no need. Just set the content type to the right type and the right message body reader will be invoked. This will only work for POST type services of course (AFAIK).
您将包含所有其他参数的“包装器对象”传递给服务。您可能需要使用 JAXB 注释(如 @XmlRootElement)来注释此包装器类,以便它与基于 Jettison 的提供程序一起使用,但如果您改用 Hymanson,则没有必要。只需将内容类型设置为正确的类型,就会调用正确的消息正文阅读器。这当然只适用于 POST 类型的服务(AFAIK)。
Example
例子
This is just an example of turning the service mentioned in the original question into one using a wrapper object.
这只是使用包装器对象将原始问题中提到的服务转换为服务的一个示例。
@Service("myService")
class RestService {
@POST
@Produces("application/json")
@Path("/fooBar")
public Result fooBar(
/**
* Using "" will inject all form params directly into a ParamsWrapper
* @see http://cxf.apache.org/docs/jax-rs-basics.html
*/
@FormParam("") FooBarParamsWrapper wrapper
) throws WebServiceException {
doSomething(wrapper.foo);
}
}
class ParamsWrapper {
double foo, bar;
MyComplexObject object;
}
Option 2
选项 2
You can provide some special string format that you pack your objects into and then implement either a constructor taking a string, a static valueOf(String s) or a static fromString(String s) in the class that will take this string and create an object from it. Or quite similar, create a ParameterHandler that does exactly the same.
您可以提供一些特殊的字符串格式,将对象打包到其中,然后在类中实现一个接受字符串的构造函数、一个静态 valueOf(String s) 或一个静态 fromString(String s) 将接受这个字符串并创建一个对象从中。或者非常相似,创建一个完全相同的 ParameterHandler。
AFAIK, only the second version will allow you to call your services from a browser using JSONP (since JSONP is a trick restricted to GET). I chose this route to be able to pass arrays of complex objects in the URI.
AFAIK,只有第二个版本才允许您使用 JSONP 从浏览器调用您的服务(因为 JSONP 是一种仅限于 GET 的技巧)。我选择这条路线是为了能够在 URI 中传递复杂对象的数组。
As an example of how this works, take the following domain class and service
作为其工作原理的示例,请使用以下域类和服务
Example
例子
@GET
@Path("myService")
public void myService(@QueryParam("a") MyClass [] myVals) {
//do something
}
class MyClass {
public int foo;
public int bar;
/** Deserializes an Object of class MyClass from its JSON representation */
public static MyClass fromString(String jsonRepresentation) {
ObjectMapper mapper = new ObjectMapper(); //Hymanson's JSON marshaller
MyClass o= null;
try {
o = mapper.readValue(jsonRepresentation, MyClass.class );
} catch (IOException e) {
throw new WebApplicationException()
}
return o;
}
}
A URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200}would in this case be deserialized into an array composed of two MyClass objects.
http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200}在这种情况下,URI将被反序列化为由两个 MyClass 对象组成的数组。
2019 comment:Seeing that this answer still gets some hits in 2019, I feel I should comment. In hindsight, I would not recomment option 2, as going through these steps just to be able to be able to do GET calls adds complexity that's probably not worth it. If your service takes such complex input, you will probably not be able to utilize client side caching anyway, due to the number of permutations of your input. I'd just go for configuring proper Cross-Origin-Sharing (CORS) headers on the server and POST the input. Then focus on caching whatever you can on the server.
2019 评论:看到这个答案在 2019 年仍然获得一些点击,我觉得我应该评论。事后看来,我不会推荐选项 2,因为执行这些步骤只是为了能够执行 GET 调用会增加可能不值得的复杂性。如果您的服务接受如此复杂的输入,由于您输入的排列数量,您可能无论如何都无法利用客户端缓存。我只是在服务器上配置正确的跨源共享(CORS)标头并发布输入。然后专注于缓存服务器上的任何内容。
回答by r_ganaus
The accepted answer is missing @BeanParam. See https://docs.jboss.org/resteasy/docs/3.0-rc-1/javadocs/javax/ws/rs/BeanParam.htmlfor further details. It allows you to define query params inside a wrapper object. E.g.
接受的答案缺少@BeanParam。有关 更多详细信息,请参阅 https://docs.jboss.org/resteasy/docs/3.0-rc-1/javadocs/javax/ws/rs/BeanParam.html。它允许您在包装器对象中定义查询参数。例如
public class TestPOJO {
@QueryParam("someQueryParam")
private boolean someQueryParam;
public boolean isSomeQueryParam() {
return someQueryParam;
}
public boolean setSomeQueryParam(boolean value) {
this.someQueryParam = value;
}
}
... // inside the Resource class
@GET
@Path("test")
public Response getTest(@BeanParam TestPOJO testPOJO) {
...
}
回答by Koustuv Ganguly
the best and simplest solution is to send your object as a json string and in server side implement a method which will decode that json and map to the specified object as per your need.. and yes it`s better to use POST.
最好和最简单的解决方案是将您的对象作为 json 字符串发送,并在服务器端实现一种方法,该方法将解码该 json 并根据您的需要映射到指定的对象......是的,最好使用 POST。

