如何访问使用< ui:define>创建的内容的内容以编程方式? [英] How can I access the content of something created with <ui:define> programmatically?

查看:91
本文介绍了如何访问使用< ui:define>创建的内容的内容以编程方式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在上下文中哪里可以找到有关使用<ui:define>构建的内容的信息?我想访问在我的bean中用<ui:define name="title">Some title</ui:define>定义的页面标题.

Where in the contexts can I find the information for something built with a <ui:define>? I want to access a page title that has been defined with <ui:define name="title">Some title</ui:define> in my bean.

为说明我的问题,我可以访问使用定义的变量

To illustrate my question, I can access a variable defined with

<ui:param name="myVariable" value="This is my variable!"/>

通过查看EL上下文中的变量映射器,就像这样

by looking at the variable mapper in the EL context, like this

VariableMapper variableMapper = elContext.getVariableMapper();
String myVariable = variableMapper.resolveVariable("myVariable").getValue(elContext).toString();

这对<ui:param>有效,但是对<ui:define>如何完成?

This works for <ui:param>, but how is it done for <ui:define>?

推荐答案

无法通过标准API进行. Xtreme Biker发布了一个绝妙的技巧,即默认"在<ui:insert>内部指定了<ui:param>值,当

This is not possible via standard API. Xtreme Biker has posted a brilliant trick whereby a "default" <ui:param> value is specified inside the <ui:insert> which would be overriden (and thus absent) when a <ui:define> is actually specified as answer on Test if ui:insert has been defined in the template client

(骇人听闻的)替代方案是为作业创建自定义标签处理程序. <ui:define>的名称收集在<ui:composition>之后的CompositionHandler标记处理程序类的Map handlers字段中. (不幸的是)这是特定于实现的,

A (hacky) alternative would be to create a custom taghandler for the job. The <ui:define>s are by their name collected in Map handlers field of the CompositionHandler taghandler class behind <ui:composition>. This is (unfortunately) implementation specific, Mojarra and MyFaces have their own implementations whereby Mojarra has named the field handlers and MyFaces _handlers.

因为该字段只是protected,所以最干净的方法是扩展CompositionHandler taghandler类,并至少将apply()方法中的键集公开为FaceletContext的属性.但是,由于CompositionHandler类本身已声明为final,因此我们无法对其进行子类化.因此,无论如何我们都不能将其包装为委托并使用一些反射黑客来抢占该领域.

As the field is just protected, cleanest would be to just extend the CompositionHandler taghandler class and expose at least the keyset in the apply() method as attribute of FaceletContext. However, as the CompositionHandler class itself is declared final, we can't subclass it. Therefore, we can't go around wrapping it as a delegate and use some reflection hackery to grab the field anyway.

这是一个基于Mojarra的启动示例,该示例收集了Map<String, Boolean>中所有已声明的<ui:define>处理程序名称,这样您就可以像分别#{defined.foo ? '...' : '...'}#{not defined.foo ? '...' : '...'}一样在EL中很好地使用它们.

Here's a kickoff example based on Mojarra which collects all declared <ui:define> handler names in a Map<String, Boolean> so that you can nicely use them in EL like so #{defined.foo ? '...' : '...'} respectively #{not defined.foo ? '...' : '...'}.

public class DefineAwareCompositionHandler extends TagHandlerImpl implements TemplateClient {

    private CompositionHandler delegate;
    private Map<String, Boolean> defined;

    @SuppressWarnings("unchecked")
    public DefineAwareCompositionHandler(TagConfig config) {
        super(config);
        delegate = new CompositionHandler(config);

        try {
            Field field = delegate.getClass().getDeclaredField("handlers");
            field.setAccessible(true);
            Map<String, DefineHandler> handlers = (Map<String, DefineHandler>) field.get(delegate);

            if (handlers != null) {
                defined = new HashMap<>();

                for (String name : handlers.keySet()) {
                    defined.put(name, true);
                }
            }
        }
        catch (Exception e) {
            throw new FaceletException(e);
        }
    }

    @Override
    public void apply(FaceletContext ctx, UIComponent parent) throws IOException {
        ctx.setAttribute("defined", defined);
        delegate.apply(ctx, parent);
    }

    @Override
    public boolean apply(FaceletContext ctx, UIComponent parent, String name) throws IOException {
        return delegate.apply(ctx, parent, name);
    }

}

在自定义my.taglib.xml中将其注册如下:

Register it as follows in your custom my.taglib.xml:

<tag>
    <tag-name>composition</tag-name>
    <handler-class>com.example.DefineAwareCompositionHandler</handler-class>
</tag>

您可以如下使用它:

<my:composition
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://xmlns.jcp.org/jsf/core"
    xmlns:h="http://xmlns.jcp.org/jsf/html"
    xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    xmlns:my="http://example.com/ui"
>
    <ui:insert name="foo">
        ...
    </ui:insert>

    <div class="#{defined.foo ? 'style1' : 'style2'}">
        ...
    </div>
</my:composition>

同样,这是很棘手的(因为它是特定于实现的),我不建议您使用它.

Again, this is hacky (as it's implementation specific), I'd not recommend using it.

这篇关于如何访问使用&lt; ui:define&gt;创建的内容的内容以编程方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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