在POST请求后重新创建ViewScoped bean时重新执行f:viewAction

时间:2015-10-12 09:47:15

标签: jsf jsf-2 view-scope

环境:JSF 2.2与Mojarra 2.2.12& CDI ViewScoped beans& javax.faces.STATE_SAVING_METHOD设置为client

为了通过<f:viewParam ... />正确初始化我的bean,我希望(重新)执行<f:viewAction action="#{bean.onLoad}" />当我的ViewScoped bean 重新创建时(在POST请求之后,视图被从LRU推出,参见com.sun.faces.numberOfLogicalViews)。

<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>

有什么想法吗?

注意:

  • 我知道postBack="true"但不适合bean.onLoad()会在每次 POST请求中调用。
  • 我无法在onLoad()方法中调用@PostConstruct,因为viewParam尚未设置值(参见When to use f:viewAction versus PostConstruct?)。

2 个答案:

答案 0 :(得分:3)

  

我知道onPostback,但它不适合,因为每次POST请求都会调用bean.onLoad()。

您可以在<f:metadata> <f:viewParam maxlength="100" name="name" value="#{bean.file}" required="true" /> <f:viewAction action="#{bean.onLoad}" onPostback="#{empty bean.file}" /> </f:metadata> 属性中使用EL,其中检查模型值和/或请求参数是否存在。

如果需要模型值,则只需检查它是否存在:

<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>

如果不需要模型值,则检查请求参数:

onLoad()
  

我无法在@PostConstruct方法中调用@PostConstruct,因为viewParam尚未设置值。

鉴于您的代码段中存在<o:form>,我发现您正在使用OmniFaces。同一个实用程序库提供了CDI @Param注释,用于在<f:viewParam><f:viewAction>运行之前注入,转换和验证HTTP请求参数。

因此可以替换整个@Inject @Param(name="name", validators="javax.faces.Length", validatorAttributes=@Attribute(name="maximum", value="100")) private String file; @PostConstruct public void onLoad() { if (!Faces.isValidationFailed()) { // ... } } ,如下所示:

@Inject @Param(name="name") @Size(max=100)
private String file;

@PostConstruct
public void onLoad() {
    if (!Faces.isValidationFailed()) {
        // ...
    }
}

或者如果你手头有Bean验证(又名JSR303):

for..in

答案 1 :(得分:0)

虽然我没有使用numberOfLogicalView,但我经常需要重新初始化具有较长生存范围的bean。例如,当用户在表视图中单击某个实体时,用例是(重新)从数据库加载一些详细数据。然后我只使用一些initialized - 标志,例如

@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;
    }
}

使用此模式,您可以将viewAction与postBack="true"一起使用。