I am having trouble navigating between my JSF pages. Most of my navigation happens when you click a command button. The action of the command button returns a string.
My log in page is my welcome page. Here it is in my web.xml:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/pages/index.xhtml</welcome-file>
</welcome-file-list>
In my browser's address bar, the page appears as:
http://localhost:8080/ui/faces/pages/index.xhtml
Once authentication happens, the function returns this String:
"/ui/faces/pages/home.xhtml"
The file I want to navigate to is located at:
pages/home.xhtml
However when navigation is supposed to happen, I get this error:
Unable to find matching navigation case with from-view-id '/pages/index.xhtml' for action '#{indexPageController.login()}' with outcome '/ui/faces/pages/home.xhtml'
Can anyone help me understand the relative path I need to correctly navigate to the page?
You should not include the context path /ui nor the FacesServlet mapping /faces in the navigation case outcome. It should just represent the sole view ID, which is basically just the path to the physical view file absolute to the webcontent root or relative to the current view ID.
So, absolute (starting with /) to the webcontent root:
/pages/home.xhtml
Or relative (not starting with /) to the current view ID (assuming that you're in /pages/index.xhtml):
home.xhtml
Do note that dot-slash ./ and double-dot-slash ../ notations are not supported.
Or even without file extension; JSF will imply the Facelets default suffix which defaults to .xhtml and is configureable by javax.faces.DEFAULT_SUFFIX context parameter:
/pages/home
home
It makes after all also sense if you realize that the context path /ui and the FacesServlet mapping /faces/* are not controllable from inside the webapp on! If they ever change externally, then you'd theoretically need to change all navigation case outcomes in the entire codebase and rebuild the webapp. This would not make any sense. JSF takes thus already care of them for you.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between h:button and h:commandButton
When should I use h:outputLink instead of h:commandLink?
What URL to use to link / navigate to other JSF pages
Related
I am having trouble navigating between my JSF pages. Most of my navigation happens when you click a command button. The action of the command button returns a string.
My log in page is my welcome page. Here it is in my web.xml:
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>faces/pages/index.xhtml</welcome-file>
</welcome-file-list>
In my browser's address bar, the page appears as:
http://localhost:8080/ui/faces/pages/index.xhtml
Once authentication happens, the function returns this String:
"/ui/faces/pages/home.xhtml"
The file I want to navigate to is located at:
pages/home.xhtml
However when navigation is supposed to happen, I get this error:
Unable to find matching navigation case with from-view-id '/pages/index.xhtml' for action '#{indexPageController.login()}' with outcome '/ui/faces/pages/home.xhtml'
Can anyone help me understand the relative path I need to correctly navigate to the page?
You should not include the context path /ui nor the FacesServlet mapping /faces in the navigation case outcome. It should just represent the sole view ID, which is basically just the path to the physical view file absolute to the webcontent root or relative to the current view ID.
So, absolute (starting with /) to the webcontent root:
/pages/home.xhtml
Or relative (not starting with /) to the current view ID (assuming that you're in /pages/index.xhtml):
home.xhtml
Do note that dot-slash ./ and double-dot-slash ../ notations are not supported.
Or even without file extension; JSF will imply the Facelets default suffix which defaults to .xhtml and is configureable by javax.faces.DEFAULT_SUFFIX context parameter:
/pages/home
home
It makes after all also sense if you realize that the context path /ui and the FacesServlet mapping /faces/* are not controllable from inside the webapp on! If they ever change externally, then you'd theoretically need to change all navigation case outcomes in the entire codebase and rebuild the webapp. This would not make any sense. JSF takes thus already care of them for you.
See also:
How to navigate in JSF? How to make URL reflect current page (and not previous one)
Difference between h:button and h:commandButton
When should I use h:outputLink instead of h:commandLink?
What URL to use to link / navigate to other JSF pages
Here is file structure of my JSF application.
User directory is secured & one needs to authenticate to see user/success.xhtml. user/success.xhtml has a button which is used to logout. That button submits form to following method.
public String logout(){
HttpSession session = (HttpSession)FacesContext.getCurrentInstance().getExternalContext().getSession(false);
session.invalidate();
return "index";
}
Last line of above method is there to redirect user to index.xhtml, as index.xhtml is not in the same directory as user/success.xhtml so I am getting following error.
Unable to find matching navigation case with from-view-id
'/user/success.xhtml' for action '#{AccContrl.logout()}' with outcome
'index'
How can I redirect to a file present up in the hierarchy?
I tried return "/../index"; but it didn't work.
The navigation outcome represents a view ID. If it does not start with /, then it is interpreted relative to the current path. If it starts with /, then it is interpreted relative to the web root.
So, just use /index.
return "/index";
Unrelated to the concrete problem, you should be redirecting here, not navigating. Not only because you should always perform a redirect when you intend to naviage away after POST, but also because the invalidated session is still present in the current request/response, but only not anymore in the next one.
return "/index?faces-redirect=true";
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to invalidate session in JSF 2.0?
I'm exploring the new features in JSF 2.2 (pretty cool so far) but I still don't understand how Protected Views works, I created a facelet1 with a link to facelet2, like this:
<h:link styleClass="link" value="Go to protected page" id="link1"
outcome="/protected/facelet2.xhtml"></h:link>
and in my faces-config.xml I added this:
<protected-views>
<url-pattern>/protected/facelet2.xhtml</url-pattern>
</protected-views>
Now when I run the page a token is added in the url:
http://localhost:8080/<project>/protected/facelet2.faces?javax.faces.Token=1426608965211
According to the documentation, if the token does not match with the one in the server, the GET request is not processed (is my understanding correct?).
But if I modify the token (using Firebug or the dev tools included in the browser) the request is still processed, even if the token was modified.
Am I doing something wrong?
This is caused because your FacesServlet is apparently mapped on JSF 1.0-style URL pattern of *.faces instead of JSF 2.0-style URL pattern of *.xhtml. The <protected-views><url-pattern> must match the actual URL pattern as you see in browser's address bar.
So, given an actual URL of /protected/facelet2.faces, you need to configure it as below:
<protected-views>
<url-pattern>/protected/facelet2.faces</url-pattern>
</protected-views>
However, while at it, I discovered some nasty issues in current Mojarra 2.2.10 implementation:
It does actually not do a prefix/suffix match as per Servlet 12.1 specification (there's even a vague comment in source code indicating that!). It does merely an exact match. This means, you can't use wildcard URL patterns like /protected/*.
When generating the <h:link>, it does not compare the protected view URL pattern to the resolved URL, but to the JSF view ID. And, when checking an incoming request, it does not compare the request URL to the JSF view ID (like as during link generation), but to the <url-pattern>. This thus never matches, totally explaining why you could simply access it without a valid token.
Basically, you need the following configuration if you need to keep the JSF 1.0-style URL pattern of *.faces.
<protected-views>
<url-pattern>/protected/facelet2.xhtml</url-pattern>
<url-pattern>/protected/facelet2.faces</url-pattern>
</protected-views>
It'll then properly throw javax.faces.application.ProtectedViewException when being accessed without a valid token. Much better is to just map the FacesServlet explicitly on *.xhtml in web.xml.
<servlet-mapping>
<servlet-name>facesServlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
This way you never need to deal with virtual URLs.
I've reported this to Mojarra guys as issue 3837.
See also:
Sometimes I see JSF URL is *.jsf, sometimes *.xhtml and sometimes /faces/*. Why?
I'd like to have different contents displayed when a portlet is in "normal mode" as opposed to "maximized mode". I'm using JSF as the view technology. Is there a check I can perform on the JSF end to check which view is currently being used?
Digging around on my own, I found out that #{request.windowState} gives you normal, maximized or minimized based on current view. Using this, there can be multiple solutions:
Do a #{request.windowState == 'normal'} check and conditionally
display content.
Use <ui:include src="#{request.windowState}.xhtml"
/> in my main view and then create normal.xhtml and maximized.xhtml
ui:composition files.
I am running JSF 2.0 and the latest version of Primefaces 2.2RC1 I believe. I am trying to create a printer friendly window. When the user clicks on a p:commandLink I want a new window to open and display a xhtml file I have named printView.xhtml.
Now I can get the window working fine using JavaScript window.open but when I open the new window it will not render any values it just displays everything as #{myBean.value}. Does anyone know how to properly open a window and extend the current scope of the application into that window so I can call all of my managed beans properly and display the values etc. etc.
it just displays everything as #{myBean.value}
So, the FacesServlet wasn't been invoked. It is the one responsible for doing the JSF works. You need to ensure that the URL in the window.open() matches the url-pattern of the FacesServlet as definied in web.xml.
If it is for example *.jsf, then you need to open it as follows:
window.open('printView.jsf');
Just an FYI, 2.2.RC1 had some bugs. You'll want version 2.2.RC2.