- Working with the Java Persistence API (JPA)
- A Simple Example Using JPA
To demonstrate JPA, I'll use a simple example of a user authentication, where the credentials are stored in a database. For this example, I'm using the following technologies in the following table.
Type | Product |
---|---|
IDE | Eclipse Helios |
Servlet Container | Tomcat 7 |
Database | Apache Derby |
Persistence Provider | EclipseLink JPA |
Architecture | Java Server Faces |
For purposes of this discussion, I'll assume that you have some experience working with J2EE. However, I'll point out any special configurations needed to work with the example.
To get started, follow these steps:
- Create a Dynamic Web Project in Eclipse. I called my project Webbeans, but you can use any name you like.
- Add Java Server Faces to the project's facets.
- Add standard.jar and jstl.jar to the Tomcat lib directory. Without these JAR files, Tomcat will not compile Java Server Faces (JSF) applications.
Now that you've set up your project, you'll need a database for the example application. We'll take care of that requirement in the next section.
Configuring Apache Derby to Work with Eclipse
Apache Derby is a lightweight, all-Java database that's good for development. To configure Derby to work with Eclipse, do the following:
- Download the Eclipse Derby plug-in from the Apache Derby site. You'll need both of the following files:
Once you've downloaded the zip files, unzip them and copy the plug-in files for each into the Eclipse plug-in directory. - Restart Eclipse so the plug-in will register, defining a driver definition for Derby.
- Create a Java project called data to hold the database files. Right-click the data project and select Apache Derby > Add Apache Derby Nature. Then right-click the data project again and select Apache Derby > Start Derby Network Server.
After you perform the steps above, your database should be ready to accept connections.
- For the example in this article, switch to the Data Source Explorer view in Eclipse. Create a new database connection using the Connection Profile wizard. Choose the Derby client driver (10.2) and accept the profile property defaults.
You should be able to connect to Derby now, and the sample database will be visible. - Right-click your new connection and select Open SQL Scrapbook. Type or paste the following database operation into the Scrapbook window:
- Make sure that the sample database is selected. Then right-click inside the Scrapbook pane and select Execute All.
The table for this example should now appear under the App Schema for the sample database.
CREATE TABLE app.users ( id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), name VARCHAR(120), login VARCHAR(75) NOT NULL, password VARCHAR(75) NOT NULL );
Configuring for Your Application
Now you need to configure EclipseLink and persistence.xml specifically for your application. Follow these steps:
- Go to the Eclipse.org EclipseLink download site and download the EclipseLink implementation.
- The download contains several JAR files. For this example, find the following files and add them to Tomcat's lib directory:
- eclipselink.jar
- javax.persistence_2.0.X.jar
- Create the file persistence.xml and add it to your project's WebContent/META-INF folder.
Your file's contents should look something like this:
<?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="User" transaction-type="RESOURCE_LOCAL"> <class>logon.User</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/sample;create=true" /> <property name="javax.persistence.jdbc.user" value="test" /> <property name="javax.persistence.jdbc.password" value="test" /> </properties> </persistence-unit> </persistence>
In persistence.xml, we define a Persistence Unit for each of our domain (business) model classes. In this example, the User class is defined. The remaining properties define our database location and credentials.
Adding the User Entity Class, Login, and Welcome Pages
The User class has all the getters/setters for the Users table. At the top, we tell the compiler that the table name is Users. By default, the table name is the name of the entity class. We declare the class an Entity by using the @Entity annotation, as I mentioned earlier. Then we use the @Id annotation to generate an ID for the Id column of the table.
package logon; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="App.Users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; String Name = null; String Login = null; String Password = null; public int get_Id(){ return id; } public void set_Id(int id){ this.id = id; } public String getName(){ return Name; } public void setName(String Name){ this.Name = Name; } public String getLogin(){ return Login; } public void setLogin(String Login){ this.Login = Login; } public String getPassword(){ return Password; } public void setPassword(String Password){ this.Password = Password; } }
Now we can test JPA by adding a record to our table:
- Create a META-INF folder in your src directory; then copy the persistence.xml file to your source/META-INF folder.
- Create the logon package and add the following Java class to this package. The class name should be LogonTest.
package logon; import java.util.List; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; public class LogonTest { private static final String PERSISTENCE_UNIT_NAME = "User"; private static EntityManagerFactory factory; public static void main(String[] args) { factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); EntityManager em = factory.createEntityManager(); // Read the existing entries and write to console Query q = em.createQuery("SELECT u FROM User u"); List<User> userList = q.getResultList(); for (User user : userList) { System.out.println(user.Name); } System.out.println("Size: " + userList.size()); // Create new user em.getTransaction().begin(); User user = new User(); user.setName("Tom Johnson"); user.setLogin("tomj"); user.setPassword("pass"); em.persist(user); em.getTransaction().commit(); em.close(); } }
- To test JPA, right-click the class and select Run As Java Application. On your console, you should see the output of the user that was just added. The user record should now be in the Users table.
To finish this example, you'll need a backing bean for the Login page. To create the backing bean, follow these steps:
- Double-click your faces-config.xml file to bring up the Faces editor.
- Click the Managed Bean tab and create a new Bean with the name logonBean1 that will be used to reference a new class called LogonBean.java, which will be a member of a new package called logon (in your project's src folder). The editor should create the new package and class for you.
- Copy the following code into your class to handle user authentication:
package logon; import java.util.*; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.persistence.Query; public class LogonBean { private static final String PERSISTENCE_UNIT_NAME = "User"; private static EntityManagerFactory factory; private String userName; private String password; public LogonBean() { } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName=userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password=password; } public String validate() { String flag="failure"; factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME); EntityManager em = factory.createEntityManager(); Query q = em.createQuery("SELECT u FROM User u WHERE u.Login = :login AND u.Password = :pass"); q.setParameter("login", userName); q.setParameter("pass", password); try{ User user = (User) q.getSingleResult(); if (userName.equalsIgnoreCase(user.Login)&&password.equals(user.Password)) { flag="success"; } }catch(Exception e){ return null; } return flag; } }
- Create the login.jsp page and place it in your WebContent folder:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <html> <head> <title>Login Page</title> </head> <body> <f:view> <h:form id="helloForm"> <Center> <H2>Logon Page</H2> </Br></Br> <table> <tr> <td> <h:outputLabel for="input1"> <h:outputText id="nameLabel" value="User Name"/> </h:outputLabel> </td> <td> <h:inputText id="input1" value="#{logonBean1.userName}" size="20"/> </td> </tr> <tr> <td> <h:outputLabel for="input2"> <h:outputText id="passwordLabel" value="Password"/> </h:outputLabel> </td> <td> <h:inputSecret id="input2" value="#{logonBean1.password}" size="20"/> </td> </tr> <tr> <td></td> <td> <h:commandButton id="logon" action="#{logonBean1.validate}" value="Logon"> </h:commandButton> </td> </tr> </table> </Center> </h:form> </f:view> </body> </html>
- Create the welcome.jsp page and place it in your WebContent folder:
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %> <html> <head> <title>Greeting Page</title> </head> <body> <f:view> <h:form id="greetingForm"> <Center> <H2>Greeting Page</H2> </Br></Br> <H4>Hello <h:outputText value="#{logonBean1.userName}"/>! You have been successfully authenticated. </H4> </Br></Br> <h:commandLink id="link" action="logout"> <h:outputText value="Logout"/> </h:commandLink> </Center> </h:form> </f:view> </body> </html>
- Copy the code below into your faces-config.xml file. It establishes the navigation rule to the welcome page from the login page, based on a successful outcome.
<?xml version="1.0" encoding="UTF-8"?> <faces-config xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" version="2.0"> <managed-bean> <managed-bean-name>logonBean1</managed-bean-name> <managed-bean-class>logon.LogonBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> <navigation-rule> <display-name>login</display-name> <from-view-id>/login.jsp</from-view-id> <navigation-case> <from-outcome>success</from-outcome> <to-view-id>/welcome.jsp</to-view-id> </navigation-case> </navigation-rule> </faces-config>
Before running the example, verify that your web.xml file looks like the one below (substituting your project's name for Webbeans):
<?xml version="1.0" encoding="ASCII"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>Webbeans</display-name> <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>/faces/*</url-pattern> </servlet-mapping> <context-param> <description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param> <context-param> <param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name> <param-value>resources.application</param-value> </context-param> <listener> <listener-class>com.sun.faces.config.ConfigureListener</listener-class> </listener> <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> </web-app>
The example should now be ready to run. Your path should look like this (again, substituting your project's name):
http://localhost:8080/Webbeans/faces/login.jsp
You can change the faces context in the faces-config.xml file to whatever you like.
Testing the Example
Enter tomj as the username and pass as the password, click Submit, and you should get the welcome screen. If your credentials are incorrect, you'll stay at the login screen.
That's it! You've mastered authentication with JPA using a database.
In a later article I'll expand on this example, demonstrating the other CRUD operations, along with some JPQL queries.
Happy coding!