Jersey客户端:如何将列表添加为查询参数

lsb*_*org 75 java rest jersey

我正在为具有List作为查询参数的GET服务创建Jersey客户端.根据文档,可以将List作为查询参数(此信息也在@QueryParam javadoc中),检查出来:

通常,方法参数的Java类型可以:

  1. 是一种原始的类型;
  2. 有一个接受单个String参数的构造函数;
  3. 有一个名为valueOf或fromString的静态方法接受单个String参数(例如,参见Integer.valueOf(String)和java.util.UUID.fromString(String)); 要么
  4. Be List,Set或SortedSet,其中T满足上面的2或3.生成的集合是只读的.

有时参数可能包含同一名称的多个值.如果是这种情况,则可以使用4)中的类型来获得所有值.

但是,我无法弄清楚如何使用Jersey客户端添加List查询参数.

我理解替代解决方案是:

  1. 使用POST而不是GET;
  2. 将List转换为JSON字符串并将其传递给服务.

第一个不好,因为服务的正确HTTP动词是GET.这是一种数据检索操作.

如果你不能帮助我,第二个将是我的选择.:)

我也正在开发这项服务,所以我可以根据需要进行更改.

谢谢!

更新

客户端代码(使用json)

Client client = Client.create();

WebResource webResource = client.resource(uri.toString());

SearchWrapper sw = new SearchWrapper(termo, pagina, ordenacao, hits, SEARCH_VIEW, navegadores);

MultivaluedMap<String, String> params = new MultivaluedMapImpl();
params.add("user", user.toUpperCase()); 
params.add("searchWrapperAsJSON", (new Gson()).toJson(sw));

ClientResponse clientResponse = webResource .path("/listar")
                                            .queryParams(params)
                                            .header(HttpHeaders.AUTHORIZATION, AuthenticationHelper.getBasicAuthHeader())
                                            .get(ClientResponse.class);

SearchResultWrapper busca = clientResponse.getEntity(new GenericType<SearchResultWrapper>() {});
Run Code Online (Sandbox Code Playgroud)

Dha*_*rmi 105

@GET 确实支持字符串列表

设置:
Java:1.7
泽西版:1.9

资源

@Path("/v1/test")
Run Code Online (Sandbox Code Playgroud)

子资源:

// receive List of Strings
@GET
@Path("/receiveListOfStrings")
public Response receiveListOfStrings(@QueryParam("list") final List<String> list){
    log.info("receieved list of size="+list.size());
    return Response.ok().build();
}
Run Code Online (Sandbox Code Playgroud)

泽西测试用例

@Test
public void testReceiveListOfStrings() throws Exception {
    WebResource webResource = resource();
    ClientResponse responseMsg = webResource.path("/v1/test/receiveListOfStrings")
            .queryParam("list", "one")
            .queryParam("list", "two")
            .queryParam("list", "three")
            .get(ClientResponse.class);
    Assert.assertEquals(200, responseMsg.getStatus());
}
Run Code Online (Sandbox Code Playgroud)

  • 就像其他人的注意事项一样,如果您直接在浏览器中编写URL,则必须重复参数名称:..?list = one&list = two&list = 3 (54认同)
  • 这确实是一份清单/订单是否得到保证?鉴于它似乎是泽西岛返回的多值地图列表,我想知道是否存在订单未保存的问题 (2认同)

Per*_*ion 28

如果您要发送除简单字符串以外的任何内容,我建议使用具有适当请求正文的POST,或将整个列表作为适当编码的JSON字符串传递.但是,使用简单的字符串,您只需要将每个值适当地附加到请求URL,Jersey将为您反序列化它.所以给出以下示例端点:

@Path("/service/echo") public class MyServiceImpl {
    public MyServiceImpl() {
        super();
    }

    @GET
    @Path("/withlist")
    @Produces(MediaType.TEXT_PLAIN)
    public Response echoInputList(@QueryParam("list") final List<String> inputList) {
        return Response.ok(inputList).build();
    }
}
Run Code Online (Sandbox Code Playgroud)

您的客户将发送对应于以下内容的请求:

获取http://example.com/services/echo?list=Hello&list=Stay&list=Goodbye

这将导致inputList被反序列化以包含值'Hello','Stay'和'Goodbye'

  • 感谢您的回答Perception!但是我想知道是否可以使用Jersey客户端使用List作为查询参数进行GET. (2认同)

Yog*_*ati 6

我同意你关于上面提到的替代解决方案

1. Use POST instead of GET;
2. Transform the List into a JSON string and pass it to the service.
Run Code Online (Sandbox Code Playgroud)

并且它确实无法添加List,MultiValuedMap因为它的impl类MultivaluedMapImpl具有接受String Key和String Value的能力.如下图所示

在此输入图像描述

你还想做这些事情,而不是尝试下面的代码.

控制器类

package net.yogesh.test;

import java.util.List;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;

import com.google.gson.Gson;

@Path("test")
public class TestController {
       @Path("testMethod")
       @GET
       @Produces("application/text")
       public String save(
               @QueryParam("list") List<String> list) {

           return  new Gson().toJson(list) ;
       }
}
Run Code Online (Sandbox Code Playgroud)

Cleint Class

package net.yogesh.test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.ws.rs.core.MultivaluedMap;

import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.core.util.MultivaluedMapImpl;

public class Client {
    public static void main(String[] args) {
        String op = doGet("http://localhost:8080/JerseyTest/rest/test/testMethod");
        System.out.println(op);
    }

    private static String doGet(String url){
        List<String> list = new ArrayList<String>();
        list = Arrays.asList(new String[]{"string1,string2,string3"});

        MultivaluedMap<String, String> params = new MultivaluedMapImpl();
        String lst = (list.toString()).substring(1, list.toString().length()-1);
        params.add("list", lst);

        ClientConfig config = new DefaultClientConfig();
        com.sun.jersey.api.client.Client client = com.sun.jersey.api.client.Client.create(config);
        WebResource resource = client.resource(url);

        ClientResponse response = resource.queryParams(params).type("application/x-www-form-urlencoded").get(ClientResponse.class);
        String en = response.getEntity(String.class);
        return en;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望这会对你有所帮助.


And*_*riy 5

可以使用 queryParam 方法,向其传递参数名称和一组值:

    public WebTarget queryParam(String name, Object... values);
Run Code Online (Sandbox Code Playgroud)

示例(泽西客户端 2.23.2):

    WebTarget target = ClientBuilder.newClient().target(URI.create("http://localhost"));
    target.path("path")
            .queryParam("param_name", Arrays.asList("paramVal1", "paramVal2").toArray())
            .request().get();
Run Code Online (Sandbox Code Playgroud)

这将向以下 URL 发出请求:

    http://localhost/path?param_name=paramVal1&param_name=paramVal2
Run Code Online (Sandbox Code Playgroud)