Pregunta sobre java, jsf, jsf-2 – Cómo crear un formulario JSF con validación de datos AJAX

3

Estoy trabajando en un prototipo de formulario JSF para insertar datos en la tabla de base de datos utilizando la validación de datos AJAX. Esta es la página JSF:

<code><?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"    
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
    <h:head>
        <ui:insert name="header">           
            <ui:include src="header.xhtml"/>         
        </ui:insert>
    </h:head>
    <h:body>

        <h1><img src="resources/css/images/icon.png" alt="NVIDIA.com" /> History Center</h1>
        <!-- layer for black background of the buttons -->
        <div id="toolbar" style="margin: 0 auto; width:1180px; height:30px; position:relative;  background-color:black">
            <!-- Include page Navigation -->
            <ui:insert name="Navigation">           
                <ui:include src="Navigation.xhtml"/>         
            </ui:insert>

        </div>  

        <div id="logodiv" style="position:relative; top:35px; left:0px;"> 
            <h:graphicImage alt="Demo Insert Form"  style="position:relative; top:-20px; left:9px;"  value="resources/images/logo_databasez.png" />
        </div>
        <div id="main" style="margin: 0 auto; width:1190px; height:700px; position:absolute;  background-color:transparent; top:105px">

            <div id="mainpage" style="margin: 0 auto; width:1190px; height:500px; position:absolute;  background-color:transparent; top:80px">

                <div id="settingsHashMap" style="width:350px; height:400px; position:absolute;  background-color:r; top:20px; left:1px">
                    <h:form>
                        <div id="settingsdiv" style="width:750px; height:400px; position:absolute;  background-color:r; top:20px; left:1px">

                            <h:panelGrid columns="2">
                                <h:panelGroup>Session ID</h:panelGroup>
                                <h:panelGroup>
                                    <h:inputText id="sessionid" value="#{DatabaseController.formMap['sessionid']}" >
                                        <f:validateLength minimum="0" maximum="15"/>
                                        <f:ajax render="sessionidvalidate" event="blur"/>                                          
                                    </h:inputText>
                                    <h:outputText id="sessionidvalidate" rendered="#{DatabaseController.validateSessionid}" value="session is already registered" />
                                </h:panelGroup>

                                <h:panelGroup>User ID</h:panelGroup>
                                <h:panelGroup>
                                    <h:inputText id="userid" value="#{DatabaseController.formMap['userid']}" >
                                        <f:validateLength minimum="0" maximum="15"/>
                                    </h:inputText>
                                </h:panelGroup>

                                <h:panelGroup>Login Time</h:panelGroup>
                                <h:panelGroup>
                                    <h:inputText id="logintime" value="#{DatabaseController.formMap['logintime']}" >
                                        <f:validateLength minimum="0" maximum="35"/>
                                    </h:inputText>
                                </h:panelGroup>

                                <h:panelGroup>Last Refresh Time</h:panelGroup>
                                <h:panelGroup>
                                    <h:inputText id="lastrefreshtime" value="#{DatabaseController.formMap['lastrefreshtime']}" >
                                        <f:validateLength minimum="0" maximum="35"/>
                                    </h:inputText>
                                </h:panelGroup>

                                <h:panelGroup>User IP</h:panelGroup>
                                <h:panelGroup>
                                    <h:inputText id="userip" value="#{DatabaseController.formMap['userip']}" >
                                        <f:validateLength minimum="0" maximum="15"/>
                                    </h:inputText>
                                </h:panelGroup>

                            </h:panelGrid>          

                        </div>   

                        <div id="settingstwodiv" style="width:150px; height:60px; position:absolute;  background-color:transparent; top:380px; left:800px">

                            <h:commandButton value="Create User" action="#{DatabaseController.saveData}"/>

                        </div> 
                    </h:form> 

                </div>   

            </div>  
        </div>

    </h:body>
</html>
</code>

Este es el bean gestionado:

<code>import java.io.Serializable;
import javax.enterprise.context.SessionScoped;
// or import javax.faces.bean.SessionScoped;
import javax.inject.Named;
/* include SQL Packages */
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import javax.annotation.Resource;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
// or import javax.faces.bean.ManagedBean;   

import org.glassfish.osgicdi.OSGiService;

// Demo Insert Form
@Named("DatabaseController")
@SessionScoped
public class Database implements Serializable {

