The page change but not the URL on clicking <p:commandButton> [duplicate] - jsf

I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?

Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params

Related

getViewId(), getServletPath() and getRequestURI() all returns previous URL, how to get current URL? [duplicate]

I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?
Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params

Why can't the login page for form-based authentication be written in JSF?

I'm just starting down the track of developing web apps and have started with JSF 2.2 on Java EE 7, GlassFish 4.
I thought I'd start with the very basics. I just want to protect the entire site, so every page you navigate to would first require you to authenticate yourself. So I read through the Java EE 7 Tutorial and tried the samples, modified them and then started to break them in ways I didn't think they would break. I tried all sorts of angles, but I'd generally end up in two situations:
I'd try to access a page using a partial request, which would land me at /index.xhtml as defined by <welcome-file-list>, and be prompted to login; but on submitting the username/password I'd be instantly directed back to the login form.
I added an action to the <h:commandButton> to point to index. This worked, but when I submitted the form on the index page which should take me to the response.xhtml page, I'd end up back at the login form instead of at the response page.
After many hours of trawling the net, it seemed that the reason I had broken the login procedure was because I had changed the plain HTML login form to use JSF tags like <h:form>, instead of <form>.
There is a discussion here that says you should not do this with login forms. To quote an interesting line from that page:
To make such a page login, make the actual login form be HTML and not JSF and code it according to the j2EE standards for login forms. Use the HTML form tag instead of the JSF form, and make sure you code an HTML SUBMIT button and not a JSF commandButton!
Once I changed it back to plain old HTML it worked. But I don't understand why. Can anyone enlighten me?! I think I am missing something fundamental which I need to understand if I'm going to start writing web apps in JSF.
Many thanks...
It's because <h:form> submits to the current URL (in web development terms also known as "postback"), not to j_security_check, while the form based authentication intercepts on j_security_check URLs.
It's however not true that using a JSF form for form based authentication is impossible. It's quite possible, you only need to perform the login in backing bean using HttpServletRequest#login() yourself.
See also:
Performing user authentication in Java EE / JSF using j_security_check

How to navigate in JSF? How to make URL reflect current page (and not previous one)

