@PostConstruct 中的 CDI 参数

Posted

技术标签:

【中文标题】@PostConstruct 中的 CDI 参数【英文标题】:CDI params in @PostConstruct 【发布时间】:2011-06-26 17:03:13 【问题描述】:

我认为我的问题类似于this,但还没有发现它可以工作

  <f:metadata>
  <f:viewParam id="id" name="id" value="#detailsBean.id"/>
 </f:metadata>

为什么我不能使用 @Named 来执行此操作并使用 CDI:

@Named
@RequestScoped
public class DetailsBean 

    private Contacts detailsContact;
    @EJB
    ContactsFacade contactsEJB;
    private int id;

    public DetailsBean() 

        System.out.println("details bean called");
    

    @PostConstruct
    public void onLoad() 
        detailsContact = contactsEJB.find(id);


我无法记录 id。

当然,@ManagedProperty 与 CDI 不兼容。

*****更新*****

一些xhtml

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="../template.xhtml"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:p="http://primefaces.prime.com.tr/ui"
                xmlns:f="http://java.sun.com/jsf/core">

    <ui:define name="head">
        <f:metadata>               
            <f:viewParam name="paginator" value="#contactsBean.contactsTablePaginator"/>
            <f:viewParam name="rows" value="#contactsBean.contactsTableRows"/>
        </f:metadata>
    </ui:define>

    <ui:define name="content">
        <p:growl id="growl" showDetail="true"/>

        <p:panel id="contactsPanel" >

            <h:form id ="contactsForm">

                <p:dataTable id="contactsTable" value="#contactsBean.contacts" selection="#detailsBean.detailsContact" var="contacts" widgetVar="contactsTable"
                             selectionMode="single" rowSelectListener="#contactsBean.rowSelect" rowUnselectListener="#contactsBean.rowUnSelect"
                             onRowUnselectUpdate="detailsForm" onRowSelectUpdate="detailsForm"
                             paginator="#contactsBean.contactsTablePaginator" rows="#contactsBean.contactsTableRows" rowsPerPageTemplate="5,10,15,25,50,100"
                             paginatorTemplate="RowsPerPageDropdown FirstPageLink PreviousPageLink CurrentPageReport NextPageLink LastPageLink">

                    <f:facet name="header">                     
                        <p:outputPanel>
                            <h:outputText value="Search:" />
                            <p:inputText id="globalFilter" onkeyup="contactsTable.filter()"  style="width:150px" />                
                        </p:outputPanel>
                    </f:facet>

                    <p:column filterStyle="display:none"  filterBy="#contacts.name" headerText="Name" style="width:200px">
                        <h:outputText value="#contacts.name" />
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.street" headerText="Street" style="width:280px">
                        <h:outputText value="#contacts.street" />                     
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.city" headerText="City" style="width:150px">
                        <h:outputText value="#contacts.city" />
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.state" headerText="State" style="width:50px">
                        <h:outputText value="#contacts.state" />
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.zip" headerText="Zip" style="width:100px">
                        <h:outputText value="#contacts.zip" />
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.country" headerText="Country" style="width:150px">
                        <h:outputText value="#contacts.country" />
                    </p:column>

                    <p:column filterStyle="display:none" filterBy="#contacts.sent" headerText="Sent" style="width:50px">
                        <h:outputText value="#contacts.sent" />
                    </p:column>                 

                </p:dataTable>

                <p:ajaxStatus >

                    <f:facet name="start">
                        <h:graphicImage value="../resources/images/ajax-loader-bar.gif" />
                    </f:facet>

                    <f:facet name="complete">
                        <h:graphicImage value="../resources/images/ajax-loader-bar-still.gif" />
                    </f:facet>

                    <f:facet name="default">
                        <h:graphicImage value="../resources/images/ajax-loader-bar-still.gif" />
                    </f:facet>
                </p:ajaxStatus>
                <br />

                <p:commandLink value="View All" action="#contactsBean.viewAll"   /> &nbsp;
                <p:commandLink value="Default View" action="#contactsBean.viewDefault"  /> &nbsp;
                <p:commandLink value="Advanced Search" action="search?faces-redirect=true" />

                <br />           

            </h:form>

            <br />

        </p:panel>

        <br />
        <br />

        <h:form id="detailsForm">

            <p:panel id="detailsPanel" visible="#detailsBean.visible" >

                <h:panelGrid id="detailsPanelGrid" cellpadding="2" cellspacing="2" columns="3"   >

                    <h:outputText value="Name :" />
                    <p:inputText id="name" value="#detailsBean.detailsContact.name" style="width:400px" />
                    <p:message for="name" />

                    <h:outputText value="Email :" />
                    <p:inputText id="email" value="#detailsBean.detailsContact.email" style="width:400px" validatorMessage="Must be a valid email address. EX: test@test.com"  >
                        <f:validateRegex pattern="[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[a-zA-Z0-9]+"/>
                        <p:ajax event="blur" update="emailMsg" />
                    </p:inputText>
                    <p:message id="emailMsg" for="email" />

                    <h:outputText value="Street :" />
                    <p:inputText id="street" value="#detailsBean.detailsContact.street" style="width:400px" />
                    <p:message for="street" />

                    <h:outputText value="City :" />
                    <p:inputText id="city" value="#detailsBean.detailsContact.city" style="width:400px" />
                    <p:message for="city" />

                    <h:outputText value="State :" />
                    <p:inputText id="state" value="#detailsBean.detailsContact.state" style="width:400px" validatorMessage="Length is greater than 2" >
                        <f:validateLength maximum="2" />
                        <p:ajax event="blur" update="stateMsg" />
                    </p:inputText>
                    <p:message id="stateMsg" for="state" />

                    <h:outputText value="Country :" />
                    <p:inputText id="country" value="#detailsBean.detailsContact.country" style="width:400px" />
                    <p:message for="country" />

                    <h:outputText value="Phone :" />
                    <p:inputText id="phone" value="#detailsBean.detailsContact.phone" style="width:400px"/>
                    <p:message for="phone" />

                    <h:outputText value="Guests :" />
                    <p:inputText id="guests" value="#detailsBean.detailsContact.guests" style="width:400px"/>
                    <p:message for="guests" />

                    <h:outputText value="Arrival :" />
                    <p:calendar id="arrival" value="#detailsBean.detailsContact.arrival" showOn="button" />
                    <p:message for="arrival" />

                    <h:outputText value="Departure :" />
                    <p:calendar id="departure" value="#detailsBean.detailsContact.departure" showOn="button" />
                    <p:message for="departure" />

                    <h:outputText value="Message :" />
                    <p:inputTextarea id="message" effectDuration="30" style="width:400px;height:100px;" value="#detailsBean.detailsContact.message"  />
                    <p:message for="message" />

                    <h:outputText value="Departure :" />
                    <p:calendar id="inserted" value="#detailsBean.detailsContact.inserted" showOn="button"/>
                    <p:message for="inserted" />

                    <h:outputText value="Sent :" />
                    <h:selectBooleanCheckbox id="sent" value="#detailsBean.detailsContact.sent" />
                    <p:message for="sent" />
                    <br />

                </h:panelGrid>

                <p:commandButton value="Submit" action="#detailsBean.updateContactDetails"  update="contactsForm, growl, stateMsg" />
                <p:commandButton value="Close" action="#detailsBean.handleClose" update="contactsForm, detailsForm" />

            </p:panel>

        </h:form>

    </ui:define>