    private HashMap<String, String> formMap = new HashMap<>();

    public Database() {
    }
    /* Call the Oracle JDBC Connection driver */
    @Resource(name = "jdbc/Oracle")
    private DataSource ds;

    public HashMap<String, String> getformMap() {
        return formMap;
    }

    /*

    CREATE TABLE ACTIVESESSIONS(
    SESSIONID VARCHAR2(30 ) NOT NULL,
    USERID VARCHAR2(30 ) NOT NULL,
    LOGINTIME TIMESTAMP(6),
    LASTREFRESHTIME TIMESTAMP(6),
    USERIP VARCHAR2(30 )
    )
    /
     */
    @PostConstruct
    public void hashMapGenerate() {
        /* Initialize the hashmap */
        formMap.put("sessionid", null);
        formMap.put("userid", null);
        formMap.put("logintime", null);
        formMap.put("lastrefreshtime", null);
        formMap.put("userip", null);
    }

    public int saveData() throws SQLException, java.text.ParseException {
//        formMap = new HashMap<String, String>();

        String SqlStatement = null;

        if (ds == null) {
            throw new SQLException();
        }

        Connection conn = ds.getConnection();
        if (conn == null) {
            throw new SQLException();
        }

        PreparedStatement ps = null;

        /*

        CREATE TABLE ACTIVESESSIONS(
        SESSIONID VARCHAR2(30 ) NOT NULL,
        USERID VARCHAR2(30 ) NOT NULL,
        LOGINTIME TIMESTAMP(6),
        LASTREFRESHTIME TIMESTAMP(6),
        USERIP VARCHAR2(30 )
        )
        /
         */

        try {
            conn.setAutoCommit(false);
            boolean committed = false;
            try {           /* insert into Oracle the default system(Linux) time */
                SqlStatement = "INSERT INTO ACTIVESESSIONS"
                        + " (SESSIONID, USERID, LOGINTIME, LASTREFRESHTIME, USERIP)"
                        + " VALUES (?, ?, ?, ?, ?)";

                ps = conn.prepareStatement(SqlStatement);

                ps.setString(1, formMap.get("sessionid"));
                ps.setString(2, formMap.get("userid"));
                ps.setTimestamp(3, toTimeStamp(formMap.get("logintime")));
                ps.setTimestamp(4, toTimeStamp(formMap.get("lastrefreshtime")));
                ps.setString(5, formMap.get("userip"));

                ps.executeUpdate();

                conn.commit();
                committed = true;
            }
            finally 
            {
                if (!committed) {
                    conn.rollback();
                }
            }
        } finally {
            /* Release the resources */
            ps.close();
            conn.close();
        }

        return 0;

    }
    private Timestamp toTimeStamp(String s) throws java.text.ParseException
    {
        Timestamp ts = null;
        java.util.Date date = null;
        if (s == null || s.trim().isEmpty()) return ts;

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.S");
        date = (java.util.Date) sdf.parse(s);
        ts = new Timestamp(date.getTime());

        return ts;

    }

    /* Validators section */
    public boolean getvalidateSessionid(){

        //do SQL query

        return true;
    }

}
</code>

Estoy teniendo dificultades para implementar la validación de formularios. Quiero pasar el String introducido por el usado y registrarlo en la base de datos si este valor ya está en la tabla de la base de datos. Aquí estoy llamando al método Java para verificar el valor:

<code>                            <h:panelGroup>
                                <h:inputText id="sessionid" value="#{DatabaseController.formMap['sessionid']}" >
                                    <f:validateLength minimum="0" maximum="15"/>
                                    <f:ajax render="sessionidvalidate" event="blur"/>                                          
                                </h:inputText>
                                <h:outputText id="sessionidvalidate" rendered="#{DatabaseController.validateSessionid}" value="session is already registered" />
                            </h:panelGroup>
</code>

¿Cómo puedo enviar el valor insertado al método Java?

Los mejores deseos

Tu respuesta

2   la respuesta
1

Solo agrega listener en tu etiquetah:inputText:

<code><h:inputText id="sessionid" value="#{DatabaseController.formMap['sessionid']}" 
         valueChangeListener="#{DatabaseController.validateSessionid}">
</code>

