Jersey Client / JAX-RS 和可选(非默认)@QueryParam(客户端)

21
我是一名有用的助手,可以为您进行文本翻译。以下是需要翻译的内容:

我有一个RESTful API的文档中说某个查询参数是可选的,并且没有提供默认参数。因此,我可以提供该值或不将其作为参数发送到GET请求中。

例如:

  • queryA 是必需的
  • queryB可选的(可以在GET中不发送它)

这应该可以工作:

http://www.example.com/service/endpoint?queryA=foo&queryB=bar

这也应该可以工作:

http://www.example.com/service/endpoint?queryA=foo

我该如何为Jersey-Proxy制作一个客户端接口,以实现这个功能??我没有服务器端的代码与之交互,因此我使用org.glassfish.jersey.client.proxy.WebResourceFactory通过Jersey-Proxy生成客户端来与服务器API进行交互。
示例界面:
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

我知道我可以创建另一个方法:

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first);

但是当你有多个可选字段时会发生什么?我不想为它们的每种可能性都创建一个变异体!


这可能会回答你的问题: https://dev59.com/pWYr5IYBdhLWcg3wFGVS - quintin
那是用于服务器端的,不是客户端。 - justderb
2个回答

37

界面之道一直正确

我简直不敢相信这是如此容易:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") String second);

}

注意到问题界面有什么不同吗?没有。那是因为那就是答案!


不要在可选参数中使用@DefaultValue

如果你想将参数默认为特定的值,你可以在参数中使用@DefaultValue注解:

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            @QueryParam("queryB") @DefaultValue("default") String second);

}

@QueryParam传递null即可不传递该参数

如果您希望使@QueryParam变为可选项,则不需要应用@DefaultValue注释。 要通过查询参数传递值,只需正常传递该值即可。 如果您不想显示查询参数,请传递null

import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/service")
@Produces("application/json")
public interface ServiceInterface {

    @Path("/endpoint")
    @GET
    public Response getEndpoint(
            @QueryParam("queryA") String first,
            // Pass null to this parameter to not put it in the GET request
            @QueryParam("queryB") String second);

}

因此,调用ServiceInterface.getEndpoint("firstQueryParam", "secondQueryParam"); 会调用:

http://targethost.com/service/endpoint?queryA=firstQueryParam&queryB=secondQueryParam

同时调用 ServiceInterface.getEndpoint("firstQueryParam", null); 将会产生以下结果:

http://targethost.com/service/endpoint?queryA=firstQueryParam

然后就没有第二个查询参数了! :)

关于基本数据类型的注释

如果你的API接收基本数据类型(如int, float, boolean等),那么请使用对象封装类(自动装箱)来封装这些基本数据类型(例如Integer, Float, Boolean等)。然后,你可以将null传递给该方法:

public Response getEndpoint(@QueryParam("queryA") Boolean first);

1
那数字呢?不能使用 null,所以必须检查值。 - jlanza
我认为要做到这一点,您需要使用自动装箱类型:BooleanInteger等... - justderb
如果你需要维护多个客户端,而它们不能全部升级到你的新API,Jersey会让你非常烦恼。基本上,它会强制你在接口中引入一个可选的查询参数,从而导致一个破坏性的变化。 - Baptiste Pernet

3
您可以将 UriInfo 实例(或类似的 HttpServletRequest)注入到您的方法中,并从中获取您想要的任何数据。
例如:
@Path("/endpoint")
@GET
public Response getEndpoint(@Context UriInfo info, @QueryParam("queryA") String queryA) {
  String queryB = info.getQueryParameters().getFirst("queryB");
  if (null != queryB) {
    // do something with it
  }
  ...
}

你脑海中能否想到这个能否与Jersey的WebResourceFactory一起使用?我会研究一下看看是否可以做到这一点... - justderb
你提到了Jersey客户端,但据我所知,你的例子是JAX-RS端点的服务器端定义... - Alex
定义是针对客户端的,因为我没有服务器端代码。 - justderb
好的,我明白了。我不确定你是否可以使用@Context样式注入,但这可能会起作用。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接