Working with Databases and Action Methods

These lecture notes will walk you through a simple example of a JSF application that uses a database to do some simple processing. The start page of the application will prompt the user to enter a user name and password. Clicking the Log In button will run a method that checks that combination against a database of users and passwords.

To start building this example, create a new JSF web application.

Setting up the database

Create a new database schema in MySQL with the name 'password', and set up a single table named 'users' with fields for user and password. Fill in some test data for your application to use.

Setting up the bean

This application will make use of a Java bean class named 'User' with 2 String properties, 'name' and 'password'. Create a new JSF Managed Bean class named User with session scope and give it those two properties.

Configuring the database resource

Our example makes use of a database to check user name/password combinations that the user provides. Next, we will configure our project to connect to the MySQL database.

Start by adding the MySQL JDBC driver library to the Libraries folder of the project.

The next step is to declare a DataSource member variable in the User bean class. Instead of initializing this object ourselves in the constructor of the User class, we will attach an annotation that tells the application server to initialize that member variable via resource injection. Resource injection is a special type of initialization that the application server can perform on our member variables once the server is properly configured.

@Resource(name = "jdbc/password")
private DataSource dataSource;

To set up this resource, we will have to do some configuration in GlassFish. Go to the Services pane in NetBeans and expand the Servers group. In that group you should see an entry for GlassFish.

Right-click and select the option to start GlassFish, then right-click again and select the option 'View Admin Console'. That will open the GlassFish administration application in a browser window.

On the left side of that window is a panel of administration tasks. Expand the JDBC task group under resources.

Click on Connection Pools to open the Connection Pools pane. Click the New... button in that pane. Fill out page 1 as shown here. Click Next.

On page 2 fill out the additional properties section at the bottom of the page as shown here. If your root password for MySQL is not 'cmsc250', modify that entry as needed.

Click the Finish button. Next, click on JDBC Resources in the task pane, and click the New... button to create a new JDBC resource. Fill that page out as shown here.

Once we have finished setting up the JNDI name 'jdbc/password' and linking it to the password connection pool we can inject that DataSource resource into our User bean:

@Resource(name = "jdbc/password")
private DataSource dataSource;

The welcome page

The first page users will encounter when they run our application is a page that will prompt them to enter a user name and password.

Replace the code for your index.xhtml page with the following code.

<?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://java.sun.com/jsf/html">
  <h:head>
    <title>JSF Login Example</title>
  </h:head>
  <h:body>
    <h:form>
      <h:panelGrid columns="2">
        Enter your user name:
        <h:inputText value="#{user.name}"/>

        Enter your password:
        <h:inputSecret value="#{user.password}"/>
      </h:panelGrid>
      <h:commandButton value="Log In" action="#{user.checkPassword}"/>
    </h:form>
  </h:body>
</html>

The form in this page has two input elements, a plain inputText element for the user name and an inputSecret element for the password. Each of these input elements is linked to the corresponding property in the user bean. When the user clicks the Log In button, the values they typed in those two fields will get loaded into those bean properties.

The most important new feature in this page is the action attribute of the commandButton. In the last example we saw a commandButton whose action attribute named a page - clicking on that button simply caused us to navigate to that page. This commandButton has an action attribute linked to a method in the user class. Clicking the Log In button calls that method.

An action method

Here is the code for the checkPassword method in the User bean class.

public String checkPassword() throws SQLException {
  String navString = "error";

  Connection connection = dataSource.getConnection();

  try {
    Statement statement = connection.createStatement();
    String query = "select password from users where user=\'" + name + "\'";
    ResultSet result = statement.executeQuery(query);

    if (result.next()) {
      String actualPassword = result.getString("password");
      if (actualPassword != null && actualPassword.equals(password)) {
        navString = "greeting";
      } else {
        navString = "wrongPassword";
      }

    } else {
      navString = "noUser";
    }
  } finally {
    connection.close();
  }

  return navString;
}

The return type of this action method is String. The first function that an action method in a JSF application is expected to perform is returning a navigation string that specifies what page to go to next. This particular action method can return a number of different navigation strings depending on circumstances. If the action method returns null, the application will navigate back to the page we were just on.

As you can see from the code above, this action method uses the DataSource we set up earlier to get a connection to the password database. It then runs a query against the users table to see if there is a user with that name, and whether or not their password matches what was give to us in the password property. Depending on the results of that query we return any of a number of different page names that will display messages to the user that are appropriate to the situation.

Other pages

To finish building the example, we have to set up pages corresponding to each of the possible navigation results returned by the action method. These additional pages are fairly simple. For example, here is the code for the greeting.xhtml page:

<?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://java.sun.com/jsf/html">
  <h:head>
    <title>Successful Login</title>
  </h:head>
  <h:body>
    Welcome, #{user.name}!
  </h:body>
</html>

Here is the code for wrongPassword.xhtml:

<?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://java.sun.com/jsf/html">
  <h:head>
    <title>Incorrect Password</title>
  </h:head>
  <h:body>
    <h:form>
      Sorry, #{user.name}, the password you entered is incorrect.
      <br/>
      <h:commandLink action="index" value="Go Back"/>
    </h:form>
  </h:body>
</html>

(The commandLink element sets up a simple link back to the start page so the user can try again. To use a commandLink we have to set up a form, even though no input is taking place here.)