泽西岛客户端/JAX-RS 和可选(非默认)@QueryParam(客户端)界面一直都是正确的不要将@DefaultValue用于可选参数传递到您不想要的null@QueryParam

2022-09-02 09:22:52

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

例:

  • queryA是必需的
  • queryB可选的(可以在没有它的情况下发送)GET

这应该有效:

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

这也应该有效:

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

如何为泽西代理制作可以执行此操作的客户端接口?我没有要与之交互的服务器端代码,因此我通过泽西代理生成客户端以与服务器API进行交互。org.glassfish.jersey.client.proxy.WebResourceFactory

示例接口:

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

但是,当您有多个可选字段时会发生什么?我不想让它们发生每一个可能的突变!


答案 1

界面一直都是正确的

我不敢相信这很容易:

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

}

传递到您不想要的null@QueryParam

如果要使@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 采用基元值(如 、 、 等),则对该基元(如 、 、 等)使用对象包装类 (Autoboxing)。然后,您可以传递给该方法:intfloatbooleanIntegerFloatBooleannull

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

答案 2

您可以将实例(或其他类似的东西)注入到您的方法中,并从中获取所需的任何数据。UriInfoHttpServletRequest

例如

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