@@希望通过URL将参数传递给CDI @Named bean

问题描述 投票:8回答:3

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

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

从玻璃鱼的日志中,id始终为0,这很奇怪。即使单击“前进”,无论单击多少次,id都不会大于1。当然,这仅仅是问题的征兆。当然,所需的输出是前进到下一条消息。

也许将消息或至少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>

和bean一样:

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
3个回答
14
投票

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

javax.faces.annotation.ManagedProperty

现在不推荐使用的@Inject @ManagedProperty("#{param.id}") private String id; 注释仅在JSF javax.faces.bean.ManagedProperty类中有效。即在由JSF管理的实例中。它在由CDI javax.faces.bean.ManagedProperty管理的实例中不起作用。此外,您犯了另一个错误:您试图基于构造函数中的托管属性准备@ManagedBean。如果它是真实的@Named,那也将不起作用。托管属性在构造期间不可用,仅因为无法在调用构造函数之前调用setter方法。您应该为此使用Message方法。

如果无法升级到JSF 2.3,则需要创建一个自定义CDI批注。 @ManagedBean中张贴了一个具体示例。以下是相关摘录:

自定义@PostConstruct批注:

this blog

注释值生成器:

@HttpParam

用法示例:

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

JSF实用程序库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受管Bean中的外部上下文中手动获取请求参数。推荐的进行托管bean初始化的方法是使用@Param方法,而不是构造函数,因为构造函数could的用途与托管bean的创建完全不同:

@Param

另一种方式,IMO也更适合这种情况,是使用Detail,它还允许您通过自定义转换器将ID直接转换为@PostConstruct

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

with just

<f:viewParam>

和一个

Message

另请参见

  • <f:metadata> <f:viewParam name="id" value="#{detail.message}" converter="messageConverter" /> </f:metadata>
  • @Named public class Detail { private Message message; // Getter+setter }

1
投票

首先,解释外来部分-Glassfish使用JBoss Weld作为其CDI实现,Oracle并未开发自己的实现。

并涉及错误消息的含义:FacesContext根本无法通过@FacesConverter("messageConverter") public class MessageConverter implements Converter { // Convert string id to Message object in getAsObject(). // Convert Message object to string id in getAsString(). } 注入。有一个相当老的ViewParam vs @ManagedProperty(value = "#{param.id}"),我认为Seam或Solder提供了一个生产者。但是,无需为此专门集成任何一个库。通过Communication in JSF 2.0 - processing GET request parameters,可以像访问普通托管bean一样访问Face上下文。


0
投票

我在问一种复杂的方法来做一件简单的事情。在CDI中,要传递参数,您不能使用@ManagedProperty,如上文BalusC所述。相反,您只需这样设置xhtml文件:

© www.soinside.com 2019 - 2024. All rights reserved.