Klient Jersey: jak dodać listę jako parametr zapytania

81

Tworzę klienta Jersey dla usługi GET, która ma listę jako parametr zapytania. Zgodnie z dokumentacją możliwe jest posiadanie listy jako parametru zapytania (ta informacja jest również w @QueryParam javadoc), sprawdź to:

Ogólnie rzecz biorąc, typ Java parametru metody może:

  1. Bądź typem prymitywnym;
  2. Mieć konstruktora, który akceptuje pojedynczy argument typu String;
  3. Mieć statyczną metodę o nazwie valueOf lub fromString, która akceptuje pojedynczy argument typu String (patrz, na przykład, Integer.valueOf (String) i java.util.UUID.fromString (String)); lub
  4. Be List, Set lub SortedSet, gdzie T spełnia 2 lub 3 powyżej. Otrzymana kolekcja jest tylko do odczytu.

Czasami parametry mogą zawierać więcej niż jedną wartość dla tej samej nazwy. W takim przypadku można użyć typów 4) w celu uzyskania wszystkich wartości.

Jednak nie mogę dowiedzieć się, jak dodać parametr zapytania List przy użyciu klienta Jersey.

Rozumiem, że alternatywne rozwiązania to:

  1. Użyj POST zamiast GET;
  2. Przekształć listę w ciąg JSON i przekaż ją do usługi.

Pierwsza nie jest dobra, ponieważ właściwy czasownik HTTP dla usługi to GET. Jest to operacja odzyskiwania danych.

Druga będzie moją opcją, jeśli nie możesz mi pomóc. :)

Rozwijam też usługę, więc w razie potrzeby mogę ją zmienić.

Dzięki!

Aktualizacja

Kod klienta (przy użyciu 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>() {});
lsborg
źródło
1
czy możesz podać kod klienta koszulki tutaj ...
Yogesh Prajapati,
1
yogesh, dodałem kod klienta.
lsborg
2
Jeśli rozumiem opis problemu, możesz przekazać listę wartości jako parametr zapytania, dodając wiele wartości do tego samego klucza. Jeśli „searchWrapper” jest kluczem i chcesz przekazać do niego wiele wartości: utwórz adres URL w ten sposób: // YourURL? SearchWrapper = value1 & searchWrapper = value2 & searchWrapper = value3 może być konieczne wielokrotne wstawianie wartości do tego samego klucza, jeśli Twoja mapa wielowartościowa to obsługuje .
Thamme Gowda
1
Dzięki, @ThammeGowda! Nie testowałem tego, ale wydaje się, że działa tak, jak javadoc MultivaluedMap do dodawania stanów metod: Dodaj wartość do bieżącej listy wartości dla dostarczonego klucza .
lsborg

Odpowiedzi:

119

@GET obsługuje listę ciągów

Instalacja :
Java: 1.7
Wersja Jersey: 1.9

Ratunek

@Path("/v1/test")

Zasób podrzędny :

// 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();
}

Tester z Jersey

@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());
}
Dharmi
źródło
1
Dzięki Ci. Pomaga mi.
Sapikelio
62
Uwaga dla innych, jeśli piszesz adres URL bezpośrednio w przeglądarce, musisz powtórzyć nazwę parametru: ..? List = one & list = two & list = three
endian
2
Czy to naprawdę lista / czy porządek jest przestrzegany? Biorąc pod uwagę, że wydaje się, że jest to mapa wielowartościowa, którą Jersey wraca jako lista, zastanawiam się, czy mogą wystąpić problemy z
niezachowaniem porządku
Tak. ? list = one & list = two & list = three nie jest tak przydatne. as list = one, two, three - dlatego paruję to ręcznie z łańcucha do listy ..List<String> argList = List.of(argString.split("\\s*,\\s*"))
ses
30

Jeśli wysyłasz coś innego niż proste ciągi znaków, polecam użycie POST z odpowiednią treścią żądania lub przekazanie całej listy jako odpowiednio zakodowanego ciągu JSON. Jednak w przypadku prostych ciągów wystarczy odpowiednio dołączyć każdą wartość do adresu URL żądania, a Jersey deserializuje ją za Ciebie. Biorąc więc pod uwagę następujący przykładowy punkt końcowy:

