如何将复杂对象作为参数传递给RESTful服务? [英] How can I pass complex objects as arguments to a RESTful service?

查看:391
本文介绍了如何将复杂对象作为参数传递给RESTful服务?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经成功地建立了一个快速测试,以创建一个类似REST的"服务,该服务返回序列化为JSON的对象,并且非常容易和快捷(基于

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).

但是虽然返回桃子形的JSON对象很容易,但是我还没有看到任何处理非原语输入参数的示例.如何传递一个复杂的对象作为参数?我正在使用Apache CXF,但是也欢迎使用其他框架(例如杰克逊)的示例:)

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 Jackson are welcome too :)

客户端可能类似于构建一个javascript对象,将其传递到JSON.stringify(complexObj),然后将该字符串作为参数之一传递.

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.

该服务可能看起来像这样

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 {
    ...
    }
}

发送序列化对象作为参数可能会很快触及Internet Explorer施加的2KB URL限制.在这些情况下,您是否建议使用POST,我是否需要在函数定义中进行很多更改?

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?

推荐答案

经过一番挖掘,我很快发现基本上有两个选择:

After digging a bit I quickly found out there are basically two options:

您将包含所有其他参数的包装对象"传递给服务.您可能需要使用@XmlRootElement之类的JAXB注释对该包装器类进行注释,以使其与基于Jettison的提供程序一起使用,但是如果您使用Jackson代替,则没有必要.只需将内容类型设置为正确的类型,就会调用正确的消息正文阅读器. 当然,这仅适用于POST类型的服务(AFAIK).

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 Jackson 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).

这只是使用包装对象将原始问题中提到的服务转换为一个服务的示例.

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;
}

选项2

您可以提供一些特殊的字符串格式,将您的对象打包到其中,然后实现采用字符串的构造函数,在将采用该字符串的类中使用静态valueOf(String s)或静态fromString(String s)的类.从中创建一个对象.或非常相似,创建一个功能完全相同的ParameterHandler.

Option 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.

AFAIK,只有第二个版本允许您使用JSONP从浏览器调用服务(因为JSONP是仅限于GET的技巧).我选择此路线是为了能够在URI中传递复杂对象的数组.

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.

作为其工作原理的示例,请采用以下域类和服务

As an example of how this works, take the following domain class and service

@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(); //Jackson's JSON marshaller
           MyClass o= null;
           try {
                   o = mapper.readValue(jsonRepresentation, MyClass.class );
           } catch (IOException e) {
                    throw new WebApplicationException()
           }
           return o;
   }
}

在这种情况下,URI http://my-server.com/myService?a={"foo":1, "bar":2}&a={"foo":100, "bar":200}将反序列化为由两个MyClass对象组成的数组.

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.

2019年评论: 看到这个答案在2019年仍然很受欢迎,我觉得我应该发表评论.事后看来,我不会建议选项2,因为为了能够进行GET调用而执行这些步骤会增加可能不值得的复杂性.如果您的服务接受了如此复杂的输入,由于输入的排列数量众多,您可能无论如何都无法利用客户端缓存.我只是去在服务器上配置正确的跨域共享(CORS)标头,然后过帐输入.然后集中精力在服务器上缓存所有内容.

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.

这篇关于如何将复杂对象作为参数传递给RESTful服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