使用阶段侦听器以编程方式将参数添加到 Html 命令链接

Programatically add Parameter to HtmlCommandLink using a Phase Listener

我需要通过 Phase Listener 将组件 (UIParameter) 添加到 HtmlCommandLink 组件中。 我想要实现的是每个元素 <h:link outcome="out"> 呈现为 <a href="out_url_parsed + ?param=paramvalue">。其中 "param" 是我的组件。

我试过用这个

private void addElement(final PhaseEvent event, final Class clazz, final UIComponent component) {
    final FacesContext fcontext = event.getFacesContext();
    UIViewRoot root = fcontext.getViewRoot();
    if (root == null) {
        return;
    }

    root.visitTree(new FullVisitContext(fcontext), new VisitCallback() {

        @Override
        public VisitResult visit(VisitContext context, UIComponent target) {
            if (clazz.isInstance(target)) {
                LOGGER.info("Element Found");
                UIParameter parameter = new UIParameter();
                parameter.setValue("willberonadom");
                parameter.setId("sessiontoken");
                target.getChildren().add(parameter);

            }
            return VisitResult.ACCEPT;
        }
    });
}

但它不起作用。该元素实际上在树上找到,但 UIParameter 未呈现。

我发现 UIViewRoot 在 RENDER_RESPONSE 阶段后只有子元素。所以我认为这就是为什么我添加的元素在过程结束时没有呈现的原因。

我确定我可以添加此参数来编辑视图,但我不想这样做,因为它必须存在于应用程序中的所有 h:link 上,并且必须存在于任何其他新添加的也。所以我认为这是避免丢失标签的更好方法

在类似的情况下,我已经设法使用此代码将输入隐藏元素添加到视图中的每个表单...

HtmlInputHidden hiddenToken = new HtmlInputHidden();
hiddenToken.setId("sessiontoken");
hiddenToken.setValue("willberandom");
hiddenToken.setRendered(true);
root.addComponentResource(event.getFacesContext(), hiddenToken,"form");

但它不适用于锚标签

有几个错误:

  1. 您想向 HtmlCommandLink component which represents <h:commandLink>, but you're giving an example with <h:link>, which is represented by HtmlOutcomeTargetLink 添加参数。你到底想要什么?

  2. 一个PhaseListener on beforePhase() of RENDER_RESPONSE may be too late on GET requests which would only build the view for the first time during render response. At the moment your PhaseListener runs, the UIViewRoot would have no children at all. You'd better hook on view build time instead. For that, a SystemEventListener on PostAddToViewEvent最合适

  3. 您将参数名称设置为 id 而不是 name。使用 UIParameter#setName() 而不是 UIParameter#setId().

如果您确实打算将它们添加到 <h:link> 组件,那么这里是一个启动示例,您可以如何使用 SystemEventListener.

实现这一点
public class YourSystemEventListener implements SystemEventListener {

    @Override
    public boolean isListenerForSource(Object source) {
        return source instanceof HtmlOutcomeTargetLink;
    }

    @Override
    public void processEvent(SystemEvent event) throws AbortProcessingException {
        UIParameter parameter = new UIParameter();
        parameter.setName("sessiontoken");
        parameter.setValue("willberonadom");
        ((UIComponent) event.getSource()).getChildren().add(parameter);
    }

}

(如果您真的想在 <h:commandLink> 上应用它们,只需使用 || source instanceof HtmlCommandLink 扩展 isListenerForSource() 检查)

为了得到运行,在faces-config.xml中注册如下:

<application>
    <system-event-listener>
        <system-event-listener-class>com.example.YourSystemEventListener</system-event-listener-class>
        <system-event-class>javax.faces.event.PostAddToViewEvent</system-event-class>
    </system-event-listener>
</application>