</ui:composition>

更多java代码:

package com.atlanticpkg.view.beans;

import com.atlanticpkg.model.entities.Contacts;
import com.atlanticpkg.util.FacesUtils;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.inject.Named;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;

@Named(value = "detailsBean")
@RequestScoped
public class EditBean 

    private Contacts detailsContact;
    private boolean visible = false;
    @Inject
    ContactsBean contactsBean;

    public EditBean() 
    

    @PostConstruct
    public void onLoad() 
    

    public void handleClose() 

        this.setVisible(false);
        this.setDetailsContact(new Contacts());
    

    public void updateContactDetails() 

        try 

            contactsBean.getContactsEJB().edit(detailsContact);
            FacesUtils.addMessage(detailsContact.getName() + " was updated successfully!");

         catch (Exception e) 
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "ERROR", e.toString()));
        

    

甚至更多:

@Named(value = "contactsBean")
@RequestScoped
public class ContactsBean 

    @Inject
    EditBean editBean;
    @EJB
    private ContactsFacade contactsEJB;
    private List<Contacts> contacts = new ArrayList<Contacts>();
    private boolean contactsTablePaginator = true;
    private int contactsTableRows = 10;
    private Contacts selectedContact = new Contacts();

    public ContactsBean() 
    

    @PostConstruct
    public void onLoad() 

        updateContactsList();
    

    public String viewDefault() 

        contactsTablePaginator = true;
        contactsTableRows = 10;
        return "index?faces-redirect=true&includeViewParams=true";
    

    public String viewAll() 

        contactsTablePaginator = false;
        contactsTableRows = 100;
        return "index?faces-redirect=true&includeViewParams=true";
    

    public void updateContactsList() 

        contacts.clear();
        contacts = contactsEJB.findAll();
    

    public void rowSelect(SelectEvent event) 

        editBean.setVisible(true);
        editBean.setDetailsContact((Contacts) event.getObject());
    

    public void rowUnSelect(UnselectEvent event) 

        editBean.setVisible(false);
        editBean.setDetailsContact(new Contacts());

    

