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>
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>
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>
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>
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>
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>
Click Me!
</a>
<input
type="submit" name="j_idt60:j_idt64" value="Click Me!"
/>
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
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