My JSF Books/Videos My JSF Tutorials OmniFaces/JSF PPTs
JSF 2.3 Tutorial
JSF Caching Tutorial
JSF Navigation Tutorial
JSF Scopes Tutorial
JSF Page Author Beginner's Guide
OmniFaces 2.3 Tutorial Examples
OmniFaces 2.2 Tutorial Examples
JSF Events Tutorial
OmniFaces Callbacks Usages
JSF State Tutorial
JSF and Design Patterns
JSF 2.3 New Features (2.3-m04)
Introduction to OmniFaces
25+ Reasons to use OmniFaces in JSF
OmniFaces Validators
OmniFaces Converters
JSF Design Patterns
Mastering OmniFaces
Reusable and less-verbose JSF code

My JSF Resources ...

Java EE Guardian
Member of JCG Program
Member MVB DZone
Blog curated on ZEEF
OmniFaces is an utility library for JSF, including PrimeFaces, RichFaces, ICEfaces ...

[OmniFaces Utilities] - Find the right JSF OmniFaces 2 utilities methods/functions

Search on blog

Petition by Java EE Guardians

Twitter

duminică, 21 februarie 2016

JSF Navigation Tutorial - Implicit Navigation

Check also:
The three golden rules of use
JSF Navigation Tutorial - Declarative Navigation
JSF Navigation Tutorial - Conditional Navigation
JSF Navigation Tutorial - Preemptive Navigation
JSF Navigation Tutorial - Programmatic Navigation
JSF VS Series: Implicit Navigation VS Declarative (explicit) Navigation

Implicit navigation is available starting with JSF 2 and is the most common type of navigation used in JSF applications. Until JSF 2, we had to declare all navigation cases in faces-config.xml which was a time consuming task and the result was snippets of XML code hard to maintain. By implicit navigation we don't need the declarative approach anymore and specifying simple navigation cases become pretty straightforward. JSF provides a mechanism for mapping logical outcomes to actual web pages. Now, we have two types of implicit navigation: with no explicit navigation outcome and with explicit navigation outcome.

The simplest implicit navigation case is accomplished by JSF itself whenever you perform an action (request) and no navigation is indicated. When an outcome is indicated the implicit navigation interprets navigation outcomes as target view IDs.


So implicit navigation save us from the tedious task of declaring navigation rules in faces-config.xml and provides us a very intuitive and easy to use mechanism of navigation. Whenever we want to navigate back to the current view, we simply do nothing! What could be simpler than that? Whenever we want to navigate to another view, we simply specify the corresponding outcome in the outcome or action attribute depending on the used navigation tag.

Let's see some examples of using implicit navigation. The managed bean used in the next examples is listed first and the application is named ImplicitNavigation:

@Named
@RequestScoped
public class TheBean {
   
 private static final Logger LOG = Logger.getLogger(TheBean.class.getName());
           
 public void theActionWithVoid(){
  LOG.info("TheBean#theActionWithVoid() called ...");
 }

 public String theActionWithViewID() {
  LOG.info("TheBean#theActionWithViewID() called ...");
  return "success.xhtml";
 }

 public String theActionWithExternalURL() {
  LOG.info("TheBean#theActionWithExternalURL() called ...");
  return "http://showcase.omnifaces.org/";
 }
   
 public String theActionWithOutcome(){
  LOG.info("TheBean#theActionWithOutcome() called ...");
  return "success";
 }
   
 public String theActionWithRedirect(){
  LOG.info("TheBean#theActionWithRedirect() called ...");
  return "success?faces-redirect=true;";
 }   
}

FIRE A JSF GET REQUEST AND NAVIGATE BACK TO THIS VIEW ID
Since there is no outcome JSF will consider this page as the targeted page name

<h:link value="Click me!"/>
<h:button value="Click me!"/>

JSF will render the following HTML (as you see the navigation cases have been hard-coded in page source code):

<a href="/ImplicitNavigation/faces/index.xhtml">Click me!</a>

<input type="button" onclick="window.location.href='/ImplicitNavigation/faces/index.xhtml'; return false;" value="Click me!" />

FIRE A JSF GET REQUEST AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
JSF will interpret the outcome value of <h:link/>/<h:button/> as the targeted page name (success becomes success.xhtml)

<h:link value="Click me!" outcome="success"/>
<h:button value="Click me!" outcome="success"/>

JSF will render the following HTML (as you see the navigation cases have been hard-coded in page source code and they contain success.xhtml):

<a href="/ImplicitNavigation/faces/success.xhtml">Click me!</a>

<input type="button" onclick="window.location.href='/ImplicitNavigation/faces/success.xhtml'; return false;" value="Click me!" />

FIRE A JSF GET REQUEST. PROVIDE THE NAVIGATION OUTCOME VIA A SERVER-SIDE METHOD CALLED DURING COMPUTING THE VIEW ID (AT RENDERING TIME)
JSF will interpret the outcome value of of <h:link/>/<h:button/> as the targeted page name (success returned by theActionWithOutcome() becomes success.xhtml)