inputText 框填充得很好。但是当我点击提交时,它说这些值为空。此代码与 SessionScope 完美配合。

警告:/admin/index.xhtml @104,109 value="#detailsBean.detailsContact.name":目标无法到达,'null' 返回 null javax.el.PropertyNotFoundException: /admin/index.xhtml @104,109 value="#detailsBean.detailsContact.name": 目标不可达,'null' 返回 null

当我选择数据表时,我可以看到它正在调用 EditBean。然后,当我单击提交按钮时,它会再次调用它。

【问题讨论】:

我相信 @PostConstruct 只会在 bean 初始化阶段被调用。因此,您的 onLoad() 方法可能不会被调用。 相关:***.com/questions/4888942/… 这个问题听起来有时值是空的,有时不是,所以看起来 bean 可能没有在需要时加载参数。 【参考方案1】:

我遇到了和你完全相同的问题,通过使用外部上下文(包含 GET 参数)而不是 f:viewParam 来解决它。

在您的 @PostConstruct 方法中,只需使用类似的方式获取您的参数

FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();

【讨论】:

【参考方案2】:

生命周期不允许您的方法。

首先,创建 bean(构造函数)。之后,执行依赖注入,然后执行 @PostConstruct 方法,然后评估 JSF 文件。 viewParam 在该文件中。因此,您必须注册另一个在填充视图参数后调用的侦听器。

我有一个@RequestScope bean 的解决方案,但是如果 bean 的范围更长(比如 View ),那么这个方法在每个请求(包括 AJAX )之后执行,这可能是不需要的。

将此用于请求范围 bean:

<f:metadata>
   <f:viewParam id="id" name="id" value="#detailsBean.id"/>
   <f:event type="preRenderView" listener="#detailsBean.onLoad" />
</f:metadata>

对于@ViewScope bean,我正在使用这个“hack”,它有效,但可能不是最佳实践。它做同样的事情,但可能不是正确的方法。

#detailsBean.onLoad()
<f:metadata>
   <f:viewParam id="id" name="id" value="#detailsBean.id"/>
</f:metadata>

希望对你有帮助。


编辑:

您在这里使用了很多 AJAX。这个调用必须至少登陆ViewScoped bean。 View Scope 与RequestScope 类似,但需要更长的时间 - 直到离开页面。

但我还没有全部阅读,有很多代码,如果 ViewScope 没有帮助,那么也许你应该提供一小段有问题的代码,以便有机会找到并专注于真正的问题。

【讨论】:

谢谢。所以看起来 viewParams 更适合 SessionScoped bean?这很有趣,因为我的想法正好相反。我试图为每个页面呈现一个新的 bean,并且没有任何内容从页面到页面。我在想请求范围是最好的方法。我猜不会。当我去更新它时,它仍然没有解决我的其他问题,其中 detailsContact 为空。就像只要点击提交按钮,它就会创建一个新的 detailsContact。我认为请求比这长一点。 @dham:我认为页面的最佳范围是请求或查看(当您使用 AJAX 时)。更长的范围是多余的。使用带有 RequestScope 的事件侦听器很好。你的另一个问题是什么?我找不到它解释。如果你能向我们展示一些代码并描述它会很好,因为我不明白它。 您好,我会用这个问题更新我的帖子。我有数据表,然后我选择一行并将我带到另一个页面。我使用请求范围来使用 EJB 来填充 inputText 字段。我正在使用您向我展示的侦听器方法。这些字段填充得很好,但是当我提交更改时,我收到一个错误,即字段实际上为空。这很奇怪。即使我不去其他页面进行编辑,我也有同样的问题。 是否可以将 ViewScoped 与命名注释一起使用?似乎没有与之合作。我猜我将不得不使用 ManagedBean javax.faces 注释。 @dham 我不知道,我总是使用带有属性名称的 ManagedBean

以上是关于@PostConstruct 中的 CDI 参数的主要内容,如果未能解决你的问题,请参考以下文章

Gluon 默认使用啥 CDI 机制?

Java EE 6:切换到 CDI - 最佳资源

JAX-WS 和 CDI 不能在 WAS Liberty Profile 8.5.5.6 上一起工作

如何使用 CDI 进行方法参数注入?

使用 CDI 而不是 @ManagedBean: UnproxyableResolutionException 因为超类没有无参数构造函数

注解@PostConstruct与@PreDestroy使用讲解