Re-execute f:viewAction when ViewScoped bean is recreated following a POST request

我的未来我决定 提交于 2019-12-07 08:39:05

问题


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 as bean.onLoad() would be called on every POST request.
  • I cannot call onLoad() in @PostConstruct method because values have not been set by viewParam 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!