关于在父页面中使用 JSF 2.0 复合组件,我有一个概念性思维障碍。我了解如何为复合组件的操作实现 ActionListener (和其他),但是如何连接父页面以供使用?例如,我希望我的登录复合组件执行身份验证,并在完成后通过事件(ActionListener?)通知父页面的支持 bean 进行一些 UI 初始化工作。这里的关键是登录组件会说,“嘿,我完成了,用户很好。轮到你了。”
提前感谢您的帮助。
和平。
克里斯
关于在父页面中使用 JSF 2.0 复合组件,我有一个概念性思维障碍。我了解如何为复合组件的操作实现 ActionListener (和其他),但是如何连接父页面以供使用?例如,我希望我的登录复合组件执行身份验证,并在完成后通过事件(ActionListener?)通知父页面的支持 bean 进行一些 UI 初始化工作。这里的关键是登录组件会说,“嘿,我完成了,用户很好。轮到你了。”
提前感谢您的帮助。
和平。
克里斯
我发现您可以完成此操作的一种方法是使用复合组件 + 自定义组件类型 + 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,以便在验证用户时生成操作事件。
verifyng 必须在验证用户和密码组件之后进行(不是您的验证,而是 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}"/>