Jak uzyskać dostęp do parametrów w metodzie RESTful POST

123

Moja metoda POST wygląda następująco:

@POST
@Consumes({"application/json"})
@Path("create/")
public void create(String param1, String param2){
    System.out.println("param1 = " + param1);
    System.out.println("param2 = " + param2);
}

Kiedy tworzę klienta Jersey w Netbeans, metoda wywołująca metodę wysyłania wygląda następująco:

public void create(Object requestEntity){
    webResource.path("create").type(MediaType.APPLICATION_JSON).post(requestEntity);
}

Podczas wykonywania tego testu:

@Test
public void hello(){
    String json = "{param1=\"hello\",param2=\"hello2\"}";
    this.client.create(json);
}

Daje następujące dane wyjściowe na serwerze:

INFO: param1 = {param1="hello",param2="hello2"}
INFO: param2 = 

Co muszę zmienić, aby parametry miały prawidłową wartość?

Klaasvaak
źródło
Czy używasz tego w aplikacji na Androida, czy nie?
Android-Droid
W końcu chcę wywołać tę metodę publikowania w aplikacji na Androida. Usługa sieciowa w jakiś sposób nie wie, jak podpisać wartości parametrów. Chcę wiedzieć, jak to zrobić.
Klaasvaak

Odpowiedzi:

356

Twoja @POSTmetoda powinna akceptować obiekt JSON zamiast ciągu. Jersey używa JAXB do obsługi organizowania i unmarshalowania obiektów JSON (szczegóły w dokumentacji koszulki ). Utwórz zajęcia takie jak:

@XmlRootElement
public class MyJaxBean {
    @XmlElement public String param1;
    @XmlElement public String param2;
}

Wtedy Twoja @POSTmetoda wyglądałaby następująco:

@POST @Consumes("application/json")
@Path("/create")
public void create(final MyJaxBean input) {
    System.out.println("param1 = " + input.param1);
    System.out.println("param2 = " + input.param2);
}

Ta metoda oczekuje, że otrzyma obiekt JSON jako treść HTTP POST. JAX-RS przekazuje treść wiadomości HTTP jako parametr bez adnotacji - inputw tym przypadku. Rzeczywista wiadomość wyglądałaby mniej więcej tak:

POST /create HTTP/1.1
Content-Type: application/json
Content-Length: 35
Host: www.example.com

{"param1":"hello","param2":"world"}

Używanie JSON w ten sposób jest dość powszechne z oczywistych powodów. Jeśli jednak generujesz lub konsumujesz go w czymś innym niż JavaScript, musisz uważać, aby odpowiednio uciec przed danymi. W JAX-RS do zaimplementowania tego można użyć MessageBodyReader i MessageBodyWriter . Uważam, że Jersey ma już implementacje dla wymaganych typów (np. Prymitywy Java i klasy opakowane JAXB), a także dla JSON. JAX-RS obsługuje wiele innych metod przekazywania danych. Nie wymagają one tworzenia nowej klasy, ponieważ dane są przekazywane za pomocą prostego przekazywania argumentów.


HTML <FORM>

Parametry zostaną opatrzone adnotacjami za pomocą @FormParam :

@POST
@Path("/create")
public void create(@FormParam("param1") String param1,
                   @FormParam("param2") String param2) {
    ...
}

Przeglądarka zakoduje formularz przy użyciu „application / x-www-form-urlencoded” . Środowisko wykonawcze JAX-RS zajmie się zdekodowaniem treści i przekazaniem jej do metody. Oto, co powinieneś zobaczyć na przewodzie:

POST /create HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Content-Length: 25

param1=hello&param2=world

W tym przypadku zawartość jest zakodowana w postaci adresu URL .

Jeśli nie znasz nazw parametrów FormParam, możesz wykonać następujące czynności:

@POST @Consumes("application/x-www-form-urlencoded")
@Path("/create")
public void create(final MultivaluedMap<String, String> formParams) {
    ...
}

Nagłówki HTTP

Możesz użyć adnotacji @HeaderParam, jeśli chcesz przekazywać parametry przez nagłówki HTTP:

@POST
@Path("/create")
public void create(@HeaderParam("param1") String param1,
                   @HeaderParam("param2") String param2) {
    ...
}

Oto jak wyglądałby komunikat HTTP. Zauważ, że ten post nie ma treści.

POST /create HTTP/1.1
Content-Length: 0
Host: www.example.com
param1: hello
param2: world