<h:link value="Click me!" outcome="#{theBean.theActionWithOutcome()}"/>
<h:button value="Click me!" outcome="#{theBean.theActionWithOutcome()}"/>

JSF will render the following HTML (as you see the navigation cases have been hard-coded in page source code and they contain success.xhtml):

<a href="/ImplicitNavigation/faces/success.xhtml">Click me!</a>

<input type="button" onclick="window.location.href='/ImplicitNavigation/faces/success.xhtml'; return false;" value="Click me!" />

Note The server-side method must return a string representing the outcome.

FIRE A GET REQUEST THAT DOESN'T INTERACT WITH JSF
The <h:outputLink/> will navigate independently of JSF (that means it doesn't interact with JSF)

<h:outputLink value="success.xhtml">Click me!</h:outputLink>
<h:outputLink value="http://showcase.omnifaces.org/">OmniFaces Showcase</h:outputLink>

JSF will render the following HTML (as you see the navigation cases have been hard-coded in page source code; notice that /faces is missing!):

<a href="success.xhtml">Click me!</a>
<a href="http://showcase.omnifaces.org/">OmniFaces Showcase</a>

FIRE A GET REQUEST THAT DOESN'T INTERACT WITH JSF. PROVIDE THE NAVIGATION TARGET VIA A SERVER-SIDE METHOD CALLED DURING COMPUTING THE VIEW ID (AT RENDERING TIME)
The <h:outputLink/> will navigate independently of JSF (that means it doesn't interact with JSF)

<h:outputLink value="#{theBean.theActionWithViewID()}">Click me!</h:outputLink>
<h:outputLink value="#{theBean.theActionWithExternalURL()}">OmniFaces Showcase</h:outputLink>

JSF will render the following HTML (as you see the navigation cases have been hard-coded in page source code; notice that /faces is missing!):

<a href="success.xhtml">Click me!</a>
<a href="http://showcase.omnifaces.org/">OmniFaces Showcase</a>

Note The server-side method must return a string representing the navigation target NOT an outcome (e.g. you must return success.xhtml, not success). Since the fired GET request will not pass through JSF  the outcome will not be computed!

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM AND NAVIGATE BACK TO THIS VIEW ID
Since there is no action JSF will consider this page as the targeted page name

<h:form>
 <h:commandLink value="Click Me!"/>
 <h:commandButton value="Click Me!"/>
</h:form>

JSF will render the following HTML (as you see the navigation cases are not hard-coded). Even if we have a HTML <a> and an <input type="submit">  there is no functional difference between them. Both will submit the form and navigate back to the current view ID.

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt30'),{'j_idt30:j_idt32':'j_idt30:j_idt32'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt30:j_idt34" value="Click Me!" />

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM. INVOKE A VOID ACTION METHOD AND NAVIGATE BACK TO THIS VIEW ID
There is an action but it points to an void action method. JSF will invoke the theBean#theActionWithVoid() action method and consider this page as the targeted page name

<h:form>
 <h:commandLink value="Click Me!" action="#{theBean.theActionWithVoid()}"/>
 <h:commandButton value="Click Me!" action="#{theBean.theActionWithVoid()}"/>
</h:form>

JSF will render the following HTML:

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt36'),{'j_idt36:j_idt38':'j_idt36:j_idt38'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt36:j_idt40" value="Click Me!" />

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
JSF will interpret the action value of <h:commandLink/Button/> as the targeted page name (success becomes success.xhtml)

<h:form>
 <h:commandLink value="Click Me!" action="success"/>
 <h:commandButton value="Click Me!" action="success"/>
</h:form>

JSF will render the following HTML:

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt42'),{'j_idt42:j_idt44':'j_idt42:j_idt44'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt42:j_idt46" value="Click Me!" />

FIRE (SUBMIT) A POST REQUEST VIA REDIRECT MECHANISM AND NAVIGATE TO THE VIEW ID COMPUTED FROM THE SPECIFIED OUTCOME
The presence of ?faces-redirect=true; will instruct JSF to rely on POST-redirect-GET (PRG) navigation pattern

<h:form>
 <h:commandLink value="Click Me!" action="success?faces-redirect=true;"/>
 <h:commandButton value="Click Me!" action="success?faces-redirect=true;"/>
</h:form>

JSF will render the following HTML:

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt48'),{'j_idt48:j_idt50':'j_idt48:j_idt50'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt48:j_idt52" value="Click Me!" />

FIRE (SUBMIT) A POST REQUEST VIA FORWARD MECHANISM. INVOKE AN ACTION METHOD AND NAVIGATE TO THE VIEW ID COMPUTED BASED ON THE OUTCOME RETURNED BY THIS METHOD
The action can point to an action method that returns a String. This string is considered the outcome and it will be interpreted as the targeted page name (success becomes success.xhtml)

<h:form>
 <h:commandLink value="Click Me!" action="#{theBean.theActionWithOutcome()}"/>
 <h:commandButton value="Click Me!" action="#{theBean.theActionWithOutcome()}"/>
</h:form>

JSF will render the following HTML:

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt54'),{'j_idt54:j_idt56':'j_idt54:j_idt56'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt54:j_idt58" value="Click Me!" />

FIRE (SUBMIT) A POST REQUEST VIA REDIRECT MECHANISM. INVOKE AN ACTION METHOD AND NAVIGATE TO THE VIEW ID COMPUTED BASED ON THE OUTCOME RETURNED BY THIS METHOD
The action can point to an action method that returns a String suffixed with ?faces-redirect=true; (will instruct JSF to rely on POST-redirect-GET (PRG) navigation pattern). This string is considered the outcome and it will be interpreted as the targeted page name (success becomes success.xhtml)

<h:form>
 <h:commandLink value="Click Me!" action="#{theBean.theActionWithRedirect()}"/>
 <h:commandButton value="Click Me!" action="#{theBean.theActionWithRedirect()}"/>
</h:form>

JSF will render the following HTML:

<a href="#" onclick="mojarra.jsfcljs(document.getElementById('j_idt60'),{'j_idt60:j_idt62':'j_idt60:j_idt62'},'');return false">
 Click Me!
</a>

<input type="submit" name="j_idt60:j_idt64" value="Click Me!" />

The complete application is available here.

Notes
Logic of outcome
When implicit navigation takes place it follows the next steps:

1.Look for the ? character in the logical outcome. If it is found then capture the query string and look for the presence of faces-redirect=true request parameter. Remember that this parameter points to a redirect navigation case.

2.Look for the file extension attached to the logical outcome. If none is found then automatically attached the extension of current view ID (e.g. xhtml)

3.If the logical outcome doesn't begin with a / then prepend the location of the current view ID (e.g., /, /pages/, etc.).

4. Locate the view ID. If it is not found then abort implicit navigation.

5.For non-redirect cases simply build and render the view ID in the current request. If it is a redirect then build a redirect URL. The query string parameters captured earlier is appended to this URL. Redirect to this URL.

Use Sub-folders
If your views are stored in subfolders then simply prefix the outcome with the corresponding path (e.g. if the view login.xhtml is stored in /mypages/credentials folder then an outcome will be: mypages/credentials/login).

Use Application Context
Whenever you want to add the application context path in a URL (for example, the URL generated via <h:outputLink>, you can use the ExternalContext.getApplicationContextPath method of JSF 2.2. For example, take a look at the following code:

<h:outputLink value="#{facesContext.externalContext.applicationContextPath}/next.xhtml">Next</h:outputLink>

Forward vs Redirect
By default, between forward and redirect, JSF will navigate from one page to another using the forward mechanism (HTTP POST). When JSF receives the user action, it will forward the user to the determined target page, which means that the URL displayed by the browser will not be updated to reflect the current target. Keeping the browser URL updated implies the page redirection mechanism; in this case, JSF, delegates the browser to send a separate GET request to the target page. You can use the page redirection mechanism by attaching the faces-redirect=true as you saw in the above examples. In the forward case, the browser URL is not updated (is with a step behind navigation URL), but there is a single request. In the redirect case, the browser URL is up to date, but there are two requests. Since forward needs a single request, it is faster than page redirection. The speed is lower, but page redirection solves the duplicated form submission problem found in the Post-Redirect-Get design pattern. Of course, this is not the case for <h:link/>, <h:button/>, and <h:outputLink/>.
We can conclude that POST via forward result in non-bookmarkable URL while POST via redirect result in bookmarkable URL and this is a major SEO aspect also.

Outcome vs View ID
In all the examples above we have used the outcome version (success) instead of view ID (success.xhtml).  In not a good idea to use view ID directly since you may decide to give up on *.xhtml mapping and use *.jsf. In such case, you will have to modify the success.xhtml in success.jsf. This will happen for all such navigation cases. Using the success outcome will not require any further adjustments.

Outcome vs Action
If you are a novice then is very possible to confuse these two attributes. Basically, the outcome attribute is specific to <h:link/> and <h:button/> tags. Its role is to point to the logical outcome used to resolve a navigation case and the tags that support it cannot submit a form. On the other hand, the action attribute is specific to commands capable to submit forms (<h:commandLink/> and <h:commandButton/>).  This attribute is a String representing the logical outcome or a MethodExpression representing the application action to invoke when this component is activated by the user. The expression must evaluate to a public method that takes no parameters, and returns an Object (the toString() of which is called to derive the logical outcome) which is passed to the NavigationHandler for this application. 

Niciun comentariu :

Trimiteți un comentariu

JSF BOOKS COLLECTION

Postări populare

Follow by Email

Visitors Starting 4 September 2015

Locations of Site Visitors