ContextNotActiveException, когда bean-компонент OmniFaces ViewScoped внедряется в сервлет

Я только что обновил bean-компонент SessionScoped до OmniFaces (1.6.1) ViewScoped. Кажется, все работает, за исключением того факта, что я получаю следующее исключение, когда мой вспомогательный компонент вводится в сервлет, который я использую для обработки запроса ajax:

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

Некоторые вещи, которые следует учитывать:

1) Причина, по которой мне нужно внедрить резервный компонент в сервлет, заключается в том, что я использую плагин jQuery DataTables, который (для таблиц обработки на стороне сервера) требует запроса ajax для извлечения данных таблицы. Так что в принципе я не могу использовать Primefaces <p:remoteCommand..> или что-то в этом роде.

2) Из того, что я могу сказать, нет никаких дополнительных запросов GET к представлению, которые уничтожили бы и воссоздали вспомогательный компонент.

Есть ли что-нибудь еще, что может вызвать это исключение? Кроме того, если это невозможно сделать, есть ли другой способ добиться того, что я делаю?


person Greg H    schedule 02.10.2013    source источник


Ответы (1)


Аннотация @ViewScoped связывает bean-компонент с конкретным представлением JSF, которое, в свою очередь, зависит от наличия FacesContext#getViewRoot(), а затем UIViewRoot#getViewMap(). Ни один из них не доступен в «простом ванильном» сервлете. Внутри простого запроса сервлета нет средств представления JSF, не говоря уже о контексте JSF. Так что, к сожалению, такое поведение «преднамеренно».

У вас есть в основном 2 варианта:

  1. Сохраните желаемую общую информацию в области сеанса, которая определяется уникальным ключом, который передается как параметр HTTP-запроса, чтобы управляемый компонент JSF и сервлет могли получить ее из области сеанса.

    Например. в компоненте поддержки JSF:

    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) {
            // ...
        });
    }
    

    В сервлете:

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

  2. Используйте настоящий вспомогательный компонент JSF вместо простого ванильного сервлета. Вы определенно можете использовать <p:remoteCommand> для этого. Вы можете использовать метод RequestContext#addCallbackParam() в действии (прослушиватель), чтобы «передать» («печать» технически более правильно) объект JSON с Java на JS и, наконец, использовать атрибут oncomplete для его обработки. Учитывая, что вы используете OmniFaces, <o:commandScript> и Ajax#data() предлагает ту же функциональность. Дополнительным преимуществом Ajax#data() является то, что он автоматически преобразует Java в JSON, поэтому вам не нужно делать это самостоятельно.

    Например. в представлении JSF:

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

    В поддерживающем компоненте JSF:

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

    В JavaScript:

    function processData() {
        var data = OmniFaces.Ajax.data;
        // ...
    }
    
person BalusC    schedule 02.10.2013
comment
Проблема с № 2 заключается в том, что javascript, который отправляет запрос, отправляется плагином datatables. Итак, чтобы настроить его, я бы сделал что-то вроде этого, как описано здесь: datatables.net/examples/ data_sources/server_side.html. Поэтому я не знаю, могу ли я вызвать метод loadData(). Мне пришлось бы либо отказаться от плагина и переписать, как работает таблица, либо использовать № 1, как вы предлагаете, и, вероятно, это подход, который мне придется использовать. Спасибо за быстрый ответ! - person Greg H; 02.10.2013
comment
Я не знаком с этим (<p:dataTable> с ленивой моделью данных намного проще), но не могли бы вы просто дать ей имя функции, которую она должна вызывать? - person BalusC; 02.10.2013
comment
При создании плагина одним из параметров является URL-адрес, передаваемый в виде строки, которую плагин использует для вызова запроса ajax. Поэтому я не думаю, что передача функции сработает (если только она не сработает, и я пропустил это в документации). Я попробую. - person Greg H; 02.10.2013
comment
@BalusC В версии 2 вашего ответа, разве это не должно быть в Javascrpit var data = OmniFaces.Ajax.loadData или это OmniFaces.Ajax.data предопределенное имя? - person John N; 03.10.2013