Вопрос по jsf-2, java, jsf – Как создать форму JSF с проверкой данных AJAX

3

Я работаю над прототипом формы JSF для вставки данных в таблицу базы данных с помощью проверки данных AJAX. Это страница 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>

Это управляемый компонент:

<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>

У меня трудности с выполнением проверки формы. Я хочу передать строку, введенную использованным, и проверить ее в базе данных - это значение уже в таблице базы данных. Здесь я вызываю Java-метод для проверки значения:

<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>

Как я могу отправить вставленное значение в метод Java?

С наилучшими пожеланиями

Ваш Ответ

2   ответа
1

Просто добавьте слушателя в свой тегh:inputText:

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

Таким образом, вы можете проверить введенное значение на стороне сервера. Когда пользователь выходит из поля ввода, JSF выполняет ajax-вызов к серверу и запускает компонент ввода имени в течение части выполнения жизненного цикла. Это означает, что JSF будет вызывать прослушиватель изменения значения ввода имени, указанный в атрибутеvalueChangeListener во время этапа валидации жизненного цикла.

И я бы предложил реализовать этот метод:

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

    //do SQL query
}

После возврата ajax-вызова JSF рендеритh:outputText id="sessionidvalidate".

Но простой динамический рендеринг сообщения об ошибке дешевле, чем генерация исключения в этой ситуации, не так ли?
valueChangeListener служит совершенно другой цели. Он намеревался прослушивать события изменения значений, а не проверять значения.
Используя правильный инструмент для работы. Если вы хотите что-то проверить, используйтеValidator, Это хорошо подходит для работы, оно имеет четко определенныеvalidate() метод, в котором вы можете броситьValidatorException что заставит JSF правильно обработать отправку как недействительную и обработать сообщение. вvalueChangeListener Вы должны сделать все это вручную.
ИспользуяValidator действительно не займет больше секунды, и он хорошо интегрирован в инфраструктуру JSF и, таким образом, его легче (повторно) использовать. Кроме того, не забудьте пометить компонент как недопустимый, пометить контекст граней как недопустимый, пропустить обновления значений модели и вызвать фазы приложения, если проверка не прошла в вашем слушателе изменения значений.
Но процесс в этом случае будет практически таким же, как при использовании пользовательского валидатора. В чем принципиальная разница?
9

Вам нужно создатьValidator.

Начальный пример:

@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));
        }
    }

}

Используйте это следующим образом:

<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" />

Обратите внимание, что вы должны использовать<h:message> показать сообщения проверки. У вас нет никого на ваш взгляд. Примените то же самое для всех других ваших полей:

<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" />

Если вы хотите использовать@Resource или же@EJB или же@Inject в валидаторе, затем замените@FacesValidator аннотация по@ManagedBean или (как вы, кажется, по какой-то причине используете CDI)@Named:

@Named
public class SessionIdValidator implements Validator {

    @Resource
    private DataSource dataSource;

    @Inject
    private YourDataService yourDataService;

    // ...
}

и используйте его следующим образом

    <f:validator binding="#{sessionIdValidator}" />
Нет, использоватьevent="keyup", Имейте в виду, что это довольно дорого.event="change" срабатывает только тогда, когда вы стираете поле после того, как вы изменили значение. Я просто использовалevent="blur" потому что у вас уже есть это в вашем фрагменте кода. Обратите внимание, чтоevent="change" таким образом, не срабатывает, когда вы не меняете значение, но если вы хотите проверитьrequired="true" сразу на пустое поле и т. д., лучше использоватьevent="blur".
Спасибо за пример! Если я реализую ваш пример проверки, когда сообщение об ошибке появится на веб-странице? Когда я нажимаю кнопку или когда я что-то вводлю? Peter Penzov
Да, это возможно. Вы могли бы использовать<f:attribute> в компоненте, чтобы указать «тип» стоимости. Например.<f:attribute name="type" value="sessionid" />, Вы можете получить его в валидаторе поcomponent.getAttributes().get("type").
Воплощать в жизньValidator и броситьValidatorException сFacesMessage как показано в моем ответе.
Согласно<f:ajax>, только когда поле ввода размывается.

Похожие вопросы