问题
Environment: JSF 2.2 with Mojarra 2.2.12 & CDI ViewScoped beans & javax.faces.STATE_SAVING_METHOD
set to client
.
In order to properly initialize my bean thanks to <f:viewParam ... />
, I would like to (re-)execute <f:viewAction action="#{bean.onLoad}" />
when my ViewScoped
bean is recreated (view was pushed out from the LRU, cf. com.sun.faces.numberOfLogicalViews) following a POST request.
<f:metadata>
<f:viewParam maxlength="100" name="name" value="#{bean.file}" />
<f:viewAction action="#{bean.onLoad}" />
</f:metadata>
<o:form includeRequestParams="true">
<!-- action can only work if onLoad has been called -->
<p:commandButton action="#{bean.action}" />
</o:form>
Any ideas?
Notes:
- I'm aware of
postBack="true"
but it's not suitable asbean.onLoad()
would be called on every POST request. - I cannot call
onLoad()
in@PostConstruct
method because values have not been set byviewParam
yet (cf. When to use f:viewAction versus PostConstruct?).
回答1:
I'm aware of
postBack="true"
but it's not suitable as bean.onLoad() would be called on every POST request.
You can just use EL in onPostback
attribute wherein you check if the model value and/or request parameter is present.
If the model value is required, then just check if it's present or not:
<f:metadata>
<f:viewParam maxlength="100" name="name" value="#{bean.file}" required="true" />
<f:viewAction action="#{bean.onLoad}" onPostback="#{empty bean.file}" />
</f:metadata>
If the model value is not required, then check the request parameter too:
<f:metadata>
<f:viewParam maxlength="100" name="name" value="#{bean.file}" />
<f:viewAction action="#{bean.onLoad}" onPostback="#{empty bean.file and not empty param.name}" />
</f:metadata>
I cannot call
onLoad()
in@PostConstruct
method because values have not been set by viewParam yet.
Given the presence of <o:form> in your snippet, I see that you're using OmniFaces. The very same utility library offers a CDI @Param annotation for the very purpose of injecting, converting and validating HTTP request parameters before the @PostConstruct
runs.
The entire <f:viewParam><f:viewAction>
can therefore be replaced as below:
@Inject @Param(name="name", validators="javax.faces.Length", validatorAttributes=@Attribute(name="maximum", value="100"))
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}
Or if you've Bean Validation (aka JSR303) at hands:
@Inject @Param(name="name") @Size(max=100)
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}
回答2:
Though I havent been struggeling with the numberOfLogicalView I often need to reinitialize beans with a long living scope. Eg a usecase is to (re-) load some detail data from database when the user clicks on some entity in a table-view. Then I simply use some initialized
-flag, eg
@SomeLongLivingScope
public class MyBean {
private boolean initialized = false;
public void preRenderView() {
if ( initialized ) return;
try {
do_init();
} finally {
initialized = true;
}
}
public void someDataChangedObserver( @Observes someData ) {
...
initialized = false;
}
}
Using this pattern you can use your viewAction with postBack="true"
.
来源:https://stackoverflow.com/questions/33078064/re-execute-fviewaction-when-viewscoped-bean-is-recreated-following-a-post-reque