JSF Form Example with Twitter Bootstrap CSS and custom Radio Button Selection and custom SelectManyCheckBox..

Lets see!



Directory Layout


pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
 
    <modelVersion>4.0.0</modelVersion>
 
    <groupId>biz.tugay</groupId>
    <artifactId>studentform</artifactId>
    <packaging>war</packaging>
 
    <version>1.0-SNAPSHOT</version>
 
    <name>studentform Maven Webapp</name>
    <url>http://www.tugay.biz</url>
 
    <dependencies>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>2.2.13</version>
        </dependency>
        <dependency>
            <groupId>com.sun.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>2.2.13</version>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>javax.el-api</artifactId>
            <version>3.0.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
 
        <dependency>
            <groupId>javax.servlet.jsp.jstl</groupId>
            <artifactId>javax.servlet.jsp.jstl-api</artifactId>
            <version>1.2.1</version>
        </dependency>
    </dependencies>
 
    <build>
        <finalName>studentform</finalName>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.1.v20140609</version>
            </plugin>
        </plugins>
    </build>
 
    <properties>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
 
</project>

web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
 
    <servlet>
        <servlet-name>FacesServlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>FacesServlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
 
    <context-param>
        <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
        <param-value>true</param-value>
    </context-param>
 
    <context-param>
        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
        <param-value>true</param-value>
    </context-param>
 
    <context-param>
        <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name>
        <param-value>true</param-value>
    </context-param>
 
    <welcome-file-list>
        <welcome-file>studentform.xhtml</welcome-file>
    </welcome-file-list>
 
</web-app>

Student.java
package biz.tugay;
 
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
 
/**
 * User: Koray Tugay (koray@tugay.biz)
 * Date: 7/23/2016
 * Time: 10:14 AM
 */
 
@ManagedBean
@SessionScoped
public class Student {
 
    private String fullname; // getter, setter
    private String password; // getter, setter
    private String interests; // getter, setter
    private boolean emailsubscription; // getter, setter
    private String highestLevelOfEducation; // getter, setter
    private String gender; // getter, setter
    private Map<String, Boolean> studentLectures 
        = new HashMap<String, Boolean>(); // getter, setter
 
    {
        for (String lecture : getLectures()) {
            studentLectures.put(lecture, false);
        }
    }
 
    public List<String> getGenders() {
        final List<String> genders = new ArrayList<String>();
        genders.add("Male");
        genders.add("Female");
        return genders;
    }
 
    public List<String> getLectures() {
        final List<String> lectures = new ArrayList<String>();
        lectures.add("Math");
        lectures.add("Science");
        lectures.add("German");
        lectures.add("Latin");
        return lectures;
    }
 
    public String registerStudent() {
        final ExternalContext externalContext 
            = FacesContext.getCurrentInstance().getExternalContext();
        final HttpServletRequest request 
        = (HttpServletRequest) externalContext.getRequest();
        processStudentLectures(request);
        this.gender = request.getParameter("genderSelection");
        return "student?faces-redirect=true";
    }
 
    private void processStudentLectures(HttpServletRequest httpServletRequest) {
        final int size = getStudentLectures().size();
        for (int i = 0; i < size; i++) {
            final String studentLectureParameter 
                = httpServletRequest.getParameter("studentLectures:" + i + ":lecture");
            if (studentLectureParameter != null 
                && studentLectureParameter.equals("on")) {
                studentLectures.put(getLectures().get(i), true);
            }
        }
    }
}

studentform.xhtml
<!--
    User: Koray Tugay (koray@tugay.biz)
    Date: 7/22/2016
    Time: 7:58 PM
-->
 
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:c="http://xmlns.jcp.org/jsp/jstl/core">
<f:view>
    <h:head>
        <title>Registiration Form</title>
        <h:outputStylesheet library="css" name="bootstrap.min.css"/>
    </h:head>
    <h:body>
        <h:panelGroup layout="block"
                      styleClass="container"
                      style="margin: 100px 15px 15px 200px;">
            <h:panelGroup id="validationMessages"
                          layout="block"
                          styleClass="alert"
                          rendered="#{not empty facesContext.messageList}">
                <button type="button"
                        class="close"
                        data-dismiss="alert">
                    <h:graphicImage library="img"
                                    name="close-window.png"
                                    style="height: 24px; width: 25px"/>
                </button>
                <c:forEach items="#{facesContext.messageList}"
                           var="facesMessage">
                    #{facesMessage.detail}
                    <br/>
                </c:forEach>
            </h:panelGroup>
 
            <h:form id="studentRegistirationForm"
                    prependId="false">
                <fieldset>
                    <legend>Student Resigtiration Form</legend>
                    <h:outputLabel id="fullnameLabel"
                                   for="fullname"
                                   value="Name:"/>
                    <h:inputText id="fullname"
                                 styleClass="input input-xlarge"
                                 validatorMessage="Name is a required field and
                                                   must be at least 2 characters!"
                                 value="#{student.fullname}">
                        <f:validateLength minimum="2"/>
                        <f:validateRequired/>
                    </h:inputText>
                    <h:panelGroup
                            styleClass="help-block">
                        Do not include your middle name, if you have any!
                    </h:panelGroup>
                    <h:outputLabel id="passwordLabel"
                                   for="password"
                                   value="Password: "/>
                    <h:inputSecret id="password"
                                   styleClass="input input-xlarge"
                                   validatorMessage="Password is a required field
                                                     and must be at least 5 characters!"
                                   value="#{student.password}">
                        <f:validateLength minimum="5"/>
                        <f:validateRequired/>
                    </h:inputSecret>
                    <br/>
                    <h:outputLabel id="interestsLabel"
                                   for="interests"
                                   value="Tell us about your interests:"/>
                    <h:inputTextarea id="interests"
                                     style="width: 50%"
                                     rows="4"
                                     value="#{student.interests}"/>
                    <br/>
                    <h:outputLabel id="emailsubscriptionLabel"
                                   for="emailsubscription"
                                   value="Subscribe to newsletter?"/>
                    <h:selectBooleanCheckbox id="emailsubscription"
                                             value="#{student.emailsubscription}">
                        <f:ajax event="valueChange"
                                execute="emailsubscription"
                                render="weeklyMailInfoSpan weeklyMailInfo"/>
                    </h:selectBooleanCheckbox>
                    <h:panelGroup id="weeklyMailInfoSpan">
                        <h:outputText id="weeklyMailInfo"
                                      styleClass="text text-info"
                                      style="float: right"
                                      rendered="#{student.emailsubscription}"
                                      value="You will be getting weekly mails from us!"/>
                    </h:panelGroup>
                    <br/>
                    <br/>
                    <h:outputLabel id="levelOfEducationLabel"
                                   for="highestLevelOfEducation"
                                   value="Highest Level of Education:"/>
                    <h:selectOneMenu id="highestLevelOfEducation"
                                     style="width: 50%"
                                     value="#{student.highestLevelOfEducation}">
                        <f:selectItem id="preschool"
                                      itemLabel="Pre School"
                                      itemValue="PreSchool"/>
                        <f:selectItem id="midschool"
                                      itemLabel="Middle School"
                                      itemValue="Middle School"/>
                        <f:selectItem id="highschool"
                                      itemLabel="High School"
                                      itemValue="High School"/>
                    </h:selectOneMenu>
                    <br/>
                    <h:outputLabel id="genderLabel"
                                   value="Gender:"/>
 
                    <ui:repeat value="#{student.genders}" var="studentGender">
                        <h:panelGroup>
                            <label class="radio">
                                <input type="radio"
                                       name="genderSelection"
                                       value="#{studentGender}"
                                       checked="#{studentGender == student.gender ? 'checked' : ''}">
                                    #{studentGender}
                                </input>
                            </label>
                        </h:panelGroup>
                    </ui:repeat>
                    <br/>
                    <h:outputLabel id="lecturesLabel"
                                   value="Lectures registered:"/>
                    <ui:repeat id="studentLectures"
                               value="#{student.lectures}"
                               var="lecture">
                        <h:panelGroup>
                            <h:outputLabel styleClass="checkbox">
                                <h:selectBooleanCheckbox id="lecture"
                                                         styleClass="checkbox"
                                                         style="margin-top: 1px"
                                                         value="#{student.studentLectures[lecture]}"/>
                                <h:panelGroup>
                                    <h:outputText value="#{lecture}"/>
                                </h:panelGroup>
                            </h:outputLabel>
                        </h:panelGroup>
                    </ui:repeat>
                    <hr/>
                    <h:commandButton id="submitFormButton"
                                     styleClass="btn"
                                     value="Submit Form"
                                     action="#{student.registerStudent()}"/>
                </fieldset>
            </h:form>
            <br/>
        </h:panelGroup>
        <h:outputScript library="js" name="jquery.js"></h:outputScript>
        <h:outputScript library="js" name="bootstrap.js"></h:outputScript>
    </h:body>
</f:view>
</html>

student.xhtml
<!--
    User: Koray Tugay (koray@tugay.biz)
    Date: 7/24/2016
    Time: 3:06 PM
-->
 
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:f="http://xmlns.jcp.org/jsf/core"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets">
<f:view>
    <h:head>
        <title>Registiration Form</title>
        <h:outputStylesheet library="css" name="bootstrap.min.css"/>
    </h:head>
    <h:body>
        <h:panelGroup layout="block"
                      styleClass="container"
                      style="margin: 100px 15px 15px 200px; font-size: 125%">
 
            <h:panelGroup layout="block" styleClass="well well-large">
                <strong>Student Name:</strong>
                #{student.fullname}
                <br/><br/>
                <strong>Interests:</strong>#{student.interests}
                <br/><br/>
                <strong>Newsletter subscription? </strong>
                #{student.emailsubscription}
                <br/><br/>
                <strong>Highest Level of Education:</strong>
                #{student.highestLevelOfEducation}
                <br/><br/>
                <strong>Gender: </strong>
                #{student.gender}
                <br/><br/>
                <strong>Applied Lectures:</strong>
                <ui:repeat value="#{student.lectures}" var="studentLecture">
                    <h:panelGroup rendered="#{student.studentLectures.get(studentLecture)}">
                        <li><h:outputText value="#{studentLecture}"/></li>
                    </h:panelGroup>
                </ui:repeat>
            </h:panelGroup>
            <h:link outcome="studentform" value="Go back to form"/>
        </h:panelGroup>
        <h:outputScript library="js" name="jquery.js"></h:outputScript>
        <h:outputScript library="js" name="bootstrap.js"></h:outputScript>
    </h:body>
</f:view>
</html>

In Action:

Notes

There is one problem, and that is with the this part:
<ui:repeat value="#{student.genders}" var="studentGender">
    <h:panelGroup>
        <label class="radio">
            <input type="radio"
                   name="genderSelection"
                   value="#{studentGender}"
                   checked="#{studentGender == student.gender ? 'checked' : ''}">
                #{studentGender}
            </input>
        </label>
    </h:panelGroup>
</ui:repeat>

The problem is, since the checked attribute is directly bound to model but not to a component, if the validation fails, the selected value will be forgotten in the form. So for example, you do not enter your firstname, you pick Male and you write down your interests. You post the form, validation fails but you will see that your interests are not removed from the view, since now they are kept in the component. But too bad for the gender field..

I do not know how that could be solved, maybe with some javascript magic, I do not know..