Getting Started with Jakarta EE 9: Jakarta Faces (JSF)
Originally published on 24 Sep 2021
Last updated on 19 Dec 2023
With Jakarta Faces, you can build user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility. It is a server-side framework that allows for rapid development of web applications, mainly administrative applications which are data entry and business logic heavy. The web pages are created by defining the components that are required and the events that are triggered by the user, and the rendering happens in a separate phase that can be customised to your needs.
In this blog, we mention a few features of Jakarta Faces 3.0 as it is one of the largest specifications of Jakarta EE 9.
Configuration
Just as the other specifications we already discussed, Jakarta Faces requires little to no configuration before we can use it. Since it is part of the Jakarta Web Profile, you do not need to add any additional libraries to your project, the web API dependency at provided scope is enough.
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-web-api</artifactId>
<version>9.0.0</version>
<scope>provided</scope>
</dependency>
The components for the web pages can be defined in several different formats, but most of the time they are defined in xhtml pages. This way, the components can be integrated with other HTML content for the page. Most people define the extension of the pages that can be used by the system in the web.xml file (although this is not strictly required as the xhtml extension is recognized by default since JSF 2.3)
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>jakarta.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
Greeting with JSF
To show you the very basics of Jakarta Faces to connect the data on the screen to the Java beans and methods, let us start with a Hello World kind of application in JSF.
As mentioned, we use xhtml files to define the content of the web applications, so in our src/main/webapp/greeting.xhtml page, we define the following namespace:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html">
The alias h will be used to reference the components defined by Jakarta Faces. The alias value can be freely chosen, the namespace is the value that is recognized by the server.
The greeting example will consist of three elements, an input field for a name, a button to perform the action, and the result of the button click. They can be defined as following in the body of the HTML page:
<h:form>
Name : <h:inputText value="#{helloBean.name}"/> <br/>
<h:commandButton value="Greet" actionListener="#{helloBean.doGreeting()}" /> <br/>
<h:outputText value="#{helloBean.greeting}" />
</h:form>
As you can see, we mix a few JSF components and HTML on the page. The above example is pretty self-explanatory. We only have to look at the references to the HelloBean we make through the Expression Language expressions.
These names beans, like helloBean, are CDI beans that have a specific annotation that defines a name for it so that we can use it in expressions. CDI was already covered in a previous getting started blog, the only new thing is the name.
@RequestScoped
@Named
public class HelloBean {
@Inject
private GreetingService greetingService;
private String name;
private String greeting;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGreeting() {
return greeting;
}
public void doGreeting() {
greeting = String.format(greetingService.getGreetingTemplate(null), name);
}
}
The CDI bean is defined with a Request Scope. So it will be created for each user request and destroyed after the response is sent to the user. Each user will also receive a different instance for each request so that data of different users cannot be mixed up.
It's important to note here that there is no setter for the greeting property, so we cannot use it for an input field. For the data binding in the EL expressions, we use the Bean naming conventions. The input field will use the methods getName() and setName() and a method can be used as an action listener as you can see on the actionListener property of the button.
Since we did not define any navigation rules for the button, the same page is shown again but this time it has the greeting value since the doGreet() method provided a value. Jakarta Faces navigation is not covered in this introduction.
The last important aspect we need to mention is that JSF needs to supply some JavaScript. This is the reason why you need to specify the head and body equivalents within JSF.
<h:head>
<title>Jakarta EE 9 - Greeting</title>
</h:head>
<h:body>
// .. The page content
</h:body>
Validation
Jakarta Faces also takes care of the most common validation tasks on the entered values. You can perform two types of validations, those defined in the components of the web page or those defined on the bean properties. The latter will be handled when we cover the Bean Validation specification, and the first one is briefly described here. Using the JSF validation is not recommended when you have also REST endpoints that validate the same data. In that case, it is better to use the Bean validation as you can define the validation rules both for JSF and Rest.
Besides the basic checks on type, you can also define validations on the content of a field. JSF has already some standard validators built-in, but you can also define your own. The following snippet asks for a name and age value of a person"
<h:messages/>
<h:form>
Name : <h:inputText value="#{personEditBean.name}"/> <br/>
Age : <h:inputText value="#{personEditBean.age}" label="Age">
<f:validateLongRange minimum="1" maximum="120" />
</h:inputText>
<br/>
<h:commandButton value="validate" actionListener="#{personEditPage.save()"/>
</h:form>
Since the Java type of the age property is an integer, JSF will check by default if you have entered a number into the age field. But as you can see, we can further restrict the value for the age property. By using the validateLongRange tag, we can require it to be between 1 and 120. The alias f is created for another default namespace of JSF, called core
xmlns:f="http://xmlns.jcp.org/jsf/core"
It contains several non-graphical elements like the validator we used.
We have also defined a label attribute on the inputField component, so that it used when a validation error is shown to the user (at the location where we have defined the messages component). The idea is of course to use resource bundles so that these labels can be centralised and internationalized so that we can create a multi-language capable application. The resource bundle functionality is also not included in this introduction.
With those definitions in place, every time we click on the validate button and a validation issue is detected, the same page is shown again with the old input values and the error message on top. The Java method linked to the button, save() in the example, is not executed. All data could not be transferred to the CDI beans and thus the method would see incorrect values.
Video - Part A
We have a video with demonstrations of the topics covered so far:
- Faces Web Pages
- Link to Java CDI Beans
- Input Validation
AJAX
In many cases, you do not want all the values on the pages submitted to the server at the same time and for the entire page to refresh. You probably want some feedback after the user has performed some action, like selecting a value in a drop-down list, and that part of the page is updated according to this selection. This is a general principle of Web pages and is known under the term AJAX (Asynchronous JavaScript And XML). Also, Jakarta Faces supports this principle. You can set it up so only certain fields and events are sent to the server and in response, a certain area of the page is updated.
<h:form>
Name : <h:inputText id="name" value="#{ajaxBean.name}"/> <br/>
<h:commandButton value="Greet" actionListener="#{ajaxBean.doGreeting()}">
<f:ajax execute="name @this" render="message"/>
</h:commandButton>
<br/>
<h:panelGroup id="message">
<h:outputText value="#{ajaxBean.greeting}"/>
</h:panelGroup>
#{ajaxBean.now}
</h:form>
The above example has the date and time at the bottom when the page is rendered by the server and shown in the browser. The getNow() method returns this by using the new Date() statement in Java.
We have specified that clicking on the Greet button triggers an AJAX process by using the ajax element in the core namespace. It has two attributes, the IDs of the elements that need to be sent to the server and the IDs of the elements on the screen that need to be updated.
Each Faces component has a unique ID. If you do not specify it, it is auto-generated. For this purpose, we define the ID for the name input field. The @this indicates the component itself and when clicking on the button, the value within the name input field and the button itself is sent to the server. Without the @this, the server would not know about the button and thus cannot perform the Java method.
The greeting is wrapped in a panelGroup component which is not visible on the screen but can be used to only update the greeting message in this example. The date and time information will not change as that part of the screen is not updated, nor is the Java method called related for retrieving the information.
Templating
Most pages in a web application have the same structure. This can be a menu-like area on the left and some header and footer area. If we need to duplicate the components for these areas, it would not be very efficient. Jakarta Faces has a templating mechanism built in. You can define the overall structure of the page and define the areas where each page can specify its specific content. The page itself refers to the template and defines the variable parts.
The xhtml page that will be used to define the template can be located anywhere, but it is a best practice to store it in a specific folder. For our example, I have created the following file within the /template/common/ directory with filename commonLayout.xhtml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:head>
<title><ui:insert name="title">Page Title</ui:insert></title>
<h:outputStylesheet name="common-style.css" library="css"/>
</h:head>
<h:body>
<div id="page">
<div id="header">
<ui:insert name="header">
<ui:include src="/template/common/commonHeader.xhtml"/>
</ui:insert>
</div>
<div id="content">
<ui:insert name="content">
<ui:include src="/template/common/commonContent.xhtml"/>
</ui:insert>
</div>
<div id="footer">
<ui:insert name="footer">
<ui:include src="/template/common/commonFooter.xhtml"/>
</ui:insert>
</div>
</div>
</h:body>
</html>
As you can see, the template file looks like a normal JSF page. The variable parts are indicated by the <ui:insert> elements. the ui alias is typically used for the facelets namespace which was originally a separate library for JSF 1.x but was integrated with JSF 2.0. The insert element requires a name attribute so we can refer later on to the area of the page where certain content needs to be placed.
The components within the <ui:insert> tag is the content shown when the actual page did not define any content for that area. And as you can see, the <ui:insert> can be used everywhere. You have the different areas within the body but you also have one within the head so that you can customize the page title.
The example also shows another feature around templating and reusing, the usage of the <ui:include> element. It is not limited to the <ui:insert> element but can be used everywhere, also on 'regular' pages. You can use it to define a snippet that is the same on different pages and thus it is easier to maintain when you reuse it. Building up the UI with Jakarta Faces is very similar to writing an application using different methods. You can extract parts and include them whenever you need them.
Styling
If you tried the different examples in this blog, you will have noticed that the web pages are very dull. It shows the html elements like an input field but there is no styling available. This is common for web application and also for Jakarta Faces. The HTML code contains the structure and the content. The looks and feel are provided by the CSS of the application.
If you look back at the template example, you can already see the inclusion of a CSS file through the <h:outputStylesheet> element. This way, you can provide the details for what your page will look like.
And Jakarta Faces is also designed with extensibility in mind, just as with all the other Jakarta specifications. PrimeFaces is the most popular JSF framework that brings you about 100 different components and has many different themes so that you can customize your application.
You can add the PrimeFaces library by defining it in the Maven project file or add it to the application artifact. There is already a version available using the Jakarta namespace:
<dependency>
<groupId>org.primefaces</groupId>
<artifactId>primefaces</artifactId>
<version>10.0.0</version>
<classifier>jakarta</classifier>
</dependency>
The library has many components available in the PrimeFaces namespace.
<html xmlns:p="http://primefaces.org/ui">
Look at the documentation on how to use them and the advanced styling capabilities.
Video - Part B
We also have a video covering the more complex topics listed above:
Conclusion
Jakarta Faces has many functionalities to create administrative applications rapidly. You can define the individual components and combine them with other elements. The Faces rendering generates an HTML structure that can be styled with CSS to get the desired visual look and feel of the application. Using expression language, you link it with CDI beans that capture the user inputs on the screen and perform the actions initiated by the users on the screen.
In this blog we have seen how you can define the Facelets pages with the Faces components, link them to Java methods and perform input validation, Partial page refreshes, and templating and Styling.
File Download with Servlets, JSF and JAX-RS
Related Posts
The Payara Monthly Catch - November 2024
Published on 28 Nov 2024
by Chiara Civardi
0 Comments
The Payara Monthly Catch - October 2024
Published on 30 Oct 2024
by Chiara Civardi
0 Comments