【问题标题】:@Inject to pass params to a CDI @Named bean via URL@Inject 通过 URL 将参数传递给 CDI @Named bean
【发布时间】:2012-04-07 22:19:31
【问题描述】:

如果我不能将@ManagedProperty 注释与@Named 一起使用,因为@ManagedProperty 在CDI(?) 中不起作用,那么如何将URL 中的参数传递给facelets 客户端?在我的代码中,我想通过“后退”和“前进”按钮将 javax.mail.getMessageNumber() 传递给 details.xhtml。

我知道应该使用@Inject,但是请问要注入什么以及如何注入?

从 glassfish 日志中,id 始终为 0,这很奇怪。即使单击“前进”,无论单击多少次按钮,id 都不会超过 1。当然,这只是问题的表象。当然,期望的输出是前进到下一条消息。

也许将 Message 或至少 int 放入会话中?

客户是这样的:

<?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:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core">
    <ui:define name="top">
        <h:form>
            <h:form>
                <h:outputLink id="link1" value="detail.xhtml">
                    <f:param name="id" value="#{detail.back()}" />
                    <h:outputText value="back" />
                </h:outputLink>
            </h:form>
        </h:form>
        <h:form>
            <h:outputLink id="link1" value="detail.xhtml">
                <f:param name="id" value="#{detail.forward()}" />
                <h:outputText value="forward" />
            </h:outputLink>
        </h:form>
    </ui:define>
    <ui:define name="content">
        <h:outputText value="#{detail.content}"></h:outputText>
    </ui:define>
</ui:composition>

豆子也是这样:

package net.bounceme.dur.nntp;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedProperty;
import javax.inject.Named;
import javax.mail.Message;

@Named
@RequestScoped
public class Detail {

    private static final Logger logger = Logger.getLogger(Detail.class.getName());
    private static final Level level = Level.INFO;
    @ManagedProperty(value = "#{param.id}")
    private Integer id = 0;
    private Message message = null;
    private SingletonNNTP nntp = SingletonNNTP.INSTANCE;

    public Detail() {
        message = nntp.getMessage(id);
    }

    public int forward() {
        logger.log(level, "Detail.forward.." + id);
        id = id + 1;
        logger.log(level, "..Detail.forward " + id);
        return id;
    }

    public int back() {
        logger.log(level, "Detail.back.." + id);
        id = id - 1;
        logger.log(level, "..Detail.back " + id);
        return id;
    }

    public Message getMessage() {
        return message;
    }

    public String getContent() throws Exception {
        return message.getContent().toString();
    }
}

【问题讨论】:

  • 我要求删除这个问题,因为它是一个有缺陷的问题。

标签: jsf facelets cdi managed-property


【解决方案1】:

这仅适用于 JSF 2.3 中引入的 javax.faces.annotation.ManagedProperty

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

现在已弃用的 javax.faces.bean.ManagedProperty 注释仅适用于 JSF @ManagedBean 类。 IE。在由 JSF 管理的实例中。它不适用于由 CDI @Named 管理的实例。此外,您还犯了另一个错误:您试图根据构造函数中的托管属性准备Message。如果它是真正的@ManagedBean,那也行不通。托管属性在构造期间不可用,仅仅是因为在调用构造函数之前无法调用 setter 方法。您应该为此使用@PostConstruct 方法。

如果您无法升级到 JSF 2.3,则需要创建自定义 CDI 注释。一个具体的例子发布在this blog。以下是相关性摘录:

自定义@HttpParam注解:

@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface HttpParam {
    @NonBinding
    public String value() default "";
}

注解值生产者:

public class HttpParamProducer {

    @Inject
    FacesContext facesContext;

    @Produces
    @HttpParam
    String getHttpParameter(InjectionPoint ip) {
        String name = ip.getAnnotated().getAnnotation(HttpParam.class).value();
        if ("".equals(name)) name = ip.getMember().getName();
        return facesContext.getExternalContext()
                .getRequestParameterMap()
                .get(name);
    }
}

一个用法示例:

@Inject @HttpParam
private String id;

JSF 实用程序库 OmniFaces 有一个 @Param 用于此目的,内置支持 JSF 转换和验证。


或者,您也可以手动从Detail 托管bean 中的外部上下文中获取请求参数。进行托管 bean 初始化的推荐方法是使用 @PostConstruct 方法,而不是构造函数,因为构造函数可以用于与托管 bean 创建完全不同的目的:

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

另一种方式,IMO 也更适合这种特殊情况,是使用 &lt;f:viewParam&gt;,它还允许您通过自定义转换器直接将 ID 转换为 Message

<f:metadata>
    <f:viewParam name="id" value="#{detail.message}" converter="messageConverter" />
</f:metadata>

只有

@Named
public class Detail {

    private Message message;

    // Getter+setter
}

还有一个

@FacesConverter("messageConverter")
public class MessageConverter implements Converter {

    // Convert string id to Message object in getAsObject().
    // Convert Message object to string id in getAsString().

}

另见

【讨论】:

  • 为什么需要自定义 FacesConverter?
  • 这样您就可以以可重用的方式将String ID 转换为对象Message
  • 我想我暂时不会实现它,但这比解析字符串更有意义。请参阅clarifying 问题。
  • 现在是 2020 年,雅加达有什么变化吗?
【解决方案2】:

首先,解释一下陌生的部分——Glassfish 使用 JBoss Weld 作为其 CDI 实现,Oracle 并没有开发自己的实现。

关于错误消息的含义:FacesContext 根本无法通过@Inject 注入。有一个相当老的feature request,我认为 Seam 或 Solder 提供了一个生产者。但是没有必要为此集成任何一个库。通过FacesContext.getCurrentInstance(),像在普通托管 bean 中一样访问面临上下文。

【讨论】:

  • 那么,在HttpParamProducer 使用@Inject 的地方,FacesContext 不是可注入的吗?稍微支持一下,为什么在这种情况下,您需要 FacesContext 作为当前实例中的参数?我知道我有点胡思乱想,对不起。
【解决方案3】:

我在问一种复杂的方法来做一件简单的事情。在 CDI 中,传递参数不能使用 @ManagedProperty,正如 BalusC 上面解释的那样。相反,您只需像这样设置您的 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:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core">
    <ui:define name="top">
        <h:form>
            <h:commandButton action="#{messages.back()}" value="..back" />
        </h:form>
        <h:form>
            <h:commandButton action="#{messages.forward()}" value="forward.." />
        </h:form>
    </ui:define>
    <ui:define name="content">
        <h:dataTable value="#{messages.model}" var="m">
            <h:column>
                <f:facet name="id">
                    <h:outputText value="id" />
                </f:facet>
                <h:outputLink id="hmmm" value="detail.xhtml">
                    <f:param name="id" value="#{m.getMessageNumber()}" />
                    <h:outputText value="#{m.getMessageNumber()}" />
                </h:outputLink>
            </h:column>
            <h:column>
                <f:facet name="subject">
                    <h:outputText value="subject" />
                </f:facet>
                <h:outputText value="#{m.subject}"></h:outputText>
            </h:column>
            <h:column>
                <f:facet name="content">
                    <h:outputText value="content" />
                </f:facet>
                <h:outputText value="#{m.sentDate}"></h:outputText>
            </h:column>
            <h:column>
                <f:facet name="date">
                    <h:outputText value="date" />
                </f:facet>
                <h:outputLink value="#{messages.getUrl(m)}">#{messages.getUrl(m)}</h:outputLink>
            </h:column>
        </h:dataTable>
    </ui:define>
</ui:composition>

到:

<?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:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core">
    <ui:define name="top">
        <h:form>
            <h:outputLink id="back" value="detail.xhtml">
                <f:metadata>
                    <f:viewParam name="id" value="#{detail.id}"  />
                </f:metadata>
                <f:param name="id" value="#{detail.back()}" />
                <h:outputText value="back" />
            </h:outputLink>
        </h:form>
        <h:form>
            <h:outputLink id="forward" value="detail.xhtml">
                <f:metadata>
                    <f:viewParam name="id" value="#{detail.id}"  />
                </f:metadata>
                <f:param name="id" value="#{detail.forward()}" />
                <h:outputText value="forward" />
            </h:outputLink>
        </h:form>
    </ui:define>
    <ui:define name="content">
        <h:outputText value="#{detail.content}"></h:outputText>
    </ui:define>
</ui:composition>

我只是为任何出现的人提供这个,以澄清,对于这个简单的例子,你不需要转换器,默认工作正常。

原来的问题也有点混乱。通过查看有关此的其他问题,我认为其他人可以从诸如此类的简单示例中受益。这么多例子过于复杂,或者涉及到EJB等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-24
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-02
    • 1970-01-01
    • 2017-05-08
    相关资源
    最近更新 更多