Learning JSF 2 series continues with page parameters and page actions. Read other Learning JSF 2 articles.
If you worked with JSF 1.2, you know that calling a page action wasn’t simple. A page action is useful when you request a page for the first time (GET request) and would like to prepare some data to be rendered on a view (page). Of course there are some workarounds, one of them is to use @PostConstruct method inside the bean or even create a phase listener. Both could work but developers desired a more robust, and out of the box solution similar to what Seam 2 provides.
A feature that closely relates to page action is page params (page parameters). Usually when you issue a get request like this:
http://host/app/page.jsf?productId=101
you want the productId request parameter to be assigned to a property inside a bean so that you can use the id inside action (page action) to load data to display on the page. In JSF 1.2, you would end up doing something like this:
Managed bean:
@ManagedBean(name="bean") public class Bean { private Integer productId; // getter and setter }
JSF configuration file:
bean test.Bean request productId #{param['productId']}
#{param} is an implicit object in JSF that holds all request parameters. In the code snippet above, we are taking the value of productId and assigning it to productId property inside the bean using JSF managed bean facility. It’s just not an elegant solution and it doesn’t offer any flexibility, ability to validate the value, and also defined separately from the actual page.
The good news is that both page actions and page params are supported by JSF 2. Let’s start with page params.
Page params
We all know that when we have a JSF input field bound to a bean property and we submit the page ( POST), the value entered in the page automatically get pushed into the bean (assuming no conversion/validation errors or anything else stopping the life cycle).
JSF page:
Bean:
public class Bean { private Integer productId; // getter and setter }
The easiest way to think of page params is that the same thing is happening as above but only without input fields on the page. Instead, the values are submitted via the GET URL and pushed in the same way into the bean:
http://host/app/page.jsf?productId=101
In both cases the result is the same, the value either from the page or URL is set into the property. We know how to do it with input field bound to a property during a POST. Let’s see what needs to be done when a GET request is issued. We have to somehow map the request param to bean properties.
JSF 2 introduced a new metadata tag called inside which pages params are defined:
...
In the code example above tag contains two new tags in JSF 2. As you guessed, the tag defines and maps two page params to bean properties. In the first one, productId param is mapped to bean.productId property. The second param text is mapped to bean.text bean property. The following GET request will take productId value of 101 and text value of ‘nice’ and set them into their respective bean properties:
http://localhost:port/app/page.jsf?productId=111&text=nice
A quick and easy way to test that values were set into the proprieties is just to render the values on the page:
Default values
If bean properties are set to some initial values page params will overwrite them (same as with a POST). If page params are not provided then during rendering the default values will be displayed.
Good to know
The tag is actually an alias for a special view level facet in JSF 2:
As this metadata tag going to be used extensively, a shortcut tag (alias) was created:
The tag is actually not required. As we are using Facelets (default in JSF 2), the entire page is a view by default.
Conversation and validation
When a value is submitted via a POST it can bean converted and validated before being pushed into the bean property. For a GET request, conversation and validation can be invoked in a similar fashion. When either fails, error message can be displayed just like with a POST.
When components are bound to a bean property, a converted or validator is registered with the component on the page. As we don’t have a component, conversation and validation is added to the tag.
Requiring a value
To make a value required, we use the familiar required attribute and overwrite the default error message:
To display the error message, is added to the page:
Note: we have to use as the message is not associated with any component.
For example, the following request:
http://localhost:port/app/page.jsf?productId=111&text=
will produce the following:
As we didn’t provide a value for text, validation fails. productId is also not set as Update Model phase was not executed (as expected after validation fails).
Good to know
When a page (view) is requested via a GET and no page params are present, Restore View and Render Respose phases will be executed (same behavior you get in JSF 1.2). Once page params are added to a GET request, JSF will run through the full life cycle in order to convert and validate the values and then set the values into the bean.
More validation
In addition to requiring a value, we can attach other standard validators to page params such as range validator for numbers and length validator for strings. For example:
In this example, was added to productId param and to text param. For both custom validation error message was set.
For example the request with the parameters which not meets the requirements specified will produce the following:
Lastly, a custom validator can be attached as well via validator attribute (in which case the method is validation method is placed inside the bean):
or with tag (in which case a class is defined which implements the Validator interface):
Conversion
As with validation, conversation is added in similar fashion. When we do a POST, all values are first converted and then validated. All values entered on a page are sent as strings and need to be converted before pushed into bean properties. Page param values are also sent as plain strings. Taking the productId param, a converter could be added like this:
This is just to demonstrate how it’s done but we don’t actually have to register the integer converter. Integer converter is one of the default converters in JSF which means that JSF will try to convert the value automatically. The converter attribute could be used to attached a custom converter as well.
Page actions
Page actions can be used to initialize data to be rendered in the view. Page actions are added with new the tag inside view metadata.
Two things are specified above, the event type (preRenderView) and the action listener to be invoked. The preRenderView event type indicates that this listener will be invoked during Render Respone phase.
Just for demonstration purposes, let’s use the productId value as a counter for the number of times to insert text value into a list and then display it.
Bean:
public ArrayList list; // getter public void loadAction() { list = new ArrayList(); for (int i = 0; i < productId ; i++) { list.add(text); } }
For this to work, page params need to be set first and that’s exactly what happens. Page params are set into the model during Update Model phase and page action is invoked during Render Response phase (just before the rendering). We use a page param (productId) to decide how many times to insert the text value into the list. To render the list, we use this:
- #{txt}
Entering the following URL:
http://host:port/app/page.jsf?productId=5&text=JSF2
will produce the following:
Note that if conversation or validation fails, the listener (page action) is still invoked. However, an exception will be thrown as productId is null (unless it’s initialized to some value). One option is to check if any error messages were queued and skip the listener logic. For example:
public void loadAction() { List messages = FacesContext.getCurrentInstance() .getMessageList(); if (messages.size() == 0) { list = new ArrayList(); for (int i = 0; i < productId ; i++) { list.add(text); } } }
Note: if only page action is present without page params, then only Restore View and Render Response phase are executed.
Summary
Page params and page actions are two great features in JSF 2. Being able to issue a GET with request params also allows to create bookmarkable URLs. Bookmarkable URLs and how page params are tied to navigation as well as the new and tags will be covered in the next article in this series.
Leave a Reply to max Cancel reply