Model view controller 从RequestMap中提取RequestScope CDIBean

Model view controller 从RequestMap中提取RequestScope CDIBean,model-view-controller,jsf-2,cdi,managed-bean,Model View Controller,Jsf 2,Cdi,Managed Bean,我目前正在将Ed Burns的JSF 2.0教科书中的虚拟培训师示例应用程序从JSF托管bean转换为CDI。到目前为止,我遇到的大多数问题都与作用域和忘记正确注入有关,但现在我正在努力克服最近的一个障碍,即从RequestMap中提取CDIBean(实际上是一个实体类)。从我到目前为止所能确定的情况来看,似乎可以通过使用Map实现提供的boilerplate.get(String managedbeanname)方法非常简单地提取请求范围的托管Bean。然而,使用CDI,bean在Creati

我目前正在将Ed Burns的JSF 2.0教科书中的虚拟培训师示例应用程序从JSF托管bean转换为CDI。到目前为止,我遇到的大多数问题都与作用域和忘记正确注入有关,但现在我正在努力克服最近的一个障碍,即从RequestMap中提取CDIBean(实际上是一个实体类)。从我到目前为止所能确定的情况来看,似乎可以通过使用Map实现提供的boilerplate.get(String managedbeanname)方法非常简单地提取请求范围的托管Bean。然而,使用CDI,bean在CreationContextImp实例中被Weld包裹,我无法提取我真正想要的对象,即使我已经确认它存在于RequestMap中。我可以直接从RequestMap访问代理对象,但调用.get(“user”)后会恢复为null,我怀疑这会有多大好处,因为代理中的字段都为null

我发现BalusC的一篇文章讨论了使用一个过滤器类来访问SessionScope()中的CDIBeans,这似乎有点复杂——有更简单的解决方案吗?我也很清楚,我可能会搞砸托管Bean与CDI策略的范围界定/混合,所以请随意告诉我。。。我也有点不确定是否以这种方式直接使用实体Bean,而不是使用外观。这会不会给我带来麻烦

环境:JEE7、Glassfish 4、Netbeans 7.4、Maven EE Web原型 与托管bean的使用相关的原始代码已被注释掉

抽象支持bean类:

@RequestScoped
public abstract class AbstractBacking implements Serializable {

    //@ManagedProperty(value="#{facesContext}")
    private FacesContext facesContext;

    //@ManagedProperty(value="#{requestScope}")
    private Map<String, Object> requestMap;

    //@ManagedProperty(value="#{sessionScope}")
    private Map<String, Object> sessionMap;

    @PostConstruct
    public void init() {
        this.facesContext = FacesContext.getCurrentInstance();
        this.sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
        this.requestMap = FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
    }
用户实体bean:

@Entity
@Named
@Table(name = "Users")
@RequestScoped
@NamedQueries({
    @NamedQuery(name = "user.getAll", query = "select u from User as u"), // @NamedQuery(name = "user.getTrainers", query = "select u from User as u where u.trainer = TRUE"),
// @NamedQuery(name = "user.getUsersForTrainerId", query = "select u from User as u where u.personalTrainerId = :theId")
})

public class User extends AbstractEntity implements Serializable {

    protected String firstName;
    protected String lastName;
    @Temporal(TemporalType.DATE)
    protected Date dob;
    protected String sex;
    protected String email;
    private String serviceLevel = "medium";
    @Column(name = "userid", nullable = false)
    private String userid;
    private String password;
    private boolean trainer;
    private List<Long> subscribedEventIds;
    private Long personalTrainerId;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
    private List<TrainingSession> sessions;

    private boolean sessionsInitialized = false;

    public User() {
        this.init();
    }

    public User(String firstName, String lastName,
            String sex, Date dob, String email, String serviceLevel,
            String userid, String password, boolean isTrainer) {
        this.init();
        this.setFirstName(firstName);
        this.setLastName(lastName);
        this.setSex(sex);
        this.setDob(dob);
        this.setEmail(email);
        this.setServiceLevel(serviceLevel);
        this.setUserid(userid);
        this.setPassword(password);
        this.setTrainer(isTrainer);
    }
.....
Getters/setters/etc
.....
@实体
@命名
@表(name=“Users”)
@请求范围
@命名查询({
@NamedQuery(name=“user.getAll”,query=“从用户中选择u作为u”),//@NamedQuery(name=“user.getTrainers”,query=“从用户中选择u作为u,其中u.trainer=TRUE”),
//@NamedQuery(name=“user.getUsersForTrainerId”,query=“从用户中选择u作为u,其中u.personalTrainerId=:theId”)
})
公共类用户扩展抽象实体实现可序列化{
受保护的字符串名;
受保护的字符串lastName;
@时态(TemporalType.DATE)
保护日期dob;
保护性;
受保护的字符串电子邮件;
私有字符串serviceLevel=“medium”;
@列(name=“userid”,nullable=false)
私有字符串用户标识;
私有字符串密码;
私人布尔训练器;
私有列表订阅事件ID;
私人长时间私人培训;
@OneToMany(mappedBy=“user”,cascade=CascadeType.ALL)
非公开名单会议;
私有布尔sessionInitialized=false;
公共用户(){
this.init();
}
公共用户(字符串名、字符串名、,
字符串性别、日期出生日期、字符串电子邮件、字符串服务级别、,
字符串用户ID、字符串密码、布尔值(isTrainer){
this.init();
这个.setFirstName(firstName);
此.setLastName(lastName);
这是性;
这是setDob(dob);
这个.setEmail(email);
此.setServiceLevel(服务级别);
this.setUserid(userid);
此.setPassword(密码);
这是setTrainer(isTrainer);
}
.....
接受者/接受者/等
.....
注册页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition template="template.xhtml">
    <ui:define name="content">
<h:form prependId="false">
    <h:panelGrid columns="3">

        <h:outputLabel for="fname" value="First Name:" />
        <h:inputText label="First Name"
                     id="fname" value="#{user.firstName}"
                     required="true"/>
        <h:message for="fname" />

        <h:outputLabel for="lname" value="Last Name:" />
        <h:inputText label="Last Name"
                     id="lname" value="#{user.lastName}"
                     required="true"/>
        <h:message for="lname" />

        <h:outputLabel for="sex" value="Sex:" />
        <h:selectOneRadio label="Sex"
                          id="sex" value="#{user.sex}" required="true">
          <f:selectItem itemLabel="Male" itemValue="male" />
          <f:selectItem itemLabel="Female" itemValue="female" />
        </h:selectOneRadio>
        <h:message for="sex" />

        <h:outputLabel for="dob" value="Date of Birth:" />
        <h:panelGroup>
            <h:inputText label="Date of Birth"
                     id="dob" value="#{user.dob}" required="true">
                <f:convertDateTime pattern="MM-dd-yy" />
            </h:inputText> (mm-dd-yy)
        </h:panelGroup>
        <h:message for="dob" />

        <h:outputLabel for="email" value="Email Address:" />
        <h:inputText label="Email Address"
                     id="email" value="#{user.email}" required="true" />
        <h:message for="email" />

        <h:outputLabel for="slevel" value="Service Level:" />
        <h:selectOneMenu label="Service Level" id="slevel"
                         value="#{user.serviceLevel}">
          <f:selectItem itemLabel="Medium" itemValue="medium" />
          <f:selectItem itemLabel="Basic" itemValue="basic" />
          <f:selectItem itemLabel="Premium" itemValue="premium" />
        </h:selectOneMenu>
        <h:message for="slevel" />

        <h:outputLabel for="userid" value="Userid:" />
        <h:inputText required="true" id="userid" value="#{user.userid}" />
        <h:message for="userid" />

        <h:outputLabel for="password" value="Password:" />
        <h:inputSecret required="true" id="password" 
                       validator="#{registerBacking.validatePassword1}"
                       value="#{requestScope.password1}" />
        <h:message for="password" />

        <h:outputLabel for="password2" value="Retype Password:" />
        <h:inputSecret required="true" id="password2" value="#{requestScope.password2}"
                       validator="#{registerBacking.validatePassword2}" />
        <h:message for="password2" />


    </h:panelGrid>

    <p><h:commandButton value="Register" 
                     action="#{registerBacking.registerUser}" /></p>
</h:form>

    </ui:define>
</ui:composition>
</body>
</html>

(年月日)


事实上,您似乎混合了CDI bean和JSF bean,老实说,您正在翻译的示例似乎很奇怪,我会将其全部扔出窗外

因为JSF也有它自己的依赖注入,除非您有一个非常特定的用例(比如ServletFilter),否则您自己不会从作用域映射中提取内容

阐明CDI使用的原理和自己“提取”的东西是一种反模式

进一步讲,CDIBean是由CDI容器(几乎所有情况下都是Weld或OWB)创建和管理的,您根本无法从externalContext检索CDIBean,因为它是JSF的上下文,是一个完全独立的东西

因此,JSF创建的实例不能在CDIBeans中注入,反之亦然。总之,正如我前面所说的,自己提取东西是不好的做法。请参阅此列表中的#10:

因此,您只需使用
@Inject
(可能带有限定符)即可

注入不起作用的特殊情况的解决方法:

  • CDI上下文在当前线程中不可用
  • 当前实例不是CDI管理的
第一个场景发生在您使用ThreadLocal时,例如QuartzJob.EJB容器可能提供获取上下文线程的方法,但如果您使用的是普通servlet容器(tomcat)或者线程是在没有CDI上下文的情况下生成的,无论出于何种原因,您必须自己附加此信息。要执行此操作,请使用Deltaspike CDI控件

该示例没有更新,今天您应该使用DependentProvider获得ContextControl

我的博客上的例子如下:

第二种情况是,当ServletContainer创建了实例,而您在一个普通容器(例如Tomcat)上时,JSF创建了实例,不管怎样

然后,注入将不起作用。因为解决方法使用Deltaspike的BeanProvider。它可以在当前实例中强制注入,更有用的是,它可以为您提取一个bean。如果您这样做,并且您仍然受到第一个场景的影响,您将得到一个异常,可能是
ContextNotActivieException

得到
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:ui="http://java.sun.com/jsf/facelets">
<body>
<ui:composition template="template.xhtml">
    <ui:define name="content">
<h:form prependId="false">
    <h:panelGrid columns="3">

        <h:outputLabel for="fname" value="First Name:" />
        <h:inputText label="First Name"
                     id="fname" value="#{user.firstName}"
                     required="true"/>
        <h:message for="fname" />

        <h:outputLabel for="lname" value="Last Name:" />
        <h:inputText label="Last Name"
                     id="lname" value="#{user.lastName}"
                     required="true"/>
        <h:message for="lname" />

        <h:outputLabel for="sex" value="Sex:" />
        <h:selectOneRadio label="Sex"
                          id="sex" value="#{user.sex}" required="true">
          <f:selectItem itemLabel="Male" itemValue="male" />
          <f:selectItem itemLabel="Female" itemValue="female" />
        </h:selectOneRadio>
        <h:message for="sex" />

        <h:outputLabel for="dob" value="Date of Birth:" />
        <h:panelGroup>
            <h:inputText label="Date of Birth"
                     id="dob" value="#{user.dob}" required="true">
                <f:convertDateTime pattern="MM-dd-yy" />
            </h:inputText> (mm-dd-yy)
        </h:panelGroup>
        <h:message for="dob" />

        <h:outputLabel for="email" value="Email Address:" />
        <h:inputText label="Email Address"
                     id="email" value="#{user.email}" required="true" />
        <h:message for="email" />

        <h:outputLabel for="slevel" value="Service Level:" />
        <h:selectOneMenu label="Service Level" id="slevel"
                         value="#{user.serviceLevel}">
          <f:selectItem itemLabel="Medium" itemValue="medium" />
          <f:selectItem itemLabel="Basic" itemValue="basic" />
          <f:selectItem itemLabel="Premium" itemValue="premium" />
        </h:selectOneMenu>
        <h:message for="slevel" />

        <h:outputLabel for="userid" value="Userid:" />
        <h:inputText required="true" id="userid" value="#{user.userid}" />
        <h:message for="userid" />

        <h:outputLabel for="password" value="Password:" />
        <h:inputSecret required="true" id="password" 
                       validator="#{registerBacking.validatePassword1}"
                       value="#{requestScope.password1}" />
        <h:message for="password" />

        <h:outputLabel for="password2" value="Retype Password:" />
        <h:inputSecret required="true" id="password2" value="#{requestScope.password2}"
                       validator="#{registerBacking.validatePassword2}" />
        <h:message for="password2" />


    </h:panelGrid>

    <p><h:commandButton value="Register" 
                     action="#{registerBacking.registerUser}" /></p>
</h:form>

    </ui:define>
</ui:composition>
</body>
</html>
@ViewScoped
@Named
public class WelcomeBean {

    @Inject
    private SettingManager settingManager;


    private boolean allowCreateAccount;


    public boolean isAllowCreateAccount() {
        return allowCreateAccount;
    }


   // login and create account here

    @PostConstruct
    private void init() {
        allowCreateAccount = settingManager.getBooleanSetting("registrationOpen");
    }
}
<h:commandButton action="#{welcomeBean.createAccount}" value="login" disabled="#{welcomeBean.allowCreateAccount}"/>