Cómo acceder a los parámetros en un método RESTful POST

123

Mi método POST se ve así:

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

Cuando creo un Cliente Jersey en Netbeans, el método que llama al método de publicación se ve así:

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

Al ejecutar esta prueba:

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

Da el siguiente resultado en el servidor:

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

¿Qué necesito cambiar para que los parámetros den el valor correcto?

Klaasvaak
fuente
¿Estás usando esto en la aplicación de Android o no?
Android-Droid
Finalmente quiero llamar a este método de publicación en una aplicación de Android. De alguna manera, el servicio web no sabe cómo firmar los valores de los parámetros. Quiero saber cómo hacer esto.
Klaasvaak

Respuestas:

355

Su @POSTmétodo debería aceptar un objeto JSON en lugar de una cadena. Jersey utiliza JAXB para admitir la organización y desarmado de objetos JSON (consulte los documentos de Jersey para más detalles ). Crea una clase como:

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

Entonces su @POSTmétodo se vería así:

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

Este método espera recibir el objeto JSON como el cuerpo de la POST HTTP. JAX-RS pasa el cuerpo del contenido del mensaje HTTP como un parámetro no anotado, inputen este caso. El mensaje real se vería así:

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

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

Usar JSON de esta manera es bastante común por razones obvias. Sin embargo, si lo está generando o consumiendo en algo que no sea JavaScript, entonces debe tener cuidado de escapar adecuadamente de los datos. En JAX-RS, usaría un MessageBodyReader y MessageBodyWriter para implementar esto. Creo que Jersey ya tiene implementaciones para los tipos requeridos (por ejemplo, primitivas Java y clases envueltas JAXB), así como para JSON. JAX-RS admite una serie de otros métodos para pasar datos. Estos no requieren la creación de una nueva clase, ya que los datos se pasan utilizando un argumento simple.


HTML <FORM>

Los parámetros serían anotados usando @FormParam :

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

El navegador codificará el formulario usando "application / x-www-form-urlencoded" . El tiempo de ejecución JAX-RS se encargará de decodificar el cuerpo y pasarlo al método. Esto es lo que debería ver en el cable:

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

El contenido está codificado en URL en este caso.

Si no conoce los nombres de los FormParam, puede hacer lo siguiente:

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

Encabezados HTTP

Puede usar la anotación @HeaderParam si desea pasar parámetros a través de encabezados HTTP:

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

Así es como se vería el mensaje HTTP. Tenga en cuenta que esta POST no tiene cuerpo.

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

No usaría este método para pasar parámetros generalizados. Sin embargo, es realmente útil si necesita acceder al valor de un encabezado HTTP en particular.


Parámetros de consulta HTTP

Este método se usa principalmente con HTTP GET pero es igualmente aplicable a POST. Utiliza la anotación @QueryParam .

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

Al igual que la técnica anterior, pasar parámetros a través de la cadena de consulta no requiere un cuerpo de mensaje. Aquí está el mensaje HTTP:

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

Debe tener especial cuidado para codificar correctamente los parámetros de consulta en el lado del cliente. El uso de parámetros de consulta puede ser problemático debido a las restricciones de longitud de URL impuestas por algunos proxies, así como a los problemas asociados con su codificación.


Parámetros de ruta HTTP

Los parámetros de ruta son similares a los parámetros de consulta, excepto que están incrustados en la ruta de recursos HTTP. Este método parece estar a favor hoy. Hay impactos con respecto al almacenamiento en caché HTTP ya que la ruta es lo que realmente define el recurso HTTP. El código se ve un poco diferente a los demás ya que la anotación @Path se modifica y utiliza @PathParam :

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

El mensaje es similar a la versión del parámetro de consulta, excepto que los nombres de los parámetros no se incluyen en ninguna parte del mensaje.

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

Este método comparte los mismos problemas de codificación que la versión del parámetro de consulta. Los segmentos de ruta se codifican de manera diferente, por lo que también debe tener cuidado.


Como puede ver, hay ventajas y desventajas de cada método. La elección generalmente la deciden sus clientes. Si está sirviendo FORMpáginas HTML basadas en, use @FormParam. Si sus clientes están basados ​​en JavaScript + HTML5, entonces probablemente quiera usar serialización basada en JAXB y objetos JSON. Las MessageBodyReader/Writerimplementaciones deben encargarse del escape necesario para usted, por lo que es una cosa menos que puede salir mal. Si su cliente está basado en Java pero no tiene un buen procesador XML (por ejemplo, Android), entonces probablemente usaría la FORMcodificación ya que un cuerpo de contenido es más fácil de generar y codificar correctamente que las URL. Esperemos que esta entrada mini-wiki arroje algo de luz sobre los diversos métodos que admite JAX-RS.

Nota: en aras de la divulgación completa, todavía no he utilizado esta función de Jersey. Estuvimos jugando con esto ya que tenemos implementadas varias aplicaciones JAXB + JAX-RS y nos estamos moviendo hacia el espacio del cliente móvil. JSON se ajusta mucho mejor que XML en HTML5 o soluciones basadas en jQuery.

D.Shawley
fuente
44
Probé esta función ayer, no se necesitaban anotaciones
@XmlElement
Gracias por esto. Si todavía quiero enviar 2 cadenas, ¿qué necesita el resto para poder consumir? ¿O los parámetros múltiples solo funcionan con @PathParm?
Klaasvaak
1
@Klaasvaak: debe especificar de dónde se espera extraer cada parámetro. Como tiene cosas ahora, Jersey / NetBeans está asumiendo una publicación de formulario y extrayendo los datos enviados como FormParm. Anote cada uno de sus aumentos de método con el lugar desde el que desea los datos (PathParam, FormParam, CookieParam, etc.)
Percepción
1
@Klaasvaak - Agregué un montón de ejemplos usando las diversas anotaciones
D.Shawley
2
muchas gracias por esto! Esto era realmente lo que estaba buscando. Me alegraste el día;) ¡Estoy usando FormParams ahora y funciona!
Klaasvaak