【问题标题】:Pass parameters in the client在客户端传递参数
【发布时间】:2013-07-21 18:00:20
【问题描述】:

我使用 RESTful Web 服务。在这个 Web 服务中,我必须传递一个要保存为参数的 bean。

这是服务器代码:

@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Unidade inserir(Unidade unidade){
    Session s = ConnectDb.getSession();
    try {
        s.getTransaction().begin();
        s.save(unidade);
        s.getTransaction().commit();
        return unidade;
    } catch (Exception e) {
        e.printStackTrace();
        s.getTransaction().rollback();
        return null;
    } finally {
        s.close(); 
    }
}

我在客户端有如下代码:

ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource webResource = client.resource("http://localhost:8080/RestauranteWeb/rest/unidades/7");
Builder builder = webResource.accept(MediaType.APPLICATION_JSON); 
GenericType<Unidade> genericType = new GenericType<Unidade>() {};

Unidade u = new Unidade();
u.setUnidSigla("KG");
//How to pass this bean as parameter?

Unidade response = builder.post(genericType);
System.out.println(response);

如何将 bean 作为参数传递给方法?

【问题讨论】:

    标签: java web-services rest


    【解决方案1】:

    将 Jackson 用作序列化器/反序列化器

    如果您的Unidade 对象使用Jackson 注释和/或注册了Deserializer,那么您应该能够使用BODY 包含JSON 代表Unidade 对象的POST。它应该神奇地反序列化并在服务器端重建为对象。

    重要

    确保在POST 请求中添加Content-Type 标头,其值为application/json。如果没有此标头,您的Jersey 可能不知道如何处理正文。

    您将使用 Jackson ObjectMapper 将您的 Unidade 对象序列化为 JSON 并将其发送而不是 GenericType 的任何内容。

    我拥有以这种方式与 Jackson 无缝协作的 Jersey 和 RESTEasy 实现。

    【讨论】:

    • 但是我怎样才能使用上面的代码呢?还是我不应该为客户端使用 Jersey api?
    • 我正在使用最新版本的 Apache Commons HTTPClient,因为 Jersey 客户端是单线程的,并且还有一些我不想解决的其他限制。
    【解决方案2】:

    如何将 bean 作为参数传递给方法?

    查看post 方法的文档:

     /**
     * Invoke the POST method with a request entity that returns a response.
     * 
     * @param <T> the type of the response.
     * @param c the type of the returned response.
     * @param requestEntity the request entity.
     * @return an instance of type <code>c</code>.
     * @throws UniformInterfaceException if the status of the HTTP response is 
     *         greater than or equal to 300 and <code>c</code> is not the type
     *         {@link ClientResponse}.
     * @throws ClientHandlerException if the client handler fails to process
     *         the request or response.
     */
    <T> T post(Class<T> c, Object requestEntity) 
            throws UniformInterfaceException, ClientHandlerException;
    

    该方法有两个参数。第一个参数是预期的响应类型,第二个参数是要放入请求正文的实体。

    这里发生了什么,当执行请求时,Jersey 会将作为请求实体传递的对象序列化为 JSON 字符串(因此您设置了标头 - accept(MediaType.APPLICATION_JSON))。当来自服务器的响应到达时,Jersey 将对其进行反序列化(如requestEntity 的反向过程)并将对象返回给您。

    如果我的方法接收到超过 1 个参数怎么办?因为帖子 方法只接受 1

    你不能用 JAX-RS 做到这一点,实际上它没有什么意义。您可以将多个参数作为@PathParam@MatrixParam 传递给方法,但只能有一个与主体相关联(我们的请求中只有一个主体,对吧?)。 Checkout answer to this questioncheckout how to use @PathParam@MatrixParam

    假设我的方法不是返回“Unidade”类 返回一个字符串。因此,它将接收一个“Unidade”作为参数,并且 返回一个“字符串”。在这种情况下我如何检索它,通过 “Unidade”实例和以前一样?

    我相信您可以通过post(String.class, unidadeInstance) 实现这一目标。第一个参数不必与第二个参数相同。接受一个参数并返回另一个参数是有效的。获取参数并且在正文中不返回任何内容甚至是有效的(就像您在问题附加的代码中所做的那样)。您可以接受正文并返回包含状态 201 CreatedLocation 标头条目的响应,指向新创建资源的 URL。

    【讨论】:

      【解决方案3】:

      不确定您使用 GenericType 的目的是什么。不管怎样,试试下面的代码。

      ClientConfig config = new DefaultClientConfig();
      Client client = Client.create(config);
      Unidade u = new Unidade();
      u.setUnidSigla("KG");
      WebResource webResource = client.resource("http://localhost:8080/RestauranteWeb/rest/unidades/7");
      Unidade response = webResource.accept(MediaType.APPLICATION_JSON)
                                .type(MediaType.APPLICATION_JSON)
                                 .post(Unidade.class, u);
      

      【讨论】:

      • 好吧,它有效!但我不明白您在哪里定义请求以及在哪里定义响应(方法的参数和方法的返回)。假设我的方法不是返回“Unidade”类,而是返回一个字符串。因此,它将接收“Unidade”作为参数并返回“String”。在这种情况下如何检索它,像以前一样传递“Unidade”实例?
      • 如果我的方法接收到多个参数怎么办?因为 post 方法只接受 1.
      【解决方案4】:

      我不确定它是否有帮助,但我遇到了类似的问题。 我的场景是我需要一个 web 服务,它必须接收一堆值,这些值被组织为一种配置文件。但是这项服务必须处理有更多的配置文件,其中仍然是使用该服务的老客户。界面必须尽可能是静态的。

      我们的解决方案非常简单。我们只发布一个文本字段作为帖子的内容。但这包括 JSON 中配置文件对象的序列化状态。 伪代码:

      public class Profile1 {
        ...
      
        public String asJSON() {
          JSONObject obj = new JSONObject();
          obj.put("profileAtr1", profileAtr1);
          ...
          return obj.toString()
        }
      }
      
      formParams.put("profile", profile.asJSON());
      client.post(formParams);
      

      这种方式不会自动反序列化,但很容易手动完成。 我们使用一个通用的 Profile 对象来做到这一点,该对象可以在构造函数中使用 JSON 字符串创建。 伪代码:

      public GenericProfile {
        public GenericProfile(String json) {
          JSONObject obj = new JSONObject(json);
          String profileName = obj.getString("profileName");
      
          if (profileName.equals("Profile1") {
            this = new Profile1(obj);   // I know this is not working ;) My impl. is a litle bit more complecated as that. I think i use a static method in the generic profile to create an instance i need.
          } ...
        }
      }
      

      然后在您的网络服务中,只有这一种形式的参数来处理和反序列化;) 伪代码:

      public ResponseEnvelope coolServiceFunction(@FormParam("profile") String profileData) {
        GenericProfile profile = new GenericProfile(profileData);
      
        if (profile instanceof Profile1) {
          do what you want
        }
      }
      

      抱歉伪代码,但我已经关闭了我的开发虚拟机并且无法再访问任何存储库:( 我认为这个解决方案的最大好处是: 1. 它可以传输任何你可以用 JSON 打包的东西。我以这种方式传输 BASE64 编码的二进制块和高度加密的文本数据。 2. POST 服务的 REST 框架的最简单教程示例将提供您执行此操作所需的一切。 3.您可以确定您的界面会长时间停留。

      希望对你有帮助

      【讨论】:

        猜你喜欢
        • 2019-03-16
        • 1970-01-01
        • 2020-07-10
        • 2015-04-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多