@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();
    }
}

Twój klient wysłałby żądanie odpowiadające:

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

Co spowodowałoby inputListdeserializację, aby zawierała wartości „Hello”, „Stay” i „Goodbye”

Postrzeganie
źródło
2
Dzięki za odpowiedź. Percepcja! Ale chciałbym się dowiedzieć, czy możliwe jest wykonanie GET z listą jako parametrem zapytania przy użyciu klienta Jersey.
lsborg
1
Czy możesz powiedzieć, jak utworzyć taką listę po stronie klienta, ponieważ moimi klientami są Android i iOS. Oczywiście nie chcemy tworzyć klucza = wartości i klucza = wartości ręcznie
nilesh
co jeśli wyśle list[0]=Hello&list[1]=Stay? jak sobie z tym poradzić?
user1735921
6

zgadzam się z tobą co do alternatywnych rozwiązań, o których wspomniałeś powyżej

1. Use POST instead of GET;
2. Transform the List into a JSON string and pass it to the service.

i to prawda, że nie można dodać Listdo MultiValuedMappowodu jego IMPL klasy MultivaluedMapImplmają możliwość akceptowania string key i Wartość ciągu. co pokazano na poniższym rysunku

wprowadź opis obrazu tutaj

nadal chcesz to zrobić, niż próbować śledzić kod.

Klasa kontrolera

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

Klasa klienta

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

mam nadzieję, że to ci pomoże.

Yogesh Prajapati
źródło
Najlepsza odpowiedź tutaj! Dzięki +1
Haramoz
3

GET Request with JSON Query Param

package com.rest.jersey.jerseyclient;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class JerseyClientGET {

    public static void main(String[] args) {
        try {               

            String BASE_URI="http://vaquarkhan.net:8080/khanWeb";               
            Client client = Client.create();    
            WebResource webResource = client.resource(BASE_URI);

            ClientResponse response = webResource.accept("application/json").get(ClientResponse.class);

            /*if (response.getStatus() != 200) {
               throw new RuntimeException("Failed : HTTP error code : "
                + response.getStatus());
            }
*/
            String output = webResource.path("/msg/sms").queryParam("search","{\"name\":\"vaquar\",\"surname\":\"khan\",\"ext\":\"2020\",\"age\":\"34\""}").get(String.class);
            //String output = response.getEntity(String.class);

            System.out.println("Output from Server .... \n");
            System.out.println(output);                         

        } catch (Exception e) {

            e.printStackTrace();    
        }    
    }    
}

Żądanie postu:

package com.rest.jersey.jerseyclient;

import com.rest.jersey.dto.KhanDTOInput;
import com.sun.jersey.api.client.Client;
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.api.json.JSONConfiguration;

public class JerseyClientPOST {

    public static void main(String[] args) {
        try {

            KhanDTOInput khanDTOInput = new KhanDTOInput("vaquar", "khan", "20", "E", null, "2222", "8308511500");                      

            ClientConfig clientConfig = new DefaultClientConfig();

            clientConfig.getFeatures().put( JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);

            Client client = Client.create(clientConfig);

               // final HTTPBasicAuthFilter authFilter = new HTTPBasicAuthFilter(username, password);
               // client.addFilter(authFilter);
               // client.addFilter(new LoggingFilter());

            //
            WebResource webResource = client
                    .resource("http://vaquarkhan.net:12221/khanWeb/messages/sms/api/v1/userapi");

              ClientResponse response = webResource.accept("application/json")
                .type("application/json").put(ClientResponse.class, khanDTOInput);


            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code :" + response.getStatus());
            }

            String output = response.getEntity(String.class);

            System.out.println("Server response .... \n");
            System.out.println(output);

        } catch (Exception e) {

            e.printStackTrace();

        }    
    }    
}
vaquar khan
źródło
zobaczenie przykładu zasobów klienta było tym, czego potrzebowałem :) dzięki
Mobigital
0

Można by użyć metody queryParam, przekazując jej nazwę parametru i tablicę wartości:

    public WebTarget queryParam(String name, Object... values);

Przykład (jersey-client 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();

Spowoduje to wysłanie żądania na następujący adres URL:

    http://localhost/path?param_name=paramVal1&param_name=paramVal2
Andriy
źródło