Como acessar parâmetros em um método RESTful POST

123

Meu método POST fica assim:

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

Quando eu crio um cliente Jersey no Netbeans, o método que chama o método post fica assim:

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

Ao executar este teste:

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

Ele fornece a seguinte saída no servidor:

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

O que preciso alterar para que os parâmetros estejam fornecendo o valor correto?

Klaasvaak
fonte
você está usando isso no aplicativo Android ou não?
Android-Droid
Finalmente, quero chamar esse método de postagem em um aplicativo Android. De alguma forma, o serviço da web não sabe como assinar os valores para os parâmetros. Eu quero saber como fazer isso.
precisa saber é o seguinte

Respostas:

355

Seu @POSTmétodo deve estar aceitando um objeto JSON em vez de uma sequência. Jersey usa JAXB para suportar objetos JSON de empacotamento e desempacotamento (consulte os documentos de jersey para obter detalhes ). Crie uma classe como:

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

Em seguida, seu @POSTmétodo seria semelhante ao seguinte:

@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 receber o objeto JSON como o corpo do HTTP POST. O JAX-RS transmite o corpo do conteúdo da mensagem HTTP como um parâmetro não anotado - inputneste caso. A mensagem real seria algo como:

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

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

Usar o JSON dessa maneira é bastante comum por razões óbvias. No entanto, se você o estiver gerando ou consumindo em algo que não seja JavaScript, será necessário ter cuidado para escapar adequadamente dos dados. No JAX-RS, você usaria um MessageBodyReader e MessageBodyWriter para implementar isso. Acredito que Jersey já tenha implementações para os tipos necessários (por exemplo, primitivas Java e classes empacotadas JAXB), bem como para JSON. O JAX-RS suporta vários outros métodos para transmitir dados. Isso não requer a criação de uma nova classe, pois os dados são passados ​​usando a simples passagem de argumentos.


HTML <FORM>

Os parâmetros seriam anotados usando @FormParam :

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

O navegador codificará o formulário usando "application / x-www-form-urlencoded" . O tempo de execução do JAX-RS cuidará da decodificação do corpo e da transmissão ao método. Aqui está o que você deve ver no fio:

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

O conteúdo é URL codificado neste caso.

Se você não souber os nomes dos FormParam's, poderá fazer o seguinte:

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

Cabeçalhos HTTP

Você pode usar a anotação @HeaderParam se desejar passar parâmetros através de cabeçalhos HTTP:

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

Aqui está a aparência da mensagem HTTP. Observe que este POST não possui um corpo.

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

Eu não usaria esse método para a passagem generalizada de parâmetros. É realmente útil se você precisar acessar o valor de um cabeçalho HTTP específico.


Parâmetros de consulta HTTP

Esse método é usado principalmente com HTTP GETs, mas é igualmente aplicável aos POSTs. Ele usa a anotação @QueryParam .

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

Como a técnica anterior, a passagem de parâmetros pela cadeia de consulta não requer um corpo da mensagem. Aqui está a mensagem HTTP:

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

Você precisa ter um cuidado especial para codificar corretamente os parâmetros de consulta no lado do cliente. O uso de parâmetros de consulta pode ser problemático devido a restrições de tamanho de URL impostas por alguns proxies, além de problemas associados à codificação deles.


Parâmetros do caminho HTTP

Os parâmetros do caminho são semelhantes aos parâmetros da consulta, exceto que eles estão incorporados no caminho do recurso HTTP. Este método parece estar a favor hoje. Há impactos com relação ao cache HTTP, pois o caminho é o que realmente define o recurso HTTP. O código parece um pouco diferente dos outros, pois a anotação @Path é modificada e usa @PathParam :

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

A mensagem é semelhante à versão do parâmetro de consulta, exceto que os nomes dos parâmetros não estão incluídos em nenhum lugar da mensagem.

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

Este método compartilha os mesmos problemas de codificação que a versão do parâmetro de consulta. Os segmentos de caminho são codificados de maneira diferente, portanto você também deve ter cuidado.


Como você pode ver, existem prós e contras em cada método. A escolha geralmente é decidida pelos seus clientes. Se você estiver servindo FORMpáginas HTML baseadas em, use @FormParam. Se seus clientes forem baseados em JavaScript + HTML5, provavelmente você desejará usar serialização baseada em JAXB e objetos JSON. As MessageBodyReader/Writerimplementações devem cuidar do escape necessário para você, para que seja menos uma coisa que pode dar errado. Se o seu cliente é baseado em Java, mas não possui um bom processador XML (por exemplo, Android), provavelmente usaria a FORMcodificação, já que um corpo de conteúdo é mais fácil de gerar e codificar adequadamente do que os URLs. Esperamos que esta entrada do mini-wiki mostre alguma luz sobre os vários métodos que o JAX-RS suporta.

Nota: no interesse da divulgação completa, ainda não usei esse recurso de Jersey. Estávamos mexendo nisso, pois temos vários aplicativos JAXB + JAX-RS implementados e estamos migrando para o espaço do cliente móvel. JSON é muito mais adequado que XML em soluções baseadas em HTML5 ou jQuery.

D.Shawley
fonte
4
Testei esse recurso ontem, as anotações @XmlElement não
eram
Obrigado por isso. Se eu ainda quiser enviar 2 Strings, o que o restante precisa ser capaz de consumir? Ou vários parâmetros só funcionam com o @PathParm?
Klaasvaak
1
@Klaasvaak - você precisa especificar de onde cada parâmetro deve ser extraído. Como você já sabe, o Jersey / NetBeans está assumindo uma postagem de formulário e extraindo os dados enviados como um FormParm. Anote cada um dos seus aumenta método com onde você quer os dados a partir de (PathParam, FormParam, CookieParam etc)
Percepção
1
@Klaasvaak - Adicionei um monte de exemplos usando as várias anotações
D.Shawley
2
Muito obrigado por isso! Era realmente o que eu estava procurando. Você fez o meu dia;) Estou usando o FormParams agora e funciona!
Klaasvaak