getparameter formulario dinamico java jersey http-post http-request jersey-1.0

java - getparameter - formulario dinamico primefaces



Cómo obtener parámetros de formulario en filtro de solicitud (2)

Asegúrese de que ResourceFilterFactory crea una instancia de ResourceFilter para el método TestResource#execute , que luego crea una instancia ContainerRequestFilter :

public class MyFilterFactory implements ResourceFilterFactory { @Override public List<ResourceFilter> create(final AbstractMethod am) { return new ArrayList<ResourceFilter>() {{ add(new ResourceFilter() { @Override public ContainerRequestFilter getRequestFilter() { return new ContainerRequestFilter() { @Override public ContainerRequest filter(final ContainerRequest request) { System.out.println(request.getFormParameters()); return request; } }; } @Override public ContainerResponseFilter getResponseFilter() { return null; } }); }}; } }

A partir de la trace que ha proporcionado, no estoy seguro de si se llama a su ContainerRequestFilter . Debería haber un encabezado de rastreo más que contenga algo como esto:

→matched message body reader: class com.sun.jersey.api.representation.Form, "application/x-www-form-urlencoded" -> com.sun.jersey.core.impl.provider.entity.FormProvider@b98df1f

Todo el rastro de mi prueba:

HTTP/1.1 201 Created Location: http://localhost:8080/helloworld-webapp/helloworld/ Content-Type: text/plain X-Jersey-Trace-000: accept root resource classes: "/helloworld" X-Jersey-Trace-001: match path "/helloworld" -> "/application/.wadl(/.*)?", "/helloworld(/.*)?" X-Jersey-Trace-002: accept right hand path java.util.regex.Matcher[pattern=/helloworld(/.*)? region=0,11 lastmatch=/helloworld]: "/helloworld" -> "/helloworld" : "" X-Jersey-Trace-003: accept resource: "helloworld" -> @Path("/helloworld") com.sun.jersey.samples.helloworld.resources.HelloWorldResource@7449df0f X-Jersey-Trace-004: match path "" -> "" X-Jersey-Trace-005: accept resource methods: "helloworld", POST -> com.sun.jersey.samples.helloworld.resources.HelloWorldResource@7449df0f X-Jersey-Trace-006: matched resource method: public javax.ws.rs.core.Response com.sun.jersey.samples.helloworld.resources.HelloWorldResource.execute(java.lang.String,java.lang.String) X-Jersey-Trace-007: matched message body reader: class com.sun.jersey.api.representation.Form, "application/x-www-form-urlencoded" -> com.sun.jersey.core.impl.provider.entity.FormProvider@6bc1b916 X-Jersey-Trace-008: matched message body reader: class com.sun.jersey.api.representation.Form, "application/x-www-form-urlencoded" -> com.sun.jersey.core.impl.provider.entity.FormProvider@6bc1b916 X-Jersey-Trace-009: matched message body writer: java.lang.String@f62, "text/plain" -> com.sun.jersey.core.impl.provider.entity.StringProvider@4aae6c4e Transfer-Encoding: chunked Server: Jetty(6.1.24)

EDIT 1:

Habilitar solicitud LoggingFilter :

<init-param> <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name> <param-value>com.sun.jersey.api.container.filter.LoggingFilter</param-value> </init-param>

EDICION 2:

También asegúrese de que ningún otro filtro Servlet o Jersey haya leído antes el InputStream . En tal caso, la corriente de entrada de la entidad puede dejar de estar disponible (pero aún puede inyectar @FormParam en su método de recursos, como en este caso).

Estoy tratando de obtener los parámetros de formulario de una solicitud en un filtro de solicitud:

