The CRUD use case Create involves
creating a new object in main memory and then saving it to persistent
storage with the help of the create
method.
The corresponding create
action method code from the
src/pl/c/BookController.java
is shown below:
public class BookController { ... public String create( String isbn, String title, int year) { try { Book.create( em, ut, isbn, title, year); // clear the form after saving the Book record FacesContext fContext = FacesContext.getCurrentInstance(); fContext.getExternalContext().getRequestMap().remove("book"); } catch ( Exception e) { e.printStackTrace(); } return "create"; } }
The BookController::create
action method invokes the
Book.create
model class method for creating and saving a
Book
instance. It returns the name of the view file found in
the same folder as the view that triggered the action. This file
(create.xhtml
in our case) will be displayed after executing
the action. Using the FacesContext
object, the form is
cleared after creating a Book
instance. The code of the
create
method in src/pl/m/Book.java
is
the following:
public class Book { ... public static void create( EntityManager em, UserTransaction ut, String isbn, String title, int year) throws Exception { ut.begin(); Book book = new Book( isbn, title, year); em.persist( book); ut.commit(); } }
Now we need to create the facelet template for the view of the
Create use case,
WebContent/views/books/create.xhtml
. Such a facelet
template essentially defines an HTML form with data binding and action
binding.
Data
binding refers to the binding of model class
properties to form (input or output) fields. For instance, in the
following facelet code fragment, the entity property
book.isbn
is bound to the form input field
"isbn":
<h:outputLabel for="isbn" value="ISBN: ">
<h:inputText id="isbn" value="#{book.isbn}" />
</h:outputLabel>
In JSF, for the inputText
elements of a form, the
id
attribute is used with a given value, e.g.,
id="isbn"
. The rendered HTML5 input
elements
have both, the id
and the name
attributes, and
their values are obtained by using the form id and element id values
separated by a colon, i.e., id="createBookForm:isbn"
and
name="createBookForm:isbn"
.
We can also see a first example of an expression in the Java EE
Expression Language (EL), where an expression starts with #
and is enclosed in curly brackets, like
#{expression}
. Such an expression allows reading the value of
a property of, or invoking a method on, a Java bean or a context object.
The value of the expression is assigned to the value
attribute of the generated HTML input
element. The example in
our JSF code above is the expression #{book.isbn}
, which
retrieves the value of the isbn
property of the
book
bean.
Action
binding refers to the binding of method invocation
expressions to actionable UI elements, where the invoked methods typically
are controller action methods, and the actionable UI elements typically
are form buttons. For instance, in the following facelet code fragment,
the method invocation expression bookCtrl.create(...)
is
bound to the form's submit button:
<h:commandButton value="Create"
action="#{bookCtrl.create( book.isbn, book.title, book.year)}"/>
After discussing data binding and action binding, it's time to look at the complete code of the facelet:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:ui="..." xmlns:h="..." xmlns:p="..."> <ui:composition template="/WEB-INF/templates/page.xhtml"> <ui:define name="headerTitle"> <h1>Create a new book record</h1> </ui:define> <ui:define name="main"> <h:form id="createBookForm"> <div><h:outputLabel for="isbn" value="ISBN: "> <h:inputText id="isbn" value="#{book.isbn}" /> </h:outputLabel></div> <div><h:outputLabel for="title" value="Title: "> <h:inputText id="title" value="#{book.title}" /> </h:outputLabel></div> <div><h:outputLabel for="year" value="Year: "> <h:inputText id="year" p:type="number" value="#{book.year}" /> </h:outputLabel></div> <div> <h:commandButton value="Save" action="#{bookCtrl.create( book.isbn, book.title, book.year)}" /> </div> </h:form> </ui:define> </ui:composition> </html>
This facelet replaces the main
region of the template
defined in page.xhtml
, because the name
attribute of the ui:define
element has been set to "main",
but it also replaces the headerTitle
region of the template,
which is part of the header
and displays the current
operations allowed by the page.
h:outputLabel
elements can be used for creating form
field labels, while h:inputText
elements are used for
creating HTML input elements. It is possible to specify a HTML5 type of an
input
element by using a special namespace prefix
(xmlns:p = "http://xmlns.jcp.org/jsf/passthrough"
) for the
type
attribute, enforcing it to be 'passed through'. In this
way the year
input field can be defined with type
number
, so it's rendered by the corresponding number widget
in the browser.
The h:commandButton
element allows creating submit
buttons rendered as a input
elements with
type="submit"
, and binding them to an action to be performed
when the button is clicked. The value of the action
attribute
is a method invocation expression. In our Create use case we want that, when the button is
clicked, a Book
instance with the property values provided by
corresponding form fields is created and saved.