如果我不能将@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>
和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();
}
}
答案 0 :(得分:13)
JSF @ManagedProperty
注释仅适用于JSF @ManagedBean
类。即在由JSF管理的实例中。它不适用于由CDI @Named
管理的实例。此外,您犯了另一个错误:您正在尝试根据构造函数中的托管属性准备Message
。如果它是真实的@ManagedBean
,那也没有用。托管属性在构造期间不可用,因为在调用构造函数之前无法调用setter方法。您可能会使用@PostConstruct
方法。但这不是解决方案,因为@ManagedProperty
无论如何都无法在@Named
中运行。
要真正替换@ManagedProperty
,您需要创建自定义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也更适合这种特殊情况,就是使用<f:viewParam>
,它还允许您通过自定义转换器直接将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().
}
答案 1 :(得分:1)
首先,为解释外来部分 - Glassfish使用JBoss Weld作为其CDI实现,Oracle不开发自己的实现。
关于错误消息的含义:FacesContext根本不能通过@Inject
注入。有一个相当古老的feature request,我认为Seam或Solder提供了一个制作人。但是没有必要为此集成任何一个库。通过FacesContext.getCurrentInstance()
访问面向上下文,就像在普通托管bean中一样。
答案 2 :(得分:0)
我问的是做一件简单事情的复杂方法。在CDI中,要传递params,你不能使用@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等等。