@Override public ContainerRequest filter(final ContainerRequest request) { final Form formParameters = request.getFormParameters(); //logic return request; }

Sin embargo, la forma siempre parece estar vacía. La documentación HttpRequestContext.getFormParameters() dice:

Obtenga los parámetros de formulario de la entidad de solicitud.

Este método asegurará que la entidad de solicitud esté protegida de manera que la aplicación pueda consumirla.

Devuelve: los parámetros del formulario, si hay una entidad de solicitud y el tipo de contenido es "application / x-www-form-urlencoded", de lo contrario se devolverá una instancia que no contenga ningún parámetro.

Mi recurso está anotado con @Consumes("application/x-www-form-urlencoded") , aunque no se haya emparejado hasta después del filtro de solicitud. ¿Es por eso que esto no funciona?

Intenté investigar un poco, pero no pude encontrar ninguna prueba concluyente de si esto es posible. Hubo una discusión de 4 años en la que Paul Sandoz dice:

Si está trabajando en filtros Jersey o con HttpRequestContext puede obtener los parámetros de formulario de la siguiente manera: [enlace roto a Jersey 1.1.1 HttpRequestContext.getFormParameters ]

También encontré esta discusión de hace 3 años sobre cómo obtener campos de formulario multipart / form-data en un filtro de solicitud. En él, Paul Sandoz usa el siguiente código:

// Buffer InputStream in = request.getEntityInputStream(); if (in.getClass() != ByteArrayInputStream.class) { // Buffer input ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { ReaderWriter.writeTo(in, baos); } catch (IOException ex) { throw new ContainerException(ex); } in = new ByteArrayInputStream(baos.toByteArray()); request.setEntityInputStream(in); } // Read entity FormDataMultiPart multiPart = request.getEntity(FormDataMultiPart.class);

Intenté emular ese enfoque para Form lugar, pero el resultado de request.getEntityInputStream() siempre es una transmisión vacía. Y al ver el origen de getFormParameters , ese método ya está haciendo lo mismo:

@Override public Form getFormParameters() { if (MediaTypes.typeEquals(MediaType.APPLICATION_FORM_URLENCODED_TYPE, getMediaType())) { InputStream in = getEntityInputStream(); if (in.getClass() != ByteArrayInputStream.class) { // Buffer input ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { ReaderWriter.writeTo(in, byteArrayOutputStream); } catch (IOException e) { throw new IllegalArgumentException(e); } in = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); setEntityInputStream(in); } ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream) in; Form f = getEntity(Form.class); byteArrayInputStream.reset(); return f; } else { return new Form(); } }

No puedo descifrar qué está sorbiendo el flujo de entrada de entidad antes de llegar a él. Algo en Jersey debe consumirlo porque los parámetros de forma se pasan luego al método de recursos. ¿Qué estoy haciendo mal aquí, o es esto imposible (y por qué)?

EDITAR: Aquí hay un ejemplo de una solicitud que se envía:

POST /test/post-stuff HTTP/1.1 Host: local.my.application.com:8443 Cache-Control: no-cache Content-Type: application/x-www-form-urlencoded form_param_1=foo&form_param_2=bar

Aquí está el registro de solicitudes (algo redundante):

INFO: 1 * Server in-bound request 1 > POST https://local.my.application.com:8443/test/post-stuff 1 > host: local.my.application.com:8443 1 > connection: keep-alive 1 > content-length: 33 1 > cache-control: no-cache 1 > origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm 1 > user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 1 > content-type: application/x-www-form-urlencoded 1 > accept: */* 1 > accept-encoding: gzip,deflate,sdch 1 > accept-language: en-US,en;q=0.8 1 > cookie: [omitted] 1 >

Aquí están los encabezados de respuesta de esa solicitud, incluido el rastro de Jersey :

Content-Type →application/json;charset=UTF-8 Date →Fri, 09 Aug 2013 18:00:17 GMT Location →https://local.my.application.com:8443/test/post-stuff/ Server →Apache-Coyote/1.1 Transfer-Encoding →chunked X-Jersey-Trace-000 →accept root resource classes: "/post-stuff" X-Jersey-Trace-001 →match path "/post-stuff" -> "/post/-stuff(/.*)?", [...], "(/.*)?" X-Jersey-Trace-002 →accept right hand path java.util.regex.Matcher[pattern=/post/-stuff(/.*)? region=0,11 lastmatch=/post-stuff]: "/post-stuff" -> "/post-stuff" : "" X-Jersey-Trace-003 →accept resource: "post-stuff" -> @Path("/post-stuff") com.application.my.jersey.resource.TestResource@7612e9d2 X-Jersey-Trace-004 →match path "" -> "" X-Jersey-Trace-005 →accept resource methods: "post-stuff", POST -> com.application.my.jersey.resource.TestResource@7612e9d2 X-Jersey-Trace-006 →matched resource method: public javax.ws.rs.core.Response com.application.my.jersey.resource.TestResource.execute(java.lang.String,java.lang.String) X-Jersey-Trace-007 →matched message body reader: class com.sun.jersey.api.representation.Form, "application/x-www-form-urlencoded" -> com.sun.jersey.core.impl.provider.entity.FormProvider@b98df1f X-Jersey-Trace-008 →matched message body writer: java.lang.String@f62, "application/json" -> com.sun.jersey.core.impl.provider.entity.StringProvider@1c5ddffa

Aquí está la configuración del servlet (nada especial):

<servlet> <servlet-name>jersey</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.application.my.jersey</param-value> </init-param> <init-param> <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name> <param-value>com.application.my.jersey.MyFilterFactory</param-value> </init-param> <init-param> <param-name>com.sun.jersey.config.feature.Trace</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>

Aquí está el recurso de ejemplo:

@Path("/post-stuff") @Produces(MediaType.APPLICATION_JSON) public final class TestResource { @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response execute( @FormParam("form_param_1") final String formParam1, @FormParam("form_param_2") final String formParam2 ) { return Response.created(URI.create("/")).entity("{}").build(); } }

Estoy usando Jersey 1.17.

Para aquellos interesados, estoy tratando de rodar mi propia validación de parámetros requerida, como se describe en JERSEY-351 . Mi solución aquí funciona para query, cookie y params de encabezado, los parámetros de formulario me están imposibilitando.


Esto fue complicado. Quité otros filtros de Jersey para eliminarlos del problema, pero olvidé un filtro de servlet plano que se oculta en la parte inferior de web.xml :

<filter> <filter-name>myFilter</filter-name> <filter-class>com.application.my.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

La eliminación de este filtro solucionó el problema: los parámetros de formulario aparecían en el filtro Jersey. ¿Pero por qué? Cavé más profundo, reduciendo el problema a una sola declaración en MyFilter :

request.getParameter("some_param")

Traté de simplificar el problema aún más eliminando MyFilter y haciendo la misma llamada en el filtro Jersey (mediante la inyección de HttpServletRequest ), pero los parámetros del formulario aún aparecían. El problema parece ocurrir específicamente al llamar a getParameter en la instancia de org.apache.catalina.connector.RequestFacade que pasa a javax.servlet.Filter.doFilter . Entonces, ¿esto es, de hecho, un error de Tomcat?

La documentación de ServletRequest.getParameter dice:

Si los datos del parámetro se enviaron en el cuerpo de la solicitud, como ocurre con una solicitud HTTP POST, leer el cuerpo directamente a través de getInputStream() o getReader() puede interferir con la ejecución de este método.

Entonces, ¿quizás lo contrario también es cierto? ¿Que la llamada getParameter podría interferir con la corriente de entrada de la entidad? No está claro si el contrato del método permite este comportamiento, y si indica un error en Tomcat, Jersey o ninguno.

De todos modos, ese viejo filtro en realidad no era necesario, así que mi problema se solucionó, solo lo eliminé.

Aquí hay una reproducción completa del problema (Tomcat 7.0):

web.xml :

<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>test</display-name> <servlet> <servlet-name>jersey</servlet-name> <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class> <init-param> <param-name>com.sun.jersey.config.property.packages</param-name> <param-value>com.application.my</param-value> </init-param> <init-param> <param-name>com.sun.jersey.spi.container.ResourceFilters</param-name> <param-value>com.application.my.TestFilterFactory</param-value> </init-param> <init-param> <param-name>com.sun.jersey.config.feature.Trace</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> <filter> <filter-name>servletFilter</filter-name> <filter-class>com.application.my.TestServletFilter</filter-class> </filter> <filter-mapping> <filter-name>servletFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>

TestServletFilter.java :

package com.application.my; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public final class TestServletFilter implements Filter { @Override public void init(FilterConfig config) { } @Override public void doFilter( final ServletRequest request, final ServletResponse response, final FilterChain chain ) throws IOException, ServletException { System.out.println("calling getParameter on " + request.getClass().getName()); request.getParameter("blah"); chain.doFilter(request, response); } @Override public void destroy() { } }

TestFilterFactory.java :

package com.application.my; import java.util.Collections; import java.util.List; import com.sun.jersey.api.model.AbstractMethod; import com.sun.jersey.spi.container.ContainerRequest; import com.sun.jersey.spi.container.ContainerRequestFilter; import com.sun.jersey.spi.container.ContainerResponseFilter; import com.sun.jersey.spi.container.ResourceFilter; import com.sun.jersey.spi.container.ResourceFilterFactory; public final class TestFilterFactory implements ResourceFilterFactory { @Override public List<ResourceFilter> create(final AbstractMethod method) { return Collections.<ResourceFilter>singletonList(new ResourceFilter() { @Override public ContainerRequestFilter getRequestFilter() { return new ContainerRequestFilter() { @Override public ContainerRequest filter(final ContainerRequest request) { System.out.println("form: " + request.getFormParameters()); return request; } }; } @Override public ContainerResponseFilter getResponseFilter() { return null; } }); } }

TestResource.java :

package com.application.my; import java.net.URI; import javax.ws.rs.Consumes; import javax.ws.rs.FormParam; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path("/post-stuff") @Produces(MediaType.APPLICATION_JSON) public final class TestResource { @POST @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public Response execute( @FormParam("form_param_1") final String formParam1, @FormParam("form_param_2") final String formParam2 ) { System.out.println("form param_1: " + formParam1); System.out.println("form param_2: " + formParam2); return Response.created(URI.create("/")).entity("{}").build(); } }