Para que pueda comprobar el valor introducido en el lado del servidor. Cuando un usuario sale del campo de entrada, JSF realiza una llamada ajax al servidor y ejecuta el componente de entrada de nombre a través de la parte de ejecución del ciclo de vida. Esto significa que JSF invocará el oyente de cambio de valor de la entrada del nombre especificado en el atributovalueChangeListener Durante la fase de proceso de validación del ciclo de vida.

Y sugeriría implementar este método:

<code>public void validateSessionid(ValueChangeEvent e) {
    UIInput nameInput = e.getComponent()
    String sessionid = nameInput.getValue()

    //do SQL query
}
</code>

Después de que la llamada ajax devuelve JSF renderiza elh:outputText id="sessionidvalidate".

Usando unValidator realmente no tardará más de un segundo, está bien integrado en el marco JSF y, por lo tanto, es más fácil de (re) usar. Además, no olvide marcar el componente como no válido, marque el contexto de las caras como no válido, omita los valores del modelo de actualización e invoque las fases de la aplicación cuando la validación haya fallado en su escucha de cambio de valor. BalusC
Usando la herramienta adecuada para el trabajo. Si quieres validar algo, usa unValidator. Está bien adaptado para el trabajo, tiene un bien definidovalidate() método en el que puede lanzar unValidatorException lo que obligará adecuadamente a JSF a tratar el envío como no válido y manejar el mensaje. En elvalueChangeListener Tendrías que hacerlo todo manualmente. BalusC
Gracias por la respuesta. Estaba buscando otra forma de crear solicitudes asíncronas en lugar de f: ajax. Tu solución funcionó bien bond_t
Pero la representación dinámica simple de un mensaje de error es más barata que generar la excepción en esta situación, ¿no es así? kapand
9

Validator.

Ejemplo de arranque:

<code>@FacesValidator("sessionIdValidator")
public class SessionIdValidator implements Validator {

    @Override
    public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        // ...

        if (yourDataService.existSessionId(value)) {
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR,
                "Session ID is already in use, please choose another.", null));
        }
    }

}
</code>

Úsalo de la siguiente manera:

<code><h:inputText id="sessionid" value="#{DatabaseController.formMap['sessionid']}">
    <f:validateLength minimum="0" maximum="15" />
    <f:validator validatorId="sessionIdValidator" />
    <f:ajax event="blur" render="sessionidMessage" />                                          
</h:inputText>
<h:message id="sessionidMessage" for="sessionid" />
</code>

Tenga en cuenta que debe usar un<h:message> para mostrar los mensajes de validación. Usted no tiene a nadie en su opinión. Aplica lo mismo para todos tus otros campos:

<code><h:inputText id="userid" value="#{DatabaseController.formMap['userid']}">
    <f:validateLength minimum="0" maximum="15" />
    <f:ajax event="blur" render="useridMessage" />                                          
</h:inputText>
<h:message id="useridMessage" for="userid" />
</code>

Si quieres usar@Resource o@EJB o@Inject en el validador, entonces reemplace el@FacesValidator anotación por@ManagedBean o (como parece que usas CDI por alguna razón)@Named:

<code>@Named
public class SessionIdValidator implements Validator {

    @Resource
    private DataSource dataSource;

    @Inject
    private YourDataService yourDataService;

    // ...
}
</code>

y usarlo de la siguiente manera

<code>    <f:validator binding="#{sessionIdValidator}" />
</code>
De acuerdo con la<f:ajax>, solo cuando el campo de entrada se desenfoca. BalusC
¿Quizás si hay una forma de activar el evento = "keyup" solo cuando se ingresan más de, por ejemplo, 6 letras, será más económico? Peter Penzov
Es inútilevent="keyup". Tenga en cuenta que esto es bastante caro. losevent="change" solo se dispara cuando desenfoca el campo después de haber cambiado el valor. Solo estaba usandoevent="blur" Porque ya lo tienes en tu fragmento de código. Tenga en cuenta que elevent="change" por lo tanto, no se dispara cuando no cambia el valor, pero si desea validarrequired="true" inmediatamente en un campo vacío y así sucesivamente, será mejor que usesevent="blur". BalusC
Desenfoque significa - (pérdida de enfoque) eventos en la entrada de texto. Creo que esto significa que cuando introduzco algunos datos en el archivo y hago clic fuera del campo, los datos se validan. ¿Cómo puedo configurar el campo de entrada para verificar cada nueva letra ingresada en el campo de entrada? Tal vez evento = "cambio"? Peter Penzov

Preguntas relacionadas