我在父页面中使用JSF 2.0复合组件时有一个概念性的思维模块。我理解如何为复合组件的操作实现ActionListener(和其他),但是如何为父页面使用这些连线?例如,我希望我的登录复合组件执行身份验证,完成后,通过一个事件(ActionListener?)通知父页面的辅助bean来执行一些UI初始化工作。这里的关键是登录组件会说,“嘿,我已经完成了,用户也很好。轮到你。”
提前感谢您的帮助。
和平。
克里斯
答案 0 :(得分:0)
我发现你可以实现的一种方法是使用复合组件+自定义组件类型+ ActionSource2 +系统事件。
在复合集的接口中有一个组件类型(当没有定义时,实现(Mojarra或MyFaces)使用默认的组件类型。
<cc:interface componentType="example.Login">
<cc:attribute name="text" type="java.lang.String"/>
<cc:attribute name="actionExpression" method-signature="void method()"/>
</cc:interface>
<cc:implementation>
<p>
<h:outputLabel value="User"/>
<h:inputText id="user"/>
</p>
<p>
<h:outputLabel value="Password"/>
<h:inputSecret id="password"/>
</p>
</cc:implementation>
此组件类型是实现NamingContainer的java类(UINamingContainer是实现此接口的组件的子类)。接下来,您必须实现ActionSource2,以便在验证用户时生成操作事件。
验证必须在验证用户和密码组件之后(不是您的验证,而是JSF PROCESS VALIDATIONS)。为了知道验证何时发生,我们使用系统事件。
这是自定义组件的代码示例。该类实现ActionSource2接口的方法并覆盖广播以处理ActionEvent。我在Mojarra中使用了一些特定的类(因为ActionSource和ActionSource2之间存在遗留问题)。
@FacesComponent("example.Login") //Component type in the composite
@ListenerFor(systemEventClass=PostValidateEvent.class) //Event to listen for user and password verification
public class LoginComponent extends UINamingContainer implements ActionSource2{
@Override
public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {
if(event instanceof PostValidateEvent){
System.out.println("post validate");
}
super.processEvent(event);
String user=(String) ((HtmlInputText)findComponent("user")).getValue();
String password=(String) ((HtmlInputSecret)findComponent("password")).getValue();
System.out.println("user: "+user);
System.out.println("password: "+password);
//a simple logic for verification
if(user != null && user.equals("victor") && password != null && password.equals(user)){
System.out.println("user ok");
queueEvent(new ActionEvent(this));
}
}
private MethodExpression exp;
@Override
public MethodExpression getActionExpression() {
return exp;
}
@Override
public void setActionExpression(MethodExpression action) {
exp=action;
}
@Override
public MethodBinding getAction() {
return exp != null ? new MethodBindingMethodExpressionAdapter(exp): null;
}
@Override
public void setAction(MethodBinding action) {
setActionExpression(new MethodExpressionMethodBindingAdapter(action));
}
private MethodBinding actionListener;
@Override
public MethodBinding getActionListener() {
return actionListener;
}
@Override
public void setActionListener(MethodBinding actionListener) {
this.actionListener=actionListener;
}
private boolean i;
@Override
public boolean isImmediate() {
return i;
}
@Override
public void setImmediate(boolean immediate) {
this.i=immediate;
}
List<ActionListener> listeners=new LinkedList<ActionListener>();
@Override
public void addActionListener(ActionListener listener) {
listeners.add(listener);
}
@Override
public ActionListener[] getActionListeners() {
return listeners.toArray(new ActionListener[0]);
}
@Override
public void removeActionListener(ActionListener listener) {
listeners.remove(listener);
}
@Override
public void broadcast(FacesEvent event) throws AbortProcessingException {
super.broadcast(event);
if (event instanceof ActionEvent) {
FacesContext context = getFacesContext();
MethodBinding binding = getActionListener();
if (binding != null) {
binding.invoke(context, new Object[] { event });
}
ActionListener listener = context.getApplication().getActionListener();
if (listener != null) {
listener.processAction((ActionEvent) event);
}
}
}
}
这是使用页面中的代码:
<ez:login actionExpression="#{bean.logged}"/>