Generating a JavaServer Faces CRUD Application from a Database
In this tutorial, you use the NetBeans IDE to generate and deploy a web application
that displays data from a database. In the tutorial you generate a web application with CRUD (Create, Read, Update, Delete)
functionality that uses the Java Persistence API (JPA) to manage the database transaction.
In the tutorial you first create entity classes based on tables in a database and then
create JavaServer Faces (JSF) pages from the entity classes using the JSF Pages from Entity Classes wizard.
The JSF Pages from Entity Classes wizard enables you to quickly and easily
generate JSF pages for working with a database based on the entity classes in your project.
The wizard was updated in NetBeans IDE 6.1 to add new features, support more cases and to generate more
robust code. The improvements to the wizard include the following:
- The generated code is simpler and easier to maintain and customize.
- Correct handling of all relationship types, generated and non-generated IDs,
and embedded IDs, including embedded ID fields that correspond to foreign key columns.
- Required checks prevent non-nullable column violations.
- Orphan checks prevent non-nullable column violations in related entities.
The generated code also includes checks to verify that the current entity is correct
in order to prevent errors if a user deviates from the normal page flow.
Errors may occur, for example, when working in multiple browser tabs.
Using the code generated by the wizard, it is now easier to remove fields from the generated JSPs.
It is also now much easier to apply styles to the generated pages.
Contents
To follow this tutorial, you need the following software and resources.
Creating the Database
This tutorial uses a consulting agency database called consult.
The database is not included when you install the IDE so you need to
first create the database to follow this tutorial.
The consult database was designed to demonstrate the scope of IDE support for handling a variety of database structures.
The database is thus not intended as an example of recommended database design.
Instead, it attempts to incorporate many of the relevant features that are potentially found in a database design.
For example, the consult database contains all possible relationship types, composite primary keys,
and many different data types. See the tables for a more detailed overview of the database structure.
- Download the create-consult.sql file and save the file to your local system.
- In the Services window, expand the Databases node, right-click the JavaDB node and choose Start Server.
- Right-click the JavaDB node and choose Create Database.
- Type consult as the Database Name, User Name, and Password in the Create Java DB dialog. Click OK.
A new node appears under the Databases node (jdbc:derby://localhost:1527/consult [consult on CONSULT]).
- Right-click the new node and choose Connect.
- Expand the consult database node, right-click the Tables node, and choose Execute Command to open the SQL editor.
- Copy and paste the contents of the create-consult.sql file into the SQL editor.
Note: Make sure that the consult database is selected in the Connection drop-down list.
- Click the Run SQL button in the SQL toolbar.
When you click Run SQL, the following output appears in the Output window.
Viewing the Database Structure
To see the if the tables were created correctly, right-click the Tables node in the Services window and choose Refresh.
You should see the database tables under the Tables node.
You can expand a table node to see the table columns, indexes and any foreign keys.
You can right-click a column and choose Properties to view additional information about the column.
If you look at the structure of the consult database you can see that the database
contains tables that have a variety of relationships and various field types.
When creating entity classes from a database, the IDE automatically generates the appropriate code for the
various field types.
The following table describes the tables found in the consult database.
| CLIENT |
A client of the consulting agency |
Non-generated, composite primary key (whose fields do not constitute a foreign key) |
| CONSULTANT |
An employee of the consulting agency whom clients can hire on a contract basis |
Includes a resume field of type LONG VARCHAR |
| CONSULTANT_STATUS |
A consultant's status with the consulting agency (for example, Active and Inactive are possible statuses) |
Non-generated primary key of type CHAR |
| RECRUITER |
An employee of the consulting agency responsible for connecting clients and consultants |
|
| PROJECT |
A project that a client staffs with consultants of the consulting agency |
Non-generated, composite primary key that includes two fields constituting a foreign key to the CLIENT table |
| BILLABLE |
A set of hours worked by a consultant on a project, for which the consulting agency bills the relevant client |
Includes an artifact field of type CLOB |
| ADDRESS |
A client's billing address |
|
| PROJECT_CONSULTANT |
Join table indicating which consultants are currently assigned to which projects |
Cross-references PROJECT and CONSULTANT, the former having a composite primary key |
The consult database includes a variety of relationships.
When creating entity classes from a database, the IDE automatically generates the appropriate code for the
table relationships, adding the appropriate annotations to the fields in the entity classes.
The following table describes the table relationships found in the consult database.
(The inverse relationships are not shown.)
| CLIENT |
RECRUITER |
nullable one-to-one with manual editing; nullable one-to-many if not edited |
| CLIENT |
ADDRESS |
non-nullable one-to-one |
| CLIENT |
PROJECT |
non-nullable one-to-many; in a Project entity, the value of the client field is part of the Project's primary key |
| CONSULTANT |
PROJECT |
many-to-many |
| CONSULTANT |
BILLABLE |
non-nullable one-to-many |
| CONSULTANT_STATUS |
CONSULTANT |
non-nullable one-to-many |
| RECRUITER |
CONSULTANT |
nullable one-to-many |
| PROJECT |
BILLABLE |
non-nullable one-to-many |
Now that the database is created, you can create the web application and use the Entity Classes from Database wizard to
generate entity classes based on the database tables.
Creating the Web Application Project
In this exercise you create a web project and add the JavaServer Faces framework to the project.
When you create the project, you will select JavaServer Faces in the Frameworks panel of the New Project wizard.
- Choose File > New Project (Ctrl-Shift-N).
- Select Web Application from the Web category and click Next.
- Type ConsultingAgency for the project name and set the project location.
- Deselect the Use Dedicated Folder option, if selected.
For this tutorial there is little reason to copy project libraries to a dedicated folder because
you will not need to share libraries with other users.
Click Next.
- Set the server to GlassFish and set the Java EE Version to Java EE 5. Click Next.
- Select the JavaServer Faces checkbox in the Frameworks panel. Click Finish.
Note: When selecting the framework, be sure to select the JavaServer Faces framework,
NOT Visual Web JavaServer Faces.
When you click Finish, the IDE creates the web application project and opens WelcomeJSF.jsp in the editor.
You can close WelcomeJSF.jsp because you will not need to edit this file.
Generating the Entity Classes from the Database
After you create the database and the database connection is registered with the IDE, you can use the
Entity Classes from Database wizard to quickly generate entity classes based on the tables in the database.
The IDE can generate entity classes for each table that you select, and can also generate any necessary
entity classes for related tables.
- In the Projects window, right-click the ConsultingAgency node, and choose New > Entity Classes from Database.
- Select New Data Source from the Data Source drop-down list to open the Create Data Source dialog.
- Type jdbc/consult as the JNDI Name and select jdbc:derby://localhost:1527/consult [consult on CONSULT]
as the Database Connection. Click OK to close the dialog box and return to the wizard.
The tables in the consult database appear in the Available Tables listbox.
- Click Add All in the wizard. Click Next.
- Type entities as the Package.
Make sure that the checkbox to generate named queries is selected.
- Click Create Persistence Unit to open the Create Persistence Unit dialog box.
Click Create in the dialog box to create the persistence unit and return to the wizard.
You can keep the default values for the persistence unit.
- Click Finish.
When using the wizard to create entity classes from a database, the IDE examines the relationships between the tables.
In the Projects window, if you expand the entities Source Package node
you can see that the IDE generated an entity class for each table except for
the PROJECT_CONSULTANT table.
The IDE did not create an entity class for PROJECT_CONSULTANT because the table is a join table.
The IDE also generated two additional classes for the tables with composite primary keys: CLIENT and PROJECT.
The primary key classes for these tables (ClientPK.java and ProjectPK.java) have PK appended to the name.
Editing the Entity Classes
Now that the entity classes are generated, you need to make small changes to the entity classes
to add code not generated by the wizard.
By adding the code before you create the JSF pages from the classes, you take advantage of
the improved code generation functionality in the wizard.
When creating the entity classes, the Entity Classes from Database wizard does not add
@GeneratedValue annotations or optional annotation elements to the entity classes.
By adding the optional annotation elements, the JSF Pages from Entity Classes wizard can generate code that
includes checks to prevent non-nullable column violations.
In this exercise you make the following changes to the default code generated by the Entity Classes from Database wizard.
- Apply a @GeneratedValue annotation to any ID field that corresponds
to an autogenerated primary key database column
If you look at the SQL script you used to create the database, you can see that
for some of the primary key columns in the tables the GENERATED ALWAYS AS IDENTITY keywords
are used to indicate that the columns are autogenerated.
- Apply the annotation element (optional = false) on all
non-nullable many-to-one (@ManyToOne) and one-to-one (@OneToOne) relationships
Adding this element will cause the IDE to generate required checks when you create the JSF pages
using the JSF Pages from Entity Classes wizard.
By generating required checks, you prevent the user from attempting to use a null value in a
non-nullable database column.
- Customize the implementations of the toString method in the entity classes
In the Client and Recruiter classes you will also modify the annotations to change the relationship between clients and recruiters
from one-to-many to one-to-one.
Because a nullable one-to-many relationship already exists between recruiters and consultants,
for demonstration purposes in this tutorial you will establish a nullable one-to-one relationship between clients and recruiters.
Editing Address.java
Open the Address entity class and make the following changes.
- Mark the addressId field as generated by adding the @GeneratedValue annotation beneath the @Id annotation.
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ADDRESS_ID", nullable = false)
private Integer addressId;
You can use the IDE's code completion to help you add annotations and annotation elements.
When you use code completion, the IDE automatically adds the appropriate import statement for you.
- Modify the return statement of the toString method to return the full address:
return line1 + ", " + line2 + ", " + city + ", " + region + ", " + country + ", " + postalCode;
You can use the IDE's code completion to help you add the fields.
- Fix your imports, if necessary, and save your changes.
Editing Billable.java
Open the Billable entity class and make the following changes.
- Mark the billableId field as generated by adding the @GeneratedValue annotation beneath the @Id annotation.
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "BILLABLE_ID", nullable = false)
private Long billableId;
- Modify the @ManyToOne annotation on the consultantId and project fields to
add the (optional = false) element.
@JoinColumn(name = "CONSULTANT_ID", referencedColumnName = "CONSULTANT_ID")
@ManyToOne(optional = false)
private Consultant consultantId;
@JoinColumns({@JoinColumn(name = "CLIENT_NAME", referencedColumnName = "CLIENT_NAME"), @JoinColumn(name = "CLIENT_DEPARTMENT_NUMBER", referencedColumnName = "CLIENT_DEPARTMENT_NUMBER"), @JoinColumn(name = "PROJECT_NAME", referencedColumnName = "PROJECT_NAME")})
@ManyToOne(optional = false)
private Project project;
- Modify the return statement of the toString method to return the description, consultant id and project:
public String toString() {
return description + ", " + consultantId + ", " + project;
- Fix your imports, if necessary, and save your changes.
Editing Client.java
- Modify the @OneToMany annotation on the recruiterCollection field to
make the relationship one-to-one and change the field from a Collection to Recruiter recruiter.
@OneToOne(mappedBy = "client")
private Recruiter recruiter;
- Modify the getters and setters for Collection<Recruiter> recruiterCollection
according to the changes in the name of the field. The new getter and setter will look like the following:
public Recruiter getRecruiter() {
return recruiter;
}
public void setRecruiter(Recruiter recruiter) {
this.recruiter = recruiter;
}
It may be simpler to delete the getter and setter for Collection<Recruiter> recruiterCollection
and then generate a new getter and setter for Recruiter recruiter using the Insert Code dialog.
To create a new getter and setter, right-click in the source code and choose Insert Code (Alt-Insert)
and then select Getter and Setter.
Select recruiter in the Generate Getter and Setter dialog box and click Generate.
- Modify the @OneToOne annotation on the billingAddress field to
add the (optional = false) property.
@JoinColumn(name = "BILLING_ADDRESS", referencedColumnName = "ADDRESS_ID")
@OneToOne(optional=false)
private Address billingAddress;
- Modify the return statement of the toString method to return String.valueOf(clientPK):
public String toString() {
return String.valueOf(clientPK);
}
- Fix your imports, if necessary, and save your changes.
Editing ClientPK.java
- Modify the return statement of the toString method to return the client name and department number:
public String toString() {
return clientName + ", " + "Dept. " + clientDepartmentNumber;
}
- Save your changes.
Editing Consultant.java
- Mark the consultantId field as generated by adding the @GeneratedValue annotation beneath the @Id annotation.
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CONSULTANT_ID", nullable = false)
private Integer consultantId;
- Modify the @ManyToOne annotation on the statusId field to
add the (optional = false) property.
@JoinColumn(name = "STATUS_ID", referencedColumnName = "STATUS_ID")
@ManyToOne(optional=false)
private ConsultantStatus statusId;
- Modify the return statement of the toString method to return the email:
public String toString() {
return email;
}
- Fix your imports, if necessary, and save your changes.
Editing ConsultantStatus.java
- Modify the return statement of the toString method to return the status ID and description:
public String toString() {
return statusId + ", " + description;
}
- Save your changes.
Editing Project
- Modify the @ManyToOne annotation on the client field to
add the (optional = false) property.
@JoinColumns({@JoinColumn(name = "CLIENT_NAME", referencedColumnName = "CLIENT_NAME", insertable = false, updatable = false), @JoinColumn(name = "CLIENT_DEPARTMENT_NUMBER", referencedColumnName = "CLIENT_DEPARTMENT_NUMBER", insertable = false, updatable = false)})
@ManyToOne(optional=false)
private Client client;
- Modify the return statement of the toString method to return the following:
public String toString() {
return (projectPK == null ? "(unnamed project)" : projectPK.getProjectName()) + ", " + client;
}
- Save your changes.
Editing Recruiter.java
- Mark the recruiterId field as generated by adding the @GeneratedValue annotation beneath the @Id annotation.
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "RECRUITER_ID", nullable = false)
private Integer recruiterId;
- Modify the @ManyToOne annotation on the client field to
mark the relationship as one-to-one.
@OneToOne
private Client client;
- Modify the return statement of the toString method to return the email:
public String toString() {
return email;;
}
- Fix your imports, if necessary, and save your changes.
Generating JSF Pages From Entity Classes
Now that the classes are created, you can create a web application for displaying and modifying the data.
You will use the JSF Pages from Entity Classes wizard to generate a JavaServer Faces application from the entity classes.
For each entity class the wizard will generate the following:
- a controller class
- a converter class
- a directory containing four JSP files (Detail.jsp, Edit.jsp, List.jsp, New.jsp)
- managed bean elements, converter elements and navigation rules for the class in faces-config.xml
The JSF Pages from Entity Classes wizard will generate code that includes checks based on the modifications you made
to the entity classes.
- Right-click the project node in the Projects window and choose New > JSF Pages from Entity Classes
to open the New JSF Pages from Entity Classes wizard.
The Available Tables pane of the wizard lists the seven entity classes in the project.
The wizard does not list the embeddable classes (ClientPK.java and ProjectPK.java)
- Click Add All to move all the classes to the Selected Entity Classes pane of the wizard. Click Next.
- Type beans for the Package. Click Finish.
When you click Finish, the IDE creates the converter and controller classes for each entity class in the beans package.
Each controller class handles the operations for the corresponding entity class, including creating, editing, and destroying instances of the entity class via the Java Persistence API.
Each converter class implements the javax.faces.convert.Converter interface defined by JavaServer Faces and performs the work of converting instances of the corresponding entity class to String objects and vice versa.
If you expand the Web Pages node, you can see that the IDE generated a folder for each of the entity classes.
Each folder contains the files Detail.jsp, Edit.jsp, List.jsp and New.jsp.
The IDE also modified welcomeJSF.jsp to insert links to each of the List.jsp pages.
If you expand the Configuration Files node and open faces-config.xml in the XML editor,
you can see that the IDE inserted the managed-bean and converter elements for each of the controller and converter classes.
The IDE also inserted a navigation-rule element for each JSP, indicating the logical outcome that causes the application to
navigate to that JSP.
Running the Project
Now that you have finished creating the application, you can deploy and run
the application.
- Click Run Main Project in the main toolbar.
The IDE saves all changed files, rebuilds the application, and deploys the application
to the server.
Your default web browser opens to the local address http://localhost:8080/ConsultingAgency/.
- Click the links to view and add details.
When you start clicking the links and adding data, you can see
how the relationships between the tables function.
See Also
For more information about using NetBeans IDE to develop web applications using Java Persistence and JSF,
see the following resources: