在 POST 请求后重新创建 ViewScoped bean 时重新执行 f:viewAction
Re-execute f:viewAction when ViewScoped bean is recreated following a POST request
环境:JSF 2.2 和 Mojarra 2.2.12 & CDI ViewScoped beans & javax.faces.STATE_SAVING_METHOD
设置为 client
。
由于 <f:viewParam ... />
,为了正确初始化我的 bean,我想在 ViewScoped
bean 重新创建时(重新)执行 <f:viewAction action="#{bean.onLoad}" />
(视图被从 LRU 推出,参见 com.sun.faces.numberOfLogicalViews)在 POST 请求之后。
<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"
但它不适合,因为 每个 POST 请求都会调用 bean.onLoad()
。
- 我无法在
@PostConstruct
方法中调用 onLoad()
,因为 viewParam
尚未设置值(参见 When to use f:viewAction versus PostConstruct?)。
虽然我没有为 numberOfLogicalView 苦苦挣扎,但我经常需要重新初始化具有较长生命周期的 bean。例如,一个用例是当用户点击 table-view 中的某个实体时(重新)从数据库加载一些详细数据。然后我简单地使用一些initialized
-flag,例如
@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"
一起使用。
I'm aware of postBack="true"
but it's not suitable as bean.onLoad() would be called on every POST request.
您可以只在 onPostback
属性中使用 EL,在其中检查模型值 and/or 请求参数是否存在。
如果需要模型值,则只需检查它是否存在:
<f:metadata>
<f:viewParam maxlength="100" name="name" value="#{bean.file}" required="true" />
<f:viewAction action="#{bean.onLoad}" onPostback="#{empty bean.file}" />
</f:metadata>
如果不需要模型值,那么也检查请求参数:
<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.
考虑到 <o:form>
in your snippet, I see that you're using OmniFaces. The very same utility library offers a CDI @Param
注释的存在是为了在 @PostConstruct
运行之前注入、转换和验证 HTTP 请求参数。
因此整个 <f:viewParam><f:viewAction>
可以替换如下:
@Inject @Param(name="name", validators="javax.faces.Length", validatorAttributes=@Attribute(name="maximum", value="100"))
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}
或者,如果您手边有 Bean 验证(又名 JSR303):
@Inject @Param(name="name") @Size(max=100)
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}
环境:JSF 2.2 和 Mojarra 2.2.12 & CDI ViewScoped beans & javax.faces.STATE_SAVING_METHOD
设置为 client
。
由于 <f:viewParam ... />
,为了正确初始化我的 bean,我想在 ViewScoped
bean 重新创建时(重新)执行 <f:viewAction action="#{bean.onLoad}" />
(视图被从 LRU 推出,参见 com.sun.faces.numberOfLogicalViews)在 POST 请求之后。
<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"
但它不适合,因为 每个 POST 请求都会调用bean.onLoad()
。 - 我无法在
@PostConstruct
方法中调用onLoad()
,因为viewParam
尚未设置值(参见 When to use f:viewAction versus PostConstruct?)。
虽然我没有为 numberOfLogicalView 苦苦挣扎,但我经常需要重新初始化具有较长生命周期的 bean。例如,一个用例是当用户点击 table-view 中的某个实体时(重新)从数据库加载一些详细数据。然后我简单地使用一些initialized
-flag,例如
@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"
一起使用。
I'm aware of
postBack="true"
but it's not suitable as bean.onLoad() would be called on every POST request.
您可以只在 onPostback
属性中使用 EL,在其中检查模型值 and/or 请求参数是否存在。
如果需要模型值,则只需检查它是否存在:
<f:metadata>
<f:viewParam maxlength="100" name="name" value="#{bean.file}" required="true" />
<f:viewAction action="#{bean.onLoad}" onPostback="#{empty bean.file}" />
</f:metadata>
如果不需要模型值,那么也检查请求参数:
<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.
考虑到 <o:form>
in your snippet, I see that you're using OmniFaces. The very same utility library offers a CDI @Param
注释的存在是为了在 @PostConstruct
运行之前注入、转换和验证 HTTP 请求参数。
因此整个 <f:viewParam><f:viewAction>
可以替换如下:
@Inject @Param(name="name", validators="javax.faces.Length", validatorAttributes=@Attribute(name="maximum", value="100"))
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}
或者,如果您手边有 Bean 验证(又名 JSR303):
@Inject @Param(name="name") @Size(max=100)
private String file;
@PostConstruct
public void onLoad() {
if (!Faces.isValidationFailed()) {
// ...
}
}