【问题标题】:ContextNotActiveException when OmniFaces ViewScoped bean is injected in servlet将 OmniFaces ViewScoped bean 注入 servlet 时出现 ContextNotActiveException
【发布时间】:2013-10-02 13:56:15
【问题描述】:

我刚刚将 SessionScoped bean 更新为 OmniFaces (1.6.1) ViewScoped。一切似乎都正常,除了当我的支持 bean 被注入我用于处理 ajax 请求的 Servlet 时,我得到以下异常:

org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type org.omnifaces.cdi.ViewScoped

需要考虑的一些事项:

1) 我必须将支持 bean 注入 servlet 的原因是因为我使用的是 jQuery 的 DataTables 插件,该插件(用于服务器端处理表)需要一个 ajax 请求来检索表数据。所以基本上我不能使用 Primefaces 的<p:remoteCommand..> 或类似的东西。

2) 据我所知,视图中没有任何额外的 GET 请求会破坏和重新创建支持 bean。

还有其他可能导致此异常的原因吗?另外,如果这不能做到,有没有另一种方法来实现我正在做的事情?

【问题讨论】:

    标签: jsf servlets cdi omnifaces view-scope


    【解决方案1】:

    @ViewScoped 注释将 bean 绑定到特定的 JSF 视图,而该视图又依赖于 FacesContext#getViewRoot() 和随后的 UIViewRoot#getViewMap() 的存在。两者都不能在“plain vanilla”servlet 中使用。在普通的 servlet 请求中没有 JSF 视图,更不用说 JSF 上下文了。因此,不幸的是,这种行为是“设计使然”。

    你基本上有两个选择:

    1. 将所需的共享信息存储在会话范围中,该信息由一个唯一键作为键,该键作为 HTTP 请求参数传递,以便 JSF 托管 bean 和 servlet 都可以从会话范围中获取它。

      例如在 JSF 支持 bean 中:

      dataId = UUID.randomUUID().toString();
      externalContext.getSessionMap().put(dataId, data);
      

      在 JSF 视图中:

      <h:outputScript>var dataId = "#{bean.dataId}";</h:outputScript>
      

      在 JavaScript 中:

      function loadData() {
          $.get("servletURL", { dataId: dataId }, function(response) {
              // ...
          });
      }
      

      在 servlet 中:

      String dataId = request.getParameter("dataId");
      Data data = (Data) session.getAttribute(dataId);
      

    2. 使用真正的 JSF 支持 bean 而不是普通的 servlet。你绝对可以使用&lt;p:remoteCommand&gt;。您可以使用RequestContext#addCallbackParam() in action(listener) 方法将 JSON 对象从 Java“传递”(“打印”在技术上更正确)到 JS,最后使用oncomplete 属性对其进行处理。鉴于您使用的是 OmniFaces,&lt;o:commandScript&gt;Ajax#data() 提供相同的功能。 Ajax#data() 的另一个优势是它会自动从 Java 转换为 JSON,因此您无需自己动手。

      例如在 JSF 视图中:

      <o:commandScript name="loadData" action="#{bean.loadData}" oncomplete="processData()" />
      

      在 JSF 支持 bean 中:

      public void loadData() {
          Ajax.data(data);
      }
      

      在 JavaScript 中:

      function processData() {
          var data = OmniFaces.Ajax.data;
          // ...
      }
      

    【讨论】:

    • #2 的问题是发送请求的 javascript 是由 datatables 插件发送的。所以要设置它,我会像这里描述的那样做这样的事情:datatables.net/examples/data_sources/server_side.html。所以我不知道我是否可以调用 loadData() 方法。我要么不得不放弃插件并重写表格的工作方式,要么按照你的建议使用#1,这可能是我必须采取的方法。感谢您的快速回复!
    • 我对此并不熟悉(&lt;p:dataTable&gt; 使用惰性数据模型要容易得多),但你不能只给它需要调用的函数名吗?
    • 在实例化插件时,其中一个选项是作为字符串传递的 url,插件使用它来调用 ajax 请求。所以我不认为传递一个函数会起作用(除非它确实起作用并且我在文档中错过了它)。我试试看。
    • @BalusC 在您答案的第 2 版中,不应该在 Javascrpit var data = OmniFaces.Ajax.loadData 中还是 OmniFaces.Ajax.data 预定义名称?
    猜你喜欢
    • 2015-04-15
    • 1970-01-01
    • 2014-02-09
    • 2011-06-08
    • 1970-01-01
    • 1970-01-01
    • 2013-05-11
    • 2012-11-14
    • 1970-01-01
    相关资源
    最近更新 更多