Zugriff auf Parameter in einer RESTful POST-Methode

123

Meine POST-Methode sieht folgendermaßen aus:

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

Wenn ich einen Jersey-Client in Netbeans erstelle, sieht die Methode, die die Post-Methode aufruft, folgendermaßen aus:

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

Wenn Sie diesen Test ausführen:

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

Es gibt die folgende Ausgabe auf dem Server:

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

Was muss ich ändern, damit die Parameter den richtigen Wert ergeben?

Klaasvaak
quelle
Verwenden Sie dies auf Android-Anwendung oder nicht?
Android-Droid
Ich möchte diese Post-Methode endlich in einer Android-App aufrufen. Irgendwie weiß der Webservice nicht, wie er die Werte für die Parameter signieren soll. Ich möchte wissen, wie das geht.
Klaasvaak

Antworten:

355

Ihre @POSTMethode sollte ein JSON-Objekt anstelle einer Zeichenfolge akzeptieren. Jersey verwendet JAXB, um das Marshalling und Unmarshaling von JSON-Objekten zu unterstützen ( Einzelheiten finden Sie in den Trikotdokumenten ). Erstellen Sie eine Klasse wie:

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

Dann würde Ihre @POSTMethode wie folgt aussehen:

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

Diese Methode erwartet, dass das JSON-Objekt als Hauptteil des HTTP-POST empfangen wird. JAX-RS übergibt den Inhaltskörper der HTTP-Nachricht als nicht kommentierten Parameter - inputin diesem Fall. Die eigentliche Nachricht würde ungefähr so ​​aussehen:

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

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

Die Verwendung von JSON auf diese Weise ist aus offensichtlichen Gründen weit verbreitet. Wenn Sie es jedoch in etwas anderem als JavaScript generieren oder verwenden, müssen Sie vorsichtig sein, um den Daten ordnungsgemäß zu entkommen. In JAX-RS würden Sie einen MessageBodyReader und einen MessageBodyWriter verwenden , um dies zu implementieren. Ich glaube, dass Jersey bereits Implementierungen für die erforderlichen Typen (z. B. Java-Grundelemente und JAXB-umhüllte Klassen) sowie für JSON hat. JAX-RS unterstützt eine Reihe anderer Methoden zum Übergeben von Daten. Diese erfordern nicht die Erstellung einer neuen Klasse, da die Daten mithilfe einer einfachen Argumentübergabe übergeben werden.


HTML <FORM>

Die Parameter würden mit @FormParam kommentiert :

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

Der Browser verschlüsselt das Formular mit "application / x-www-form-urlencoded" . Die JAX-RS-Laufzeit sorgt dafür, dass der Body dekodiert und an die Methode übergeben wird. Folgendes sollten Sie auf dem Draht sehen:

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

Der Inhalt ist in diesem Fall URL-codiert .

Wenn Sie die Namen der FormParam nicht kennen, können Sie Folgendes tun:

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

HTTP-Header

Sie können die Annotation @HeaderParam verwenden, wenn Sie Parameter über HTTP-Header übergeben möchten:

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

So würde die HTTP-Nachricht aussehen. Beachten Sie, dass dieser POST keinen Body hat.

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

Ich würde diese Methode nicht für die allgemeine Parameterübergabe verwenden. Dies ist sehr praktisch, wenn Sie auf den Wert eines bestimmten HTTP-Headers zugreifen müssen.


HTTP-Abfrageparameter

Diese Methode wird hauptsächlich bei HTTP-GETs verwendet, gilt jedoch auch für POSTs. Es wird die Annotation @QueryParam verwendet .

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

Wie bei der vorherigen Technik ist für die Übergabe von Parametern über die Abfragezeichenfolge kein Nachrichtentext erforderlich. Hier ist die HTTP-Nachricht:

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

Sie müssen besonders vorsichtig sein, um die Abfrageparameter auf der Clientseite ordnungsgemäß zu codieren . Die Verwendung von Abfrageparametern kann aufgrund von URL-Längenbeschränkungen, die von einigen Proxys erzwungen werden, sowie Problemen bei der Codierung problematisch sein.


HTTP-Pfadparameter

Pfadparameter ähneln Abfrageparametern, sind jedoch in den HTTP-Ressourcenpfad eingebettet. Diese Methode scheint heute zu sprechen. Es gibt Auswirkungen in Bezug auf das HTTP-Caching, da der Pfad die HTTP-Ressource wirklich definiert. Der Code sieht etwas anders aus als die anderen, da die Annotation @Path geändert wurde und @PathParam verwendet wird :

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

Die Nachricht ähnelt der Version der Abfrageparameter, außer dass die Namen der Parameter an keiner Stelle in der Nachricht enthalten sind.

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

Diese Methode hat dieselben Codierungsprobleme wie die Version des Abfrageparameters. Pfadsegmente sind unterschiedlich codiert, daher müssen Sie auch dort vorsichtig sein.


Wie Sie sehen können, hat jede Methode Vor- und Nachteile. Die Wahl wird normalerweise von Ihren Kunden entschieden. Wenn Sie FORMHTML-Seiten auf Basis bereitstellen, verwenden Sie @FormParam. Wenn Ihre Clients auf JavaScript + HTML5 basieren, möchten Sie wahrscheinlich JAXB-basierte Serialisierungs- und JSON-Objekte verwenden. Die MessageBodyReader/WriterImplementierungen sollten sich um das notwendige Entkommen für Sie kümmern, damit eine Sache weniger schief gehen kann. Wenn Ihr Client Java-basiert ist, aber keinen guten XML-Prozessor hat (z. B. Android), würde ich wahrscheinlich die FORMCodierung verwenden , da ein Inhaltskörper einfacher zu generieren und ordnungsgemäß zu codieren ist als URLs. Hoffentlich beleuchtet dieser Mini-Wiki-Eintrag die verschiedenen Methoden, die JAX-RS unterstützt.

Hinweis: Im Interesse einer vollständigen Offenlegung habe ich diese Funktion von Jersey noch nicht verwendet. Wir haben daran herumgebastelt, da wir eine Reihe von JAXB + JAX-RS-Anwendungen bereitgestellt haben und in den mobilen Client-Bereich ziehen. JSON passt viel besser als XML auf HTML5- oder jQuery-basierte Lösungen.

D. Shawley
quelle
4
Ich habe diese Funktion gestern getestet, @XmlElement-Anmerkungen wurden nicht benötigt
mmatloka
Danke dafür. Wenn ich immer noch 2 Strings senden möchte, was muss der Restfull dann verbrauchen können? Oder funktionieren mehrere Parameter nur mit @PathParm?
Klaasvaak
1
@Klaasvaak - Sie müssen angeben, woher die einzelnen Parameter extrahiert werden sollen. Wie Sie jetzt wissen, übernimmt Jersey / NetBeans einen Formularbeitrag und extrahiert die als FormParm gesendeten Daten. Kommentieren Sie jede Ihrer Methodenerweiterungen mit der Stelle, von der Sie die Daten erhalten möchten (PathParam, FormParam, CookieParam usw.)
Wahrnehmung
1
@Klaasvaak - Ich habe eine Reihe von Beispielen mit den verschiedenen Anmerkungen
hinzugefügt
2
Vielen Dank dafür! Das war wirklich das, wonach ich gesucht habe. Du hast meinen Tag gemacht;) Ich benutze jetzt die FormParams und es funktioniert!
Klaasvaak