I am currently learning JSF and was rather amazed and puzzled when I realized that whenever we use <h:form>, the standard behavior of JSF is to always show me the URL of the previous page in the browser, as opposed to the URL of the current page.
I understand that this has to do with the way JSF always posts a form to the same page and then just renders whatever page the controller gives it back to the browser which doesn't know the page location has changed.
It seems like JSF has been around for long enough that there must be a clean, solid way to deal with this. If so, would you mind sharing?
I have found various workarounds, but sadly nothing that seems like a real solid solution.
Simply accept that the URL is misleading.
Append "?faces-redirect=true" to the return value of every bean's action and then
figure out how to replace #RequestScoped with something else (Flash Scopes, CDI conversation, #SessionScoped, ...).
accept to have two HTTP round trips for every user action.
Use some method (e.g. 3rd party library or custom code) to hide the page name in the URL, always using the same generic URL for every page.
If "?faces-redirect=true" is as good as it gets, is there a way do configure an entire application to treat all requests this way?
Indeed, JSF as being a form based application targeted MVC framework submits the POST form to the very same URL as where the page with the <h:form> is been requested form. You can confirm it by looking at the <form action> URL of the generated HTML output. This is in web development terms characterized as postback. A navigation on a postback does by default not cause a new request to the new URL, but instead loads the target page as content of the response. This is indeed confusing when you merely want page-to-page navigation.
Generally, the right approach as to navigation/redirection depends on the business requirements and the idempotence (read: "bookmarkability") of the request (note: for concrete code examples, see the "See also" links below).
If the request is idempotent, just use a GET form/link instead of POST form (i.e. use <a>, <form>, <h:link> or <h:button> instead of <h:form> and <h:commandXxx>).
For example, page-to-page navigation, Google-like search form, etc.
If the request is non-idempotent, just show results conditionally in the same view (i.e. return null or void from action method and make use of e.g. <h:message(s)> and/or rendered).
For example, in-page data entry/edit, multi-step wizard, modal dialog, confirmation form, etc.
If the request is non-idempotent, but the target page is idempotent, just send a redirect after POST (i.e. return outcome with ?faces-redirect=true from action method, or manually invoke ExternalContext#redirect(), or put <redirect/> in legacy XML navigation case).
For example, showing list of all data after successful editing, redirect after login, etc.
Note that pure page-to-page navigation is usually idempotent and this is where many JSF starters fail by abusing command links/buttons for that and then complain afterwards that URLs don't change. Also note that navigation cases are very rarely used in real world applications which are developed with respect to SEO/UX and this is where many JSF tutorials fail by letting the readers believe otherwise.
Also note that using POST is absolutely not "more secure" than GET because the request parameters aren't immediately visible in URL. They are still visible in HTTP request body and still manipulatable. So there's absolutely no reason to prefer POST for idempotent requests for the sake of "security". The real security is in using HTTPS instead of HTTP and checking in business service methods if currently logged-in user is allowed to query entity X, or to manipulate entity X, etc. A decent security framework offers annotations for this.
See also:
What is the difference between redirect and navigation/forward and when to use what?
JSF implicit vs. explicit navigation
What URL to use to link / navigate to other JSF pages
Bookmarkability via View Parameters feature
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
When should I use h:outputLink instead of h:commandLink?
Creating master-detail pages for entities, how to link them and which bean scope to choose
Retaining GET request query string parameters on JSF form submit
Pass an object between #ViewScoped beans without using GET params

JSF / Applet integration

In our current prototype most the standard HTML controls are replaced by an applet, most important the form submission is triggered by the applet.
Is there a way to call an associated action on the server side much the same way as with
<h:commandButton action="#{ctrl.doit}"/>?
This article Applet and JSF Integration - example had the same question but not a suitable answer. The applet is a drop in replacement for a form from the viewpoint of the server. It fills dedicated (hidden) fields and submits - no direct communication to a server.
EDIT
So far, i understand there are these integration possibilities:
add a (hidden) UICommand and trigger it via JavaScript
Implement a UICommand of your own. As far as i understand, i'd define a hidden parameter for marking the applet as the form submit control, in the request processing cycle the UICommand implementation will find out and trigger the action. Maybe one should implement a virtual control (comparable to f:viewParam) as an endpoint for MethodExpressions.
Attach a listener, either to a (random) control or a more general event listener and do your stuff here. In this case, how is navigation done?
This is not possible without having a physical JSF view in the very same page which has the applet embedded. So, you should really at least have a <h:form> with a <h:commandButton> in the same page, if necessary hidden by CSS display: none;. This is simply because JSF needs to have a view state of that form in the server side, among others to prevent CSRF-like attacks. If having a physical <h:form> in the page is not a problem for you (which seems to be true in your particular case), then you can just let Applet fill the fields (if any) and click the button of the form using Applet-JavaScript communication.
Other than that, a simple servlet or a real webservice API like JAX-RS/JAX-WS is really the best way. JSF is a component based MVC framework and not a webservice framework. That's what my answer in that linked question is trying to make clear: use the right tool for the job.

jsf - intercept when user departs page

I have the following 3 simple pages in a JSF app.
index.html
start.html
confirmSuccess.thml
start.html is a simple form, with a "GO!" button and a html link back to index.html. When the user clicks GO! it kicks of a transaction in the backing bean. If this fails, I want start.html form redisplayed, but with an error explaining failure. So, I have an error flag set in my backing bean, and the error display is managed using rendered="" attribute.
Simple, right?
So, how do I handle the case where the user then clicks the html link to index.html, and from index.html clicks the link back to start.html, or simply clicks back. That is, how do I clear intercept that user has departed the start page, and clear the error flag so I know second time around that I don't need to display the error.
Is this possible without getting deep into the bowels of JSF lifecycle management?
Note The 3 pages listed is a gross oversimplification of my webapp, in reality, there multiple pages a user can go to from start.html, so I don't want to have a solution where I need to track the page someone arrives at to clear flags for start.
Sounds like you're transferring request scoped data around in a session scoped bean. Make the bean which holds request scoped data request scoped and instruct the browser to not cache the dynamic pages so that it is forced to re-request the page from the webserver instead of from its history.
That said, I'd rather use a combination of FacesContext#addMessage() and <h:messages/> to display errors. You can use an clientId of null to denote global message. They are in turn already request based so that you don't need to hassle with a flag to render/unrender an error display.
E.g.
public void submit() {
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Error!"));
}
with
<h:messages globalOnly="true" />

Resources