31

这似乎不对。我正在清理我的代码,我才注意到这一点。每个 ajax 请求都在触发构造函数和@PostConstruct我的@ViewScopedbean。即使是简单的数据库分页也会触发它。

知道这比每次请求@ViewScoped都更长,@RequestScoped并且不应该重建它。只有在通过 GET 重新加载完整的页面后。

4

1 回答 1

58

换句话说,你的@ViewScopedbean 的行为就像一个@RequestScopedbean。它在每个回发请求中都从头开始重新创建。这有很多可能的原因,其中大部分归结为相关的 JSF 视图在 JSF 状态下不再可用,而 JSF 状态又默认与 HTTP 会话相关联。

前提是您可以确保 HTTP 会话本身不是问题的根本原因,即当@SessionScoped工作绝对正常时,请查看下面的可能原因列表。否则,如果 HTTP 会话本身也被丢弃并在每个请求上重新创建,那么您需要退后一步,查看会话 cookie 和服务器配置。任何与 HTTP 会话中断相关的原因至少超出了 JSF 的上下文。

  1. 您使用的是 Mojarra 2.1.17 或更早版本,并且视图包含 EL 表达式,这些表达式将视图范围的 bean 属性绑定到在视图构建时评估的标记属性。示例是 JSTL <c:if>, <c:forEach>, 等或 JSF <ui:include>, <x:someComponent id="#{...}",<x:someComponent binding="#{...}">等。这是由 Mojarra 中的错误引起的(问题 1496)。另请参阅为什么 @PostConstruct 回调每次都会触发,即使 bean 是 @ViewScoped?JSF

    这已在 Mojarra 版本 2.1.18 中修复。如果您无法升级到较新版本,解决方法是禁用部分状态保存,如下所示web.xml,另请参阅JSF2 Facelets 中的 JSTL... 有意义吗?

     <context-param>
         <param-name>javax.faces.PARTIAL_STATE_SAVING</param-name>
         <param-value>false</param-value>
     </context-param>
    

    或者,当您只想针对一组特定的 JSF 视图时:

     <context-param>
         <param-name>javax.faces.FULL_STATE_SAVING_VIEW_IDS</param-name>
         <param-value>/foo.xhtml;/bar.xhtml;/folder/baz.xhtml</param-value>
     </context-param>
    

    值得一提的是,将 JSF 组件idbinding属性的值绑定到视图范围的 bean 属性是一种不好的做法。这些确实应该绑定到请求范围的 bean 属性,或者应该寻求替代方案。另请参阅JSF 中的“绑定”属性如何工作?何时以及如何使用它?

  2. 您使用的是 Mojarra 2.2.0,只有该版本在维护 2.2.1 中已修复的视图范围方面存在(尚未知)错误,另请参见问题 2916。解决方案是升级到较新的版本。

  3. @ViewScoped注释是从错误的包中导入的。JSF 提供了两种@ViewScoped注解,一种来自javax.faces.bean用 注释的 JSF 托管 bean 的包@ManagedBean,另一种来自javax.faces.view用 注释的 CDI 托管 bean的包@Named。当 bean 范围注解与 bean 管理注解不匹配时,实际的 bean 范围将成为 bean 管理框架的默认范围,即@RequestScoped在 JSF 托管 bean 和@DependentCDI 托管 bean 中。

    您需要确保您具有以下任一构造并且不要混合它们,另请参阅使用 JSF 2.2 时在每个回发请求上重新创建的 @ViewScoped bean

     import javax.faces.bean.ManagedBean;
     import javax.faces.bean.ViewScoped;
    
     @ManagedBean
     @ViewScoped
     public class CorrectJSFViewScopedBean implements Serializable {
    
     import javax.inject.Named;
     import javax.faces.view.ViewScoped;
    
     @Named
     @ViewScoped
     public class CorrectCDIViewScopedBean implements Serializable {
    
  4. 该视图(意外地?)通过 标记为瞬态<f:view transient="true">。这基本上开启了“无状态 JSF”,这是自 Mojarra 2.1.19 以来的新功能。因此,JSF 视图根本不会保存在 JSF 状态中,逻辑结果是所有引用的视图范围 bean 不能再与 JSF 视图相关联。另请参阅JSF 中无状态的用处是什么?

  5. Web 应用程序配置了com.sun.faces.enableRestoreView11Compatibility上下文参数设置true为“避免”的错误尝试ViewExpiredException。使用此上下文参数,ViewExpiredException将永远不会抛出,但视图(以及所有关联的视图范围 bean)只会从头开始重新创建。但是,如果每个请求都发生这种情况,那么这种方法实际上隐藏了另一个问题:视图过期太快了。这表明在维护 JSF 视图状态和/或 HTTP 会话时可能存在问题。如何正确解决/配置该问题,请前往javax.faces.application.ViewExpiredException: View could not be restore

  6. Web 应用程序的运行时类路径被多个不同版本的 JSF API 或 impl 相关类污染。这会导致 JSF 视图状态的标识符/标记出现损坏/不匹配。您需要确保 webapp 中没有多个 JSF API JAR 文件/WEB-INF/lib。如果您使用 Maven,请确保将服务器提供的库标记为<scope>provided</scope>. 另请参阅我们的 JSF wiki 页面中的“安装 JSF”部分以及此相关问题的答案:如何通过 Maven 正确安装和配置 JSF 库?.

  7. 当您使用 PrimeFaces 时,请<p:dialog>确保它<p:dialog>有自己的<h:form>并且它没有嵌套在另一个中<h:form>。另请参阅p:dialog 中的 p:fileUpload 丢失 @ViewScoped 值

  8. 当您将 PrimeFacesFileUploadFilter与 PrettyFaces 结合使用时,请确保它们FileUploadFilter也在 PrettyFaces 重写/转发的请求上运行。另请参阅使用 PrettyFaces 调用 FileUploadListener 时重建 ViewScoped bean如何使用 PrimeFaces p:fileUpload? 侦听器方法永远不会被调用或 UploadedFile 为空/抛出错误/不可用

  9. 当您使用 PrettyFaces 时,将 CSS/JS/图像资源重定向到绑定到@ViewScopedbean 的 JSF 页面的错误配置的重写规则也会产生误导行为。另请参阅CDI ViewScope 和 PrettyFaces:多次调用 @PostConstruct (JSF 2.2)

于 2011-04-04T17:20:33.040 回答