如何访问使用< ui:define>创建的内容的内容以编程方式? [英] How can I access the content of something created with <ui:define> programmatically?
问题描述
在上下文中哪里可以找到有关使用<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
字段中. (不幸的是)这是特定于实现的, MyFaces 有其自己的实现, Mojarra已将字段命名为handlers
,并将MyFaces命名为_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.
这篇关于如何访问使用< ui:define>创建的内容的内容以编程方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!