¿Cómo enviar programáticamente una solicitud POST a la página JSF sin usar el formulario HTML?

Tengo un frijol JSF muy simple como se muestra a continuación:

import org.jboss.seam.annotations.Name;

@Name(Sample.NAME)
public class Sample {

    public static final String NAME="df";

    private String text = "text-test";

    public void sampleM(){
        System.out.println("Test: "+text);
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

Y el formulario JSF conectado con este componente:

<h:form id="sampleForm">
        <h:commandButton id="sampleButton" action="#{df.sampleM()}" value="ok" />
</h:form>

Ahora, me gustaría enviar mediante programación una solicitud POST a este formulario.

Según mi investigación, la clave aquí son los parámetros POST. Si se selecciona correctamente, se obtienen los resultados adecuados (la cadena 'Test: text-test' se imprime en la consola del servidor).

Entonces la pregunta es: ¿Cómo debo seleccionar los datos POST que eran correctos?

El formulario JSF que se muestra arriba produce este formulario HTML:

<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="sampleForm" value="sampleForm" />
    <input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
    <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>

Así que estos parámetros son correctos.

Pero, ¿cómo puedo saber qué parámetros (nombre y valor) serán suficientes para cualquier otro componente?

Por ejemplo: cuando envío datos POST de la misma manera que en el formulario HTML que se muestra pero con un valor de parámetro 'javax.faces.ViewState' diferente, el método del componente no se ejecutará.

preguntado el 29 de agosto de 12 a las 11:08

1 Respuestas

Entiendo que básicamente está preguntando cómo enviar un formulario JSF mediante programación utilizando algún cliente HTTP como java.net.URLConnection o Apache HttpComponents Client, ¿verdad?

Primero debe enviar una solicitud GET y asegurarse de mantener la misma sesión HTTP (básicamente, el JSESSIONID cookie) a través de las solicitudes. Deje que su cliente HTTP extraiga el Set-Cookie encabezado de la respuesta de la primera solicitud GET, obtenga el JSESSIONID cookie de él y enviarlo de vuelta como Cookie encabezado de solicitudes POST posteriores. Esto mantendrá la sesión HTTP en el lado del servidor; de lo contrario, JSF la tratará como una "Ver caducado" que puede devolver una página de error HTTP 500 en una aplicación web JSF configurada decentemente con ViewExpiredException, o en una aplicación web JSF mal configurada, se comportan como una actualización de página.

Como parte de la naturaleza con estado de JSF y la prevención implícita de ataques CSRF, los formularios deben enviarse con un javax.faces.ViewState valor como el cliente se ha recuperado en la solicitud GET inicial. También debe asegurarse de enviar el name=value par de todos los demás campos ocultos y, en particular, el del botón Enviar también.

Entonces, si su solicitud GET inicial le devuelve este HTML

<form id="sampleForm" name="sampleForm" method="post" action="/pages/main/main.smnet" enctype="application/x-www-form-urlencoded">
    <input type="hidden" name="sampleForm" value="sampleForm" />
    <input id="sampleForm:sampleButton" type="submit" name="sampleForm:sampleButton" value="ok" />
    <input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="j_id65" autocomplete="off" />
</form>

entonces necesitas analizarlo (sopa puede ser útil en esto) y extraiga los siguientes parámetros de solicitud:

  • sampleForm=sampleForm
  • sampleForm:sampleButton=ok
  • javax.faces.ViewState=j_id65

Finalmente envíe una solicitud POST en /pages/main/main.smnet con exactamente esos parámetros de solicitud (y el JSESSIONID ¡Galleta!). Sin embargo, tenga cuidado, es posible que un (pobre) desarrollador de JSF se haya saltado, por ejemplo id="sampleButton" from the <h:commandButton> y luego JSF generaría automáticamente uno que se parece a este formato sampleForm:j_id42. No puede codificarlos ya que el valor puede cambiar según la posición del componente en el árbol del lado del servidor y luego realmente necesitaría analizarlo para obtener el HTML obtenido.

No obstante, es aconsejable ponerse en contacto con el propietario/administrador del sitio y preguntar si no hay una API de servicio web disponible para la tarea que tenía en mente. Un sitio web Java EE decente que usa una aplicación JSF para una interfaz HTML generalmente también usa una aplicación JAX-RS separada para una interfaz REST. Es mucho más fácil y confiable extraer información a través de una API de servicio web de este tipo que raspar un documento HTML.

Ver también:

Respondido el 11 de enero de 22 a las 15:01

Básicamente, me gustaría tener acceso a los componentes de JSF y al ciclo de vida de JSF sin usar formularios HTML y páginas HTML. ¿Es posible? Supongamos que el JSESSIONID es conocida. ¿Puedo pedirle al servidor que sea válido? javax.faces.ViewState valor de alguna manera? ¿Quizás haya otra forma de obtener acceso a los componentes JSF? - pwoz

No. JSF es un marco MVC basado en la web que tiene como objetivo generar aplicaciones basadas en formularios HTML, no es un marco de servicio web. Si ese sitio web JSF está bajo su control total, entonces básicamente está utilizando la herramienta incorrecta para el trabajo. Cree un servicio web en su lugar (incluso puede ejecutarlo junto con JSF). La API Java EE ofrece las API JAX-RS (RESTful) y JAX-WS (SOAP) para esto. Si ese sitio web de JSF no está bajo su control total, comuníquese con el administrador y pregunte si no hay un servicio web disponible. - BalusC

Entonces, no hay forma de generar tal escenario: tengo una aplicación JSF y varios servicios web (todos en el mismo servidor en una aplicación). Cuando la solicitud llega al método del servicio web, este método usa el objeto almacenado en JSF application scope (no hay necesidad de consultar la base de datos) ? - pwoz

El alcance de la aplicación JSF está debajo de las cubiertas solo representado por atributos de ServletContext. Si el servicio web se ejecuta en la misma aplicación web y contenedor, seguramente tiene acceso a la misma ServletContext instancia y por lo tanto también todos sus atributos. - BalusC

Por favor, @balusC, ¿puede responder esta pregunta? stackoverflow.com/questions/23503948/… - Cabeza de jengibre

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.