@ManagedProperty для #{param} не работает в @ViewScoped

#jsf #jsf-2 #view-scope #http-request-parameters

#jsf #jsf-2 #вид-область видимости #http-запрос-параметры #область просмотра

Вопрос:

У моего боба есть это:

 @ManagedBean
@ViewScoped
public class BookBean implements Serializable
{       
    @ManagedProperty(value = "#{param.id}") // does not work with @ViewScoped
    private String id;

    public void init()
    {
        id = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id")
        if (id != null) {
            System.out.println("ID: "   id);
            currentBook = bookService.find(id);
        }
    }

    @PostConstruct
    public void post()
    {   
        // does not work with @ViewScoped
        System.out.println("ID: "   id);
        currentBook = bookService.find(id);    
    }

    public String getId() {
        return id;
    } 

    public void setId(String id) {
       this.id = id;
    }
}
  

И конечный интерфейс имеет это:

 <f:metadata>
    <f:viewParam name="id" value="#{bookBean.id}">
        <f:event type="preRenderView" listener="#{bookBean.init}" />
    </f:viewParam>
</f:metadata> 
  

В ходе тестирования я заметил, что @ManagedProperty и @PostConstruct работают только с @RequestScoped компонентом.

Для @ViewScoped bean я обнаружил, что мне пришлось сделать это, FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("id") чтобы получить значение id параметра.

Является ли это единственным способом получить значение параметра запроса с помощью @ViewScoped ?

Есть какие-нибудь мысли?

Ответ №1:

Область представления шире области запроса. @ManagedProperty Может устанавливать свойства, которые имеют ту же или более широкую область по сравнению с областью управляемого компонента.

Просто продолжайте использовать <f:viewParam> with <f:event> . Вы должны только не вкладывать их друг в друга.

 <f:metadata>
    <f:viewParam name="id" value="#{bookBean.id}" />
    <f:event type="preRenderView" listener="#{bookBean.init}" />
</f:metadata> 
  

с

 @ManagedBean
@ViewScoped
public class BookBean implements Serializable {

    private String id;

    public void init() {
        if (id != null) {
            currentBook = bookService.find(id);
        }
    }

    // ...
}
  

<f:viewParam> Установит параметр запроса и <f:event> выполнит метод прослушивания после установки этих параметров.

@PostConstruct Также отлично работает на компонентах с областью просмотра, но запускается только непосредственно после построения компонента и установки всех инъекций зависимостей (таких как @ManagedProperty , @EJB @Inject , @Resource , и т.д.). <f:viewParam> Однако впоследствии свойство устанавливается, поэтому оно недоступно в @PostConstruct .

Комментарии:

1. @BalusC: У меня это не сработало. Значение id возвращает null.

2. Здесь работает нормально. Какой JSF impl / version? Какой сервер приложений? Я создал быстрый тестовый набор с Mojarra 2.0.4 на Tomcat 7.0.11, и он отлично работает при вызове test.xhtml?id=123 .

3. Mojarra 2.1.0, который поставляется с Glassfish 3.1. Мои средства получения / установки созданы для id поля =, поэтому технически оно должно принимать значение, установленное f:viewParam> тегом

4. Вы уверены, что исправили неправильную вложенность? Если вы вложите его, то f:event будет вызван раньше f:viewParam .

5. @BalusC: Да, я забыл переместить тег f:event после <f:metadata> тега. Моя ошибка. Сегодня я узнал кое-что новое. Могу ли я предложить, чтобы будущая спецификация JSF была написана вами, Бауке. У вас есть талант в том, что вы можете переводить сложную документацию в простые для понимания демонстрируемые примеры кода. Я уже побывал на многих сайтах JSF 2, включая те, которые написаны сотрудниками Sun, но я не могу разобраться в некоторых их объяснениях новых функций JSF 2, таких как <f:viewParam> . С другой стороны, у вас это выглядит так просто. Я уважаю тебя за эту способность…

Ответ №2:

Вот еще один метод получения параметра запроса внутри компонента ViewScoped. Это было бы то, что #{param.device} получил бы в компоненте, ограниченном запросами. Преимущество этого заключается в том, что не требуются никакие теги на уровне представления.

 private int deviceID;
public int getDeviceID() {
    if (deviceID == 0) {
        String s = FacesContext.getCurrentInstance().getExternalContext().
                getRequestParameterMap().get("device");
        try {
            deviceID = Integer.parseInt(s);
        } catch (NumberFormatException nfe) {
        }
    }
    return deviceID;
}