The Create use case involves creating a new object in
main memory and then saving it to persistent storage with the help of the add
method.
The corresponding add
action method code from the
src/pl/ctrl/BookController.java
is shown
below:
public class BookController { ... public String add( String isbn, String title, int year) { try { Book.add( 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::add
action method invokes the Book.add
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. In lines 5
and 6 above, using a FacesContext
object, the form is cleared after creating a
Book
instance. The code of the add
method in
src/pl/model/Book.java
is the following:
public class Book {
...
public static void add( 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 a 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}" />
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"
.
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 element typically are form
buttons. For instance, in the following facelet code fragment, the method invocation expression
bookCtrl.add(...)
is bound to the form's submit
button:
<h:commandButton value="Create"
action="#{bookCtrl.add( 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 template:
<!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="main"> <h:form id="createBookForm"> <h:panelGrid columns="2"> <h:outputLabel for="isbn" value="ISBN: " /> <h:inputText id="isbn" value="#{book.isbn}" /> <h:outputLabel for="title" value="Title: " /> <h:inputText id="title" value="#{book.title}" /> <h:outputLabel for="year" value="Year: " /> <h:inputText id="year" p:type="number" value="#{book.year}" /> </h:panelGrid> <h:commandButton value="Create" action="#{bookCtrl.add( book.isbn, book.title, book.year)}"/> </h:form> <h:button value="Main menu" outcome="index" /> </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".
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.