@Inject通过URL将params传递给CDI @Named bean

Thu*_*fir 7 jsf facelets cdi managed-property

如果我不能将@ManagedProperty注释与@Named一起使用,因为@ManagedProperty在CDI(?)中不起作用,那么如何将URL中的params传递给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>
Run Code Online (Sandbox Code Playgroud)

和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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 13

JSF @ManagedProperty注释仅适用于JSF @ManagedBean类.即在由JSF管理的实例中.它不适用于由CDI管理的实例@Named.此外,您犯了另一个错误:您正在尝试Message基于构造函数中的托管属性进行准备.如果它是真实的@ManagedBean,那也没有用.托管属性在构造期间不可用,因为在调用构造函数之前无法调用setter方法.你会使用一种@PostConstruct方法.但这不是解决方案,因为无论如何@ManagedProperty都不起作用@Named.

要真正替代@ManagedProperty,您需要创建自定义CDI注释.此博客中发布了一个具体示例.这是相关的摘录:

自定义@HttpParam注释:

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

注释值生成器:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

一个用法示例:

@Inject @HttpParam
private String id;
Run Code Online (Sandbox Code Playgroud)

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


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

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

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

<f:metadata>
    <f:viewParam name="id" value="#{detail.message}" converter="messageConverter" />
</f:metadata>
Run Code Online (Sandbox Code Playgroud)

只是

@Named
public class Detail {

    private Message message;

    // Getter+setter
}
Run Code Online (Sandbox Code Playgroud)

和a

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

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

}
Run Code Online (Sandbox Code Playgroud)

也可以看看