@Inject通过URL将参数传递给CDI @Named bean [英] @Inject to pass params to a CDI @Named bean via URL

查看:151
本文介绍了@Inject通过URL将参数传递给CDI @Named bean的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

If I cannot use the @ManagedProperty annotation with @Named, because @ManagedProperty doesn't work in CDI(?), then how do you pass params in the URL to the facelets client? In my code, I want to pass javax.mail.getMessageNumber() to details.xhtml through the "back" and "forward" buttons.

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

I understand that @Inject should be used, but what is being injected and how, please?

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

From the glassfish logs, id is always 0, which is quite odd. Even when "forward" is clicked, id never gets above 1 no matter how many times the button is clicked. Of course, that's merely a symptom of the problem. The desired output, of course, is to advance to the next Message.

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

Perhaps put the Message, or at least the int, into the session?

客户端如此:

<?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 @ManagedProperty注释仅在JSF @ManagedBean类中有效. IE.在由JSF管理的实例中.它在由CDI @Named管理的实例中不起作用.此外,您犯了另一个错误:您正在尝试根据构造函数中的托管属性准备Message.如果它是真实的@ManagedBean,那也就行不通了.托管属性在构造期间不可用,仅是因为无法在调用构造函数之前调用setter方法.您将为此使用@PostConstruct方法.但这不是解决方案,因为@ManagedProperty无论如何都不能在@Named中工作.

The JSF @ManagedProperty annotation works only in JSF @ManagedBean classes. I.e. in instances which are managed by JSF. It does not work in instances which are managed by CDI @Named. Further, you've made another mistake: you're trying to prepare the Message based on the managed property in the constructor. If it were a real @ManagedBean, that would also not have worked. The managed property is not available during construction, simply because it's not possible to call the setter method before the constructor is called. You would have used a @PostConstruct method for this. But this isn't the solution as the @ManagedProperty don't work in a @Named anyway.

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

To have a real replacement for @ManagedProperty, you'd need to create a custom CDI annotation. A concrete example is posted in this blog. Here's an extract of relevance:

自定义@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 具有

JSF utility library OmniFaces has a @Param for this purpose, with builtin support for JSF conversion and validation.

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

Alternatively, you can also manually grab the request parameter from the external context in the Detail managed bean. The recommended way to do managed bean initialization is to use a @PostConstruct method, not the constructor, as the constructor could be used for completely different purposes than managed bean creation:

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


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


Another way, IMO also more suitable for this particular case, is to use <f:viewParam> which also allows you to convert the ID to Message directly by a custom converter.

<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().

}

另请参见

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