Nie użyłbym tej metody do uogólnionego przekazywania parametrów. Jest to jednak bardzo przydatne, jeśli chcesz uzyskać dostęp do wartości określonego nagłówka HTTP.


Parametry zapytania HTTP

Ta metoda jest używana głównie z HTTP GET, ale ma również zastosowanie do POST. Używa adnotacji @QueryParam .

@POST
@Path("/create")
public void create(@QueryParam("param1") String param1,
                   @QueryParam("param2") String param2) {
    ...
}

Podobnie jak w poprzedniej technice, przekazywanie parametrów za pośrednictwem ciągu zapytania nie wymaga treści wiadomości. Oto wiadomość HTTP:

POST /create?param1=hello&param2=world HTTP/1.1
Content-Length: 0
Host: www.example.com

Musisz być szczególnie ostrożny, aby poprawnie zakodować parametry zapytania po stronie klienta. Korzystanie z parametrów zapytania może być problematyczne ze względu na ograniczenia długości adresów URL narzucane przez niektóre serwery proxy, a także problemy związane z ich kodowaniem.


Parametry ścieżki HTTP

Parametry ścieżki są podobne do parametrów zapytania, z tą różnicą, że są osadzone w ścieżce zasobów HTTP. Ta metoda wydaje się być dziś korzystna. Istnieją skutki w odniesieniu do buforowania HTTP, ponieważ ścieżka jest tym, co naprawdę definiuje zasób HTTP. Kod wygląda trochę inaczej niż pozostałe, ponieważ adnotacja @Path została zmodyfikowana i używa @PathParam :

@POST
@Path("/create/{param1}/{param2}")
public void create(@PathParam("param1") String param1,
                   @PathParam("param2") String param2) {
    ...
}

Wiadomość jest podobna do wersji parametru zapytania, z tym wyjątkiem, że nazwy parametrów nie są nigdzie zawarte w wiadomości.

POST /create/hello/world HTTP/1.1
Content-Length: 0
Host: www.example.com

Ta metoda ma te same problemy z kodowaniem, co wersja parametru zapytania. Segmenty ścieżek są kodowane w różny sposób, więc również musisz zachować ostrożność.


Jak widać, każda metoda ma swoje wady i zalety. O wyborze najczęściej decydują Twoi klienci. Jeśli wyświetlasz FORMstrony HTML oparte na wyświetlaniu, użyj @FormParam. Jeśli Twoi klienci są oparte na JavaScript + HTML5, prawdopodobnie będziesz chciał użyć serializacji opartej na JAXB i obiektów JSON. W MessageBodyReader/Writerimplementacje powinny dbać o konieczności ucieczki dla Ciebie tak, że jest jeden mniej, co może się nie udać. Jeśli twój klient jest oparty na Javie, ale nie ma dobrego procesora XML (np. Android), prawdopodobnie użyłbym FORMkodowania, ponieważ treść treści jest łatwiejsza do wygenerowania i zakodowania poprawnie niż adresy URL. Miejmy nadzieję, że ten wpis na mini-wiki rzuci trochę światła na różne metody obsługiwane przez JAX-RS.

Uwaga: w celu pełnego ujawnienia, tak naprawdę nie korzystałem jeszcze z tej funkcji Jersey. Majstrowaliśmy przy tym, ponieważ mamy wiele wdrożonych aplikacji JAXB + JAX-RS i przenosimy się do mobilnej przestrzeni klienta. JSON znacznie lepiej pasuje do XML w rozwiązaniach opartych na HTML5 lub jQuery.

D.Shawley
źródło
4
Przetestowałem tę funkcję wczoraj, adnotacje @XmlElement nie były potrzebne
mmatloka
Dzięki za to. Jeśli nadal chcę wysłać 2 ciągi, to czego potrzebuje reszta, aby móc skonsumować? A może wiele parametrów działa tylko z @PathParm?
Klaasvaak
1
@Klaasvaak - musisz określić, skąd ma być wyodrębniony każdy parametr. Jak masz teraz rzeczy, Jersey / NetBeans przyjmuje post formularza i wyodrębnia dane wysłane jako FormParm. Dodaj adnotacje do każdego rozszerzenia metody, określając, skąd mają pochodzić dane (PathParam, FormParam, CookieParam itp.)
Percepcja,
1
@Klaasvaak - Dodałem kilka przykładów przy użyciu różnych adnotacji
D.Shawley,
2
Bardzo dziękuję za to! To było naprawdę to, czego szukałem. Zrobiłeś mój dzień;) Używam teraz FormParams i działa!
Klaasvaak