Comment accéder aux paramètres dans une méthode POST RESTful

123

Ma méthode POST ressemble à ceci:

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

Lorsque je crée un client Jersey dans Netbeans, la méthode qui appelle la méthode post ressemble à ceci:

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

Lors de l'exécution de ce test:

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

Il donne la sortie suivante sur le serveur:

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

Que dois-je changer pour que les paramètres donnent la valeur correcte?

Klaasvaak
la source
utilisez-vous cela sur une application Android ou non?
Android-Droid
Je veux enfin appeler cette méthode de publication dans une application Android. D'une manière ou d'une autre, le service Web ne sait pas comment signer les valeurs des paramètres. Je veux savoir comment faire cela.
Klaasvaak

Réponses:

356

Votre @POSTméthode doit accepter un objet JSON au lieu d'une chaîne. Jersey utilise JAXB pour prendre en charge le marshaling et le démarshaling des objets JSON (voir la documentation de Jersey pour plus de détails ). Créez une classe comme:

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

Ensuite, votre @POSTméthode ressemblerait à ceci:

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

Cette méthode s'attend à recevoir l'objet JSON en tant que corps du HTTP POST. JAX-RS transmet le corps du contenu du message HTTP en tant que paramètre non annoté - inputdans ce cas. Le message réel ressemblerait à quelque chose comme:

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

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

Utiliser JSON de cette manière est assez courant pour des raisons évidentes. Cependant, si vous le générez ou le consommez dans autre chose que JavaScript, vous devez faire attention à échapper correctement aux données. Dans JAX-RS, vous utiliseriez un MessageBodyReader et MessageBodyWriter pour l'implémenter. Je crois que Jersey a déjà des implémentations pour les types requis (par exemple, les primitives Java et les classes enveloppées JAXB) ainsi que pour JSON. JAX-RS prend en charge un certain nombre d'autres méthodes de transmission de données. Celles-ci ne nécessitent pas la création d'une nouvelle classe car les données sont transmises en utilisant un simple passage d'arguments.


HTML <FORM>

Les paramètres seraient annotés à l'aide de @FormParam :

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

Le navigateur encodera le formulaire en utilisant "application / x-www-form-urlencoded" . Le runtime JAX-RS se chargera de décoder le corps et de le transmettre à la méthode. Voici ce que vous devriez voir sur le fil:

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

Le contenu est encodé en URL dans ce cas.

Si vous ne connaissez pas les noms des FormParam, vous pouvez effectuer les opérations suivantes:

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

En-têtes HTTP

Vous pouvez utiliser l' annotation @HeaderParam si vous souhaitez passer des paramètres via des en-têtes HTTP:

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

Voici à quoi ressemblerait le message HTTP. Notez que ce POST n'a pas de corps.

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

Je n'utiliserais pas cette méthode pour le passage de paramètres généralisés. C'est vraiment pratique si vous avez besoin d'accéder à la valeur d'un en-tête HTTP particulier.


Paramètres de requête HTTP

Cette méthode est principalement utilisée avec les HTTP GET, mais elle est également applicable aux POST. Il utilise l' annotation @QueryParam .

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

Comme la technique précédente, le passage de paramètres via la chaîne de requête ne nécessite pas de corps de message. Voici le message HTTP:

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

Vous devez être particulièrement prudent pour encoder correctement les paramètres de requête côté client. L'utilisation des paramètres de requête peut être problématique en raison des restrictions de longueur d'URL imposées par certains proxys ainsi que des problèmes associés à leur codage.


Paramètres de chemin HTTP

Les paramètres de chemin sont similaires aux paramètres de requête, sauf qu'ils sont intégrés dans le chemin de la ressource HTTP. Cette méthode semble être en faveur aujourd'hui. Il y a des impacts en ce qui concerne la mise en cache HTTP puisque le chemin est ce qui définit vraiment la ressource HTTP. Le code est un peu différent des autres puisque l' annotation @Path est modifiée et utilise @PathParam :

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

Le message est similaire à la version du paramètre de requête, sauf que les noms des paramètres ne sont inclus nulle part dans le message.

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

Cette méthode partage les mêmes problèmes de codage que la version du paramètre de requête. Les segments de chemin sont codés différemment , vous devez donc y faire attention également.


Comme vous pouvez le voir, chaque méthode présente des avantages et des inconvénients. Le choix est généralement décidé par vos clients. Si vous FORMdiffusez des pages HTML, utilisez @FormParam. Si vos clients sont basés sur JavaScript + HTML5, vous souhaiterez probablement utiliser la sérialisation basée sur JAXB et les objets JSON. Les MessageBodyReader/Writerimplémentations doivent prendre en charge les échappements nécessaires pour vous afin que ce soit une chose de moins qui puisse mal tourner. Si votre client est basé sur Java mais n'a pas un bon processeur XML (par exemple, Android), j'utiliserais probablement l' FORMencodage car un corps de contenu est plus facile à générer et à encoder correctement que les URL. Espérons que cette entrée mini-wiki jette un éclairage sur les différentes méthodes prises en charge par JAX-RS.

Remarque: dans l'intérêt d'une divulgation complète, je n'ai pas encore utilisé cette fonctionnalité de Jersey. Nous le bricolions depuis que nous avons déployé un certain nombre d'applications JAXB + JAX-RS et que nous entrons dans l'espace client mobile. JSON est un bien meilleur ajustement que XML sur les solutions HTML5 ou jQuery.

D.Shawley
la source
4
J'ai testé cette fonctionnalité hier, les annotations @XmlElement n'étaient pas nécessaires
mmatloka
Merci pour cela. Si je veux toujours envoyer 2 chaînes, qu'est-ce que le reste a besoin pour pouvoir consommer? Ou est-ce que plusieurs paramètres fonctionnent uniquement avec @PathParm?
Klaasvaak
1
@Klaasvaak - vous devez spécifier où chaque paramètre doit être extrait. Comme vous l'avez fait maintenant, Jersey / NetBeans assume un post de formulaire et extrait les données envoyées sous forme de FormParm. Annotez chacune de vos augmentations de méthode avec l'endroit où vous voulez les données (PathParam, FormParam, CookieParam, etc.)
Perception
1
@Klaasvaak - J'ai ajouté un tas d'exemples en utilisant les différentes annotations
D.Shawley
2
Merci beaucoup pour cela! C'était vraiment ce que je cherchais. Vous avez fait ma journée;) J'utilise FormParams maintenant et ça marche!
Klaasvaak