Introduction
There are several ways to achieve this. The naive way is to simply null out the fields in backing bean. The insane way is to grab JS/jQuery for the job which does that after submit or even during page load. Those ways only introduces unnecessary code and indicates a thinking/design problem. All you want is just starting with a fresh request/page/view/bean. Like as you would get with a GET request.
POST-Redirect-GET
The best way is thus to just send a redirect after submit. You probably already ever heard of it: POST-Redirect-GET. It gives you a fresh new GET request after a POST request (a form submit), exactly as you intended. This has the additional benefit that the previously submitted data isn’t re-submitted when the enduser ignorantly presses F5 afterwards and ignores the browser warning.
There are several ways to perform PRG in JSF.
-
Just return to same view with
faces-redirect=true
query string. Assuming a/page.xhtml
, you could do so in action method:public String submit() { // ... return "/page.xhtml?faces-redirect=true"; }
If you’re still fiddling around with navigation cases the JSF 1.x way, then it’s a matter of adding
<redirect/>
to the navigation case in question. See also How to make redirect using navigation-rule. -
To make it more reusable, you can obtain the view ID programmatically:
public String submit() { // ... UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot(); return view.getViewId() + "?faces-redirect=true"; }
Either way, if you’ve view parameters which needs to be retained in the request URL as well, then append
&includeViewParams=true
to the outcome. See also Retaining GET request query string parameters on JSF form submit. -
If you’re making use of some URL rewriting solution which runs outside JSF context, then you’d best grab the current request URL (with query string) and use
ExternalContext#redirect()
to redirect to exactly that.public void submit() throws IOException { // ... ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext(); StringBuffer requestURL = ((HttpServletRequest) ec.getRequest()).getRequestURL(); String queryString = ((HttpServletRequest) ec.getRequest()).getQueryString(); ec.redirect((queryString == null) ? requestURL.toString() : requestURL.append('?').append(queryString).toString()); }
It’s only a mess which should really be refactored to some utility class.
Request/View scoped bean
Note that this all works only nicely in combination with request or view scoped beans. If you’ve a session scoped bean tied to the form, then the bean wouldn’t be recreated from scratch. You’ve then another problem which needs to be solved as well. Split it into a smaller session scoped one for the session scoped data and a view scoped one for the view scoped data. See also How to choose the right bean scope?
Faces Messages
If you’ve a faces message to be shown as result of successful action, then just make it a flash message. See also How to show faces message in the redirected page.
public String submit() {
// ...
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(clientId, message);
context.getExternalContext().getFlash().setKeepMessages(true);
return "/page.xhtml?faces-redirect=true";
}
Ajax
Only if you happen to have an ajax-only page on which a F5 would always trigger a fresh new GET request, then simply nulling out the model field(s) in action method shouldn’t harm that much.