JSF 2 AJAX Example – Check Username Availability

JSF 2 AJAX

In this tutorial I am going to show you how to use AJAX (Asynchronous JavaScript And XML) technique in JSF (Java Server Faces) based applications. AJAX is generally used for updating or refreshing a small part of the page because, you may not need to refresh the whole page.

Here in this example I am going to use blur event with <f:ajax/> tag to verify a particular string is available or not. The JavaScript’s blur event is actually fired when you type something in the input box and focus out of the input box.

Prerequisites

Java 1.8+, JSF 2.2.20, MySQL 8.0.26, Maven 3.8.5, Tomcat 10

Project Setup

Create a maven based project in your favorite IDE or tool. The following pom.xml file can be used for your project.

<?xml version="1.0" encoding="UTF-8"?>

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>jsf2-ajax-check-username-availability</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>11</maven.compiler.source>
		<maven.compiler.target>11</maven.compiler.target>
	</properties>

	<dependencies>
		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-api</artifactId>
			<version>2.2.20</version>
		</dependency>

		<dependency>
			<groupId>com.sun.faces</groupId>
			<artifactId>jsf-impl</artifactId>
			<version>2.2.20</version>
		</dependency>

		<dependency>
			<groupId>javax.enterprise</groupId>
			<artifactId>cdi-api</artifactId>
			<version>2.0.SP1</version>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.31</version>
		</dependency>

		<!--required only if jdk 9 or higher version is used-->
		<dependency>
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
			<version>2.4.0-b180830.0359</version>
		</dependency>
	</dependencies>

	<build>
		<finalName>jsf2-ajax-check-username-availability</finalName>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
			</plugin>
		</plugins>
	</build>
</project>

MySQL Table

First thing is to create MySQL table, which will be used to store the user details information.

This table stores information about user’s log in details. Use the following table creation script:

CREATE TABLE `user` (
	`user_id` int unsigned COLLATE utf8mb4_unicode_ci NOT NULL AUTO_INCREMENT,
	`login_username` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
	`login_password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
	`last_login` timestamp COLLATE utf8mb4_unicode_ci NULL DEFAULT CURRENT_TIMESTAMP,
	PRIMARY KEY (`user_id`),
	UNIQUE KEY `login_email_UNIQUE` (`login_username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

Dumping Data

I need to insert some data in order to complete the testing that checks whether the functionality is really working as expected in the application.

insert into `user`(`user_id`,`login_username`,`login_password`,`last_login`)
values
(1,'user1','$2a$08$S5IfrpOVOvFbbOSOmZpjsO5N9PXgEerTloK','2014-07-19 19:18:30'),
(14,'user2','$2a$08$v1kJflweCK3FOcoAsmYAUCMxFa5Shh7c2','2013-11-17 19:22:46');

Deployment Descriptor

Modify src/main/webapp/WEB-INF/web.xml file as below. I have just added welcome file that will be displayed upon home page URL access. I have mentioned the project stage as development so that any application error can be logged.

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="3.1"
	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"
	id="webappid">

	<display-name>JSF 2.2 AJAX Example</display-name>

	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>

	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

	<welcome-file-list>
		<welcome-file>index.jsf</welcome-file>
	</welcome-file-list>
</web-app>

Database Helper

I have created the following database helper class that will be used to query database table. Instead of writing the same piece of code every time while executing queries, I am putting into a helper class to reuse wherever required.

public class DBHelper {

	private DBHelper() {
	}

	/**
	 * to load the database driver
	 *
	 * @return a database connection
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static Connection getDBConnection() throws SQLException {
		Connection conn = null;
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/roytuts", "root", "root");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}

	/**
	 * to get a result set of a query
	 *
	 * @param query custom query
	 * @return a result set of custom query
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static ResultSet getDBResultSet(Connection conn, String query) throws SQLException {
		ResultSet rs = null;
		if (null != conn) {
			PreparedStatement st = conn.prepareStatement(query);
			rs = st.executeQuery();
		}
		return rs;
	}

	/**
	 * to run an update query such as update, delete
	 *
	 * @param query custom query
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static void runQuery(Connection conn, String query) throws SQLException {
		if (null != conn) {
			PreparedStatement st = conn.prepareStatement(query);
			st.executeUpdate();
		} else {
			System.out.println("Query execution failed!");
		}
	}

	/**
	 * close an opened PreparedStatement
	 *
	 * @return a void
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static void closePreparedStatement(PreparedStatement ps) throws SQLException {
		if (null != ps) {
			ps.close();
		}
	}

	/**
	 * close an opened ResultSet
	 *
	 * @return a void
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static void closeResultSet(ResultSet rs) throws SQLException {
		if (null != rs) {
			rs.close();
		}
	}

	/**
	 * close an opened database connection
	 *
	 * @return a void
	 * @throws SQLException throws an exception if an error occurs
	 */
	public static void closeDBConnection(Connection conn) throws SQLException {
		if (null != conn) {
			conn.close();
		}
	}

}

Query Helper

Query helper class returns the result set required for the application.

public class QueryHelper {

	public boolean isUsernameAvailable(final String username) {
		final String sql = "SELECT * FROM user WHERE login_username='" + username.trim() + "' LIMIT 1";

		Connection connection = null;
		ResultSet resultSet = null;

		try {
			connection = DBHelper.getDBConnection();
			resultSet = DBHelper.getDBResultSet(connection, sql);
			if (resultSet != null) {
				if (resultSet.next()) {
					return false;
				} else {
					return true;
				}
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			if (resultSet != null) {
				try {
					DBHelper.closeResultSet(resultSet);
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (connection != null) {
				try {
					DBHelper.closeDBConnection(connection);
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

		return false;
	}

}

JSF Managed Bean

Now you need JSF Managed Bean class to perform the business logic. You can also perform business validation in this class. You need to bind any values on the UI with this managed bean.

I am not using faces-config.xml file to configure the managed bean, rather I am using annotation based configurations.

@ViewScoped
@ManagedBean
public class UserMBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private String msg;
	private String userName;
	private QueryHelper queryHelper;

	public UserMBean() {
		this.queryHelper = new QueryHelper();
	}

	public String getMsg() {
		return msg;
	}

	public void setMsg(String msg) {
		this.msg = msg;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public void isUserNameAvailable() {
		if (queryHelper.isUsernameAvailable(userName)) {
			msg = "<span style=\"color:green;\">Username available</span>";
		} else {
			msg = "<span style=\"color:red;\">Username unavailable</span>";
		}
	}

}

UI – View File

Finally I have created the below index.xhtml file which will be rendered on UI (User Interface) to display the required data.

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://xmlns.jcp.org/jsf/html"
	xmlns:f="http://xmlns.jcp.org/jsf/core">
<h:head>
	<title>JSF 2.2 AJAX Example</title>
</h:head>
<h:body>
	<h2>JSF 2 AJAX Example</h2>
	<br />
	<h:form prependid="false">
		<!-- html table having only one column -->
		<h:panelGrid columns="1">
			<h:panelGroup>
				<h:messages style="color:red" />
			</h:panelGroup>
			<h:outputText value="Input Username:" />
			<h:inputText value="#{userMBean.userName}" required="true"
				requiredMessage="Type to check username is available or not">
				<f:ajax onevent="onblur" render="msg"
					listener="#{userMBean.isUserNameAvailable()}" />
			</h:inputText>
			<h:panelGroup>
				<h:outputLabel id="msg" value="#{userMBean.msg}" escape="false" />
			</h:panelGroup>
		</h:panelGrid>
	</h:form>
</h:body>
</html>

I have used escape="false" in the <h:outputLabel/> so HTML content will be treated as HTML content. So, for example if you use any HTML tag in your output response from JSF managed bean then the response will be parsed as HTML.

The render="msg" is used in <f:ajax/> tag to update the value in the target id (render="msg") after getting response from the managed bean in JSF app.

Testing JSF 2 AJAX Example

Once you deploy the application into Tomcat server, you can access the URL http://localhost:808/jsf2-ajax-check-username-availability in the browser, and you will see the following page:

jsf 2 ajax

If any user name which you are trying to search is available then you will see the following message in green color. Make sure after typing something in the input box you come out of the input box to get the result, because I am using JavaScript’s blur event.

jsf 2 ajax blur

If any username has already been taken and not available for use then you will see the message in red color:

jsf 2 ajax blur

Hope you got an idea how to use AJAX in JSF 2 application.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *