Как установить значение параметра в bean-компоненте SessionScoped перед вызовом @PostConstruct в bean-компоненте RequestScoped - PullRequest
2 голосов
/ 19 февраля 2012

Буду признателен за помощь в решении следующих проблем (JBoss 6.0, Mojarra - 2.2 Snapshot, facelet 1.1 и PrimeFaces 3.0.M4:

Проблема в том, что метод post-конструкции bean-компонента запроса вызывается до получения установленного значения. Как мы можем убедиться, что сначала устанавливается значение параметра в сессионном компоненте, а затем вызывается метод post-конструкции объекта запроса.

Проблема № 1: При нажатии кнопки «Далее», которая является вызовом ajax 1. testRequestBB "инициализировать" метод пост-конструкции вызывается 2. Метод «next» testSessionBB вызывается для установки значения

Ожидаемое поведение должно быть другим, установить значение в сессионном компоненте с помощью вызова ajax, а затем запросный компонент должен быть инициализирован.

Проблема №2: метод пост инициализации компонента инициализации объекта запроса вызывается дважды.
- Это потому, что bean-компонент запроса расширяется из базового класса (хотя в базовом классе нет метода post-construct).

Что можно сделать, чтобы решить эту проблему, вызвав метод post-construct, вызываемый два раза при отображении страницы test.xhtml?

Вот код:

test.xhtml

<h:dataTable id="testId" emptyMessage="#{messages.noData}" var="test" value="#{testList}">
....
<f:facet name="footer">
    <h:form id="pgId">                  
        <h:commandLink value="#{messages.next} ">
            <f:ajax listener="#{testSessionBB.next}" />
        </h:commandLink>
            .....
    </h:form>
</f:facet>
</h:dataTable>

TestSessionBB.java

@Named("testSessionBB")
@SessionScoped
public class TestSessionBB implements Serializable
{
    private int testStartRow;
    .....

    public String next() 
    {
        if (this.getTestStartRow() + 5 > 15) // hard coded value for simplicity in this post
        {
            this.setTestStartRow(15);
        } else {
            this.setTestStartRow(this.getTestStartRow() + 5);
        }
        log.debug("next - testStartRow: " + this.getTestStartRow());

        return "";
    }
}

TestRequestBB.java

@Named
@RequestScoped
public class TestRequestBB extends testBase implements Serializable {

    ....

    @PostConstruct
    public void initialize()
    {
        log.debug("Initializing TestRequestBB backing bean ...");

        setTestList(allTests()); // load initial list containing 5 rows of test data

        log.debug("Initializing TestRequestBB backing bean done ...");
    }

    @Produces
    @Named
    public List<Test> getTestList()
    {   
        return super.getTestList();
    }
    ....
}

TestBase.java

public abstract class TestBase implements Serializable {

    ..... (contains all common code shared by other classes extending this base class)

    // does not contain any @PostConstruct method

}

1 Ответ

5 голосов
/ 24 февраля 2012

У @PostConstruct действительно никогда не будет доступа к обновленным значениям модели. Они доступны только после фазы обновления значений модели (таким образом, во время действия вызова и фазы ответа рендеринга). @PostConstruct никогда не предназначен для выполнения действий с обновленными значениями модели, он предназначен для выполнения действий с внедренными зависимостями, которые, в свою очередь, также создаются заново при необходимости, например @EJB, @Inject, @ManagedProperty.

То, что вы хотите, это метод, который вызывается во время фазы действия invoke. Вам нужно либо выполнить работу в методе прослушивания ajax TestSessionBB:

@Inject
private TestRequestBB testRequestBB;

public void next() { // No, no need to return String.
    // ...

    testRequestBB.initialize();
}

Или , чтобы добавить <f:event type="preRenderView"> к представлению. Это позволяет вам выполнять методы bean-компонента в самом конце фазы действия invoke, прямо перед фазой ответа рендеринга. Поместите это где-нибудь на ваш взгляд:

<f:event type="preRenderView" listener="#{testRequestBB.initialize}" />

Не забудьте удалить аннотацию @PostConstruct из метода.

Что касается проблемы вызова метода @PostConstruct дважды, то это потому, что каждый @Named приводит к совершенно отдельному экземпляру. У вас есть два @Named в одном классе, один в самом классе и один в самом методе получения. Я бы посоветовал удалить один из методов получения и заменить #{testList} на ваш взгляд на #{testRequestBB.testList}.

<h:dataTable value="#{testRequestBB.testList}" ...>

Если вам действительно, действительно , нужно получить параметры запроса внутри @PostConstruct, то вы можете получить их вручную с помощью ExternalContext#getRequestParameterMap():

@PostConstruct
public void initialize() {
    String foo = (String) FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("foo");
    // ...
}

Если бы вы использовали аннотацию JSF2 @ManagedBean вместо аннотации CDI @Named, вы могли бы вместо этого использовать @ManagedProperty:

@ManagedProperty("#{param.foo}")
private String foo;

Это значение будет доступно в течение @PostConstruct. В CDI такой аннотации нет, однако вы можете homegrow сделать ее самостоятельно, если необходимо.

Смотри также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...