json - 如何将复杂对象作为参数传递给 RESTful 服务?

标签 json parameter-passing deserialization cxf

我已经成功设置了一个快速测试来创建一个“类 REST”服务,该服务返回一个序列化为 JSON 的对象,这非常简单快捷(基于 this article)。

但是,虽然返回 JSON 化对象很容易,但我还没有看到任何处理非原始输入参数的示例。如何将复杂对象作为参数传递?我正在使用 Apache CXF,但也欢迎使用其他框架(如 Jackson)的示例 :)

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

服务可能看起来像这样

@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 吗?我需要在函数定义中进行很多更改吗?

最佳答案

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

选项 1

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

示例

这只是使用包装器对象将原始问题中提到的服务变成一个示例。

@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。

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

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

示例

@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 对象组成的数组。

2019年评论: 看到这个答案在 2019 年仍然有一些热门,我觉得我应该发表评论。事后看来,我不会推荐选项 2,因为通过这些步骤只是为了能够进行 GET 调用会增加可能不值得的复杂性。如果您的服务接受如此复杂的输入,那么由于输入的排列数量,您可能无论如何都无法使用客户端缓存。我只是去在服务器上配置正确的跨域共享(CORS) header 并发布输入。然后专注于在服务器上缓存所有可以缓存的内容。

关于json - 如何将复杂对象作为参数传递给 RESTful 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6061292/

相关文章:

javascript - 使用保留字作为属性名,重温

java - 使用java中自制的打印方法打印int或double

javascript - 将命名参数传递给 Javascript 函数

c# - 仅当数组为空时 JSON 反序列化才会失败

java - 可靠地识别序列化 Java 对象的类

json - 将 _id 解码为 id 不起作用

php - 主键 ID 字段自动递增不允许 JSON 导入。 PHP/PDO 和 MySQL

oracle - Dapper with Oracle 传入 DbParameter

c# - Web API 发布反序列化 json 结果但所有属性为空

javascript - 如何通过 HTML 表单输入文本并使用 Javascript 从 JSON 文件中检索数据作为响应?