FeaturesPluginsDocs & SupportCommunityPartners

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

Content on this page applies to NetBeans IDE 6.1

To follow this tutorial, you need the following software and resources.

Software or Resource Version Required
NetBeans IDE Web & Java EE version 6.1
Java Development Kit (JDK) Version 6 or
version 5
GlassFish Application Server V2
Consulting Agency Database Download

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.

  1. Download the create-consult.sql file and save the file to your local system.
  2. In the Services window, expand the Databases node, right-click the JavaDB node and choose Start Server.
  3. Right-click the JavaDB node and choose Create Database.
  4. Type consult as the Database Name, User Name, and Password in the Create Java DB dialog. Click OK.
    Create New Database dialog box

    A new node appears under the Databases node (jdbc:derby://localhost:1527/consult [consult on CONSULT]).

  5. Right-click the new node and choose Connect.
  6. Expand the consult database node, right-click the Tables node, and choose Execute Command to open the SQL editor.
  7. 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.
  8. Click the Run SQL button in the SQL toolbar.
screenshot of SQL editor

When you click Run SQL, the following output appears in the Output window.

screenshot of 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.

screenshot of Services window

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.

Database Table Description Design Features
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.)

Database Table Related Table Relationship Information
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.

  1. Choose File > New Project (Ctrl-Shift-N).
  2. Select Web Application from the Web category and click Next.
  3. Type ConsultingAgency for the project name and set the project location.
  4. 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.
  5. Set the server to GlassFish and set the Java EE Version to Java EE 5. Click Next.
  6. 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.

  1. In the Projects window, right-click the ConsultingAgency node, and choose New > Entity Classes from Database.
  2. Select New Data Source from the Data Source drop-down list to open the Create Data Source dialog.
  3. 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.
    Create Datasource dialog box

    The tables in the consult database appear in the Available Tables listbox.

  4. Click Add All in the wizard. Click Next.
    New Entities from Database wizard
  5. Type entities as the Package. Make sure that the checkbox to generate named queries is selected.
  6. 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.

    New Entities from Database wizard
  7. 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.

screenshot of Projects window

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.

  1. 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.

    screenshot of code completion for annotations
  2. 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.

    screenshot of code completion for fields
  3. Fix your imports, if necessary, and save your changes.

Editing Billable.java

Open the Billable entity class and make the following changes.

  1. 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;
  2. 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;
  3. Modify the return statement of the toString method to return the description, consultant id and project:
    public String toString() {
            return description + ", " + consultantId + ", " + project;
  4. Fix your imports, if necessary, and save your changes.

Editing Client.java

  1. 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;
  2. 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.

    Generate Getters and Setters dialog box
  3. 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;
  4. Modify the return statement of the toString method to return String.valueOf(clientPK):
    public String toString() {
        return String.valueOf(clientPK);
    }
  5. Fix your imports, if necessary, and save your changes.

Editing ClientPK.java

  1. Modify the return statement of the toString method to return the client name and department number:
    public String toString() {
        return clientName + ", " + "Dept. " + clientDepartmentNumber;
    }
  2. Save your changes.

Editing Consultant.java

  1. 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;
  2. 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;
  3. Modify the return statement of the toString method to return the email:
    public String toString() {
        return email;
    }
  4. Fix your imports, if necessary, and save your changes.

Editing ConsultantStatus.java

  1. Modify the return statement of the toString method to return the status ID and description:
    public String toString() {
        return statusId + ", " + description;
    }
  2. Save your changes.

Editing Project

  1. 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;
  2. Modify the return statement of the toString method to return the following:
    public String toString() {
        return (projectPK == null ? "(unnamed project)" : projectPK.getProjectName()) + ", " + client;
    }
  3. Save your changes.

Editing Recruiter.java

  1. 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;
  2. Modify the @ManyToOne annotation on the client field to mark the relationship as one-to-one.
    @OneToOne
    private Client client;
  3. Modify the return statement of the toString method to return the email:
    public String toString() {
        return email;;
    }
  4. 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.

  1. 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)

  2. Click Add All to move all the classes to the Selected Entity Classes pane of the wizard. Click Next.
    New JSF Pages from Entity Classes wizard
  3. 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.

screenshot of Web Pages directory in Projects window

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.

  1. 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/.

  2. Click the links to view and add details.
screenshot of browser window with welcomeJSF page

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:

Companion
Projects:
MySQL Database Server   Open JDK: an Open SourceJDK   GlassFish Community: an Open Source Application Server    Mobile & Embedded Community    Open Solaris   java.net - The Source for Java Technology Collaboration   Virtual Box - full virtualizer  Open ESB - The Open Enterprise Service Bus Powered by