多个动态包含一个JSF标签

每个JSF开发人员都知道ui:include和ui:param标签。 您可以包括一个facelet(XHTML文件)并传递一个对象,该对象将在包含的facelet中可用,如下所示:

<ui:include src="/sections/columns.xhtml"><ui:param name="columns" value="#{bean.columns}"/>
</ui:include>

因此,您可以在带有dynamich列的PrimeFaces DataTable中使用它(p:columns)

<p:dataTable value="#{bean.entries}" var="data" rowKey="#{data.id}" ...>...<ui:include src="/sections/columns.xhtml"><ui:param name="data" value="#{data}"/><ui:param name="columns" value="#{bean.columns}"/></ui:include></p:dataTable>

其中包含的facelet可能包含此代码

<ui:composition xmlns="http://www.w3.org/1999/xhtml"xmlns:p="http://primefaces.org/ui"xmlns:ui="http://java.sun.com/jsf/facelets"...><p:columns value="#{columns}" var="column"><f:facet name="header"><h:outputText value="#{msgs[column.header]}"/></f:facet>// place some input / select or complex composite component for multiple data types here.// a simple example for demonstration purpose:<p:inputText value="#{data[column.property]}"/></p:columns>
</ui:composition>

#{bean.columns}表示描述这些列的特殊对象的列表。 我将此类对象命名为ColumnModel。 所以,这是一个
列出<ColumnModel>。 ColumnModel具有例如属性标头和属性。

继续。 现在,如果要添加对排序/过滤的支持,我们可以使用动态路径,该路径引用包含排序或/和过滤功能的特定facelet文件。 简单地将src属性绑定到bean属性。

<ui:include src="#{bean.columnsIncludeSrc}"><ui:param name="data" value="#{data}"/><ui:param name="columns" value="#{bean.columns}"/>
</ui:include>

豆有类似的东西

private boolean isFilterRight;
private boolean isSortRight// setter / getterpublic String getColumnsIncludeSrc() {if (isFilterRight && isSortRight) {return "/include/columnsTableFilterSort.xhtml";} else if (isFilterRight && !isSortRight) {return "/include/columnsTableFilter.xhtml";} else if (!isFilterRight && isSortRight) {return "/include/columnsTableSort.xhtml";} else {return "/include/columnsTable.xhtml";}
}

根据所设置的布尔权限,包含了不同的方面。 因此,将要包含的文件的决定放在Bean中。 为了更加灵活,我们可以将表封装在一个复合组件中,并将决策逻辑移至组件类。

<cc:interface componentType="xxx.component.DataTable"><cc:attribute name="id" required="false" type="java.lang.String"shortDescription="Unique identifier of the component in a NamingContainer"/><cc:attribute name="entries" required="true"shortDescription="The data which are shown in the datatable. This is a list of object representing one row."/><cc:attribute name="columns" required="true" type="java.util.List"shortDescription="The columns which are shown in the datatable. This is a list of instances of type ColumnModel."/>...
</cc:interface>
<cc:implementation><p:dataTable value="#{cc.attrs.entries}" var="data" rowKey="#{data.id}" ...>...<ui:include src="#{cc.columnsIncludeSrc}"><ui:param name="data" value="#{data}"/><ui:param name="columns" value="#{cc.attrs.columns}"/></ui:include></p:dataTable>
</cc:implementation>

ui:include如何工作? 这是在构建视图时应用的标记处理程序。 在JSF 2中,组件树根据POST请求构建两次,一次在RESTORE_VIEW阶段,一次在RENDER_RESPONSE阶段。 在GET上,它在RENDER_RESPONSE阶段构建一次。 此行为在JSF 2规范中指定,并且在Mojarra和MyFaces中相同。 如果页面作者使用条件包含或条件模板,则必须在RENDER_RESPONSE中建立视图。 因此,您可以确保ui:include的src属性在呈现阶段之前不久就得到了评估。

但是到了重点! 到目前为止,我所写的内容只是介绍了扩展ui:include的动机。 最近,我有一项任务要使用带有动态列的ap:dataTable和p:rowEditor。 在PrimeFaces展示柜中就是这样的 。 问题只是–这种编辑功能不支持p:columns。 我的想法是动态地多次添加p:column标签,但是具有不同的上下文参数。 您可以将其想象为ui:include和ui:param在循环中。 在上面的示例中,我们打算遍历List <ColumnModel>。 每次循环迭代都应在所包含的facelet中提供ColumnModel类型的实例。 因此,我编写了一个自定义标签处理程序以多次包含任何facelet。

package xxx.taghandler;import xxx.util.VariableMapperWrapper;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import javax.faces.component.UIComponent;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.TagAttribute;
import javax.faces.view.facelets.TagAttributeException;
import javax.faces.view.facelets.TagConfig;
import javax.faces.view.facelets.TagHandler;/*** Tag handler to include a facelet multiple times with different contextes (objects from "value").* The attribute "value" can be either of type java.util.List or array.* If the "value" is null, the tag handler works as a standard ui:include.*/
public class InlcudesTagHandler extends TagHandler {private final TagAttribute src;private final TagAttribute value;private final TagAttribute name;public InlcudesTagHandler(TagConfig config) {super(config);this.src = this.getRequiredAttribute("src");this.value = this.getAttribute("value");this.name = this.getAttribute("name");}@Overridepublic void apply(FaceletContext ctx, UIComponent parent) throws IOException {String path = this.src.getValue(ctx);if ((path == null) || (path.length() == 0)) {return;}// wrap the original mapper - this is important when some objects passed into include via ui:param// because ui:param invokes setVariable(...) on the set variable mappper instanceVariableMapper origVarMapper = ctx.getVariableMapper();ctx.setVariableMapper(new VariableMapperWrapper(origVarMapper));try {this.nextHandler.apply(ctx, null);ValueExpression ve = (this.value != null) ? this.value.getValueExpression(ctx, Object.class) : null;Object objValue = (ve != null) ? ve.getValue(ctx) : null;if (objValue == null) {// include facelet only oncectx.includeFacelet(parent, path);} else {int size = 0;if (objValue instanceof List) {size = ((List) objValue).size();} else if (objValue.getClass().isArray()) {size = ((Object[]) objValue).length;}final ExpressionFactory exprFactory = ctx.getFacesContext().getApplication().getExpressionFactory();final String strName = this.name.getValue(ctx);// generate unique Id as a valid Java identifier and use it as variable for the provided value expressionfinal String uniqueId = "a" + UUID.randomUUID().toString().replaceAll("-", "");ctx.getVariableMapper().setVariable(uniqueId, ve);// include facelet multiple timesStringBuilder sb = new StringBuilder();for (int i = 0; i < size; i++) {if ((strName != null) && (strName.length() != 0)) {// create a new value expression in the array notation and bind it to the variable "name"sb.append("#{");sb.append(uniqueId);sb.append("[");sb.append(i);sb.append("]}");ctx.getVariableMapper().setVariable(strName,exprFactory.createValueExpression(ctx, sb.toString(), Object.class));}// included facelet can access the created above value expressionctx.includeFacelet(parent, path);// reset for next iterationsb.setLength(0);}}} catch (IOException e) {throw new TagAttributeException(this.tag, this.src, "Invalid path : " + path);} finally {// restore original mapperctx.setVariableMapper(origVarMapper);}}
}

最重要的调用是ctx.includeFacelet(parent,path)。 JSF API中的 includeFacelet(…)方法在相对于当前标记的某个路径上包含了facelet标记。 类VariableMapperWrapper用于通过ui:param从名称到值的映射。 对于带有列的示例,在每次调用includeFacelet(...)之前,变量列还将映射到表达式#{columns [0]},#{columns [1]}等。 好吧,不完全是这些表达式,在列的位置应该是一个唯一的名称,该名称再次映射到columns对象(以避免可能的名称冲突)。 映射器类如下所示

package xxx.util;import java.util.HashMap;
import java.util.Map;
import javax.el.ELException;
import javax.el.ValueExpression;
import javax.el.VariableMapper;/*** Utility class for wrapping a VariableMapper. Modifications occur to the internal Map instance.* The resolving occurs first against the internal Map instance and then against the wrapped VariableMapper* if the Map doesn't contain the requested ValueExpression.*/
public class VariableMapperWrapper extends VariableMapper {private final VariableMapper wrapped;private Map<String, ValueExpression> vars;public VariableMapperWrapper(VariableMapper orig) {super();this.wrapped = orig;}@Overridepublic ValueExpression resolveVariable(String variable) {ValueExpression ve = null;try {if (this.vars != null) {// try to resolve against the internal mapve = this.vars.get(variable);}if (ve == null) {// look in the wrapped variable mapperreturn this.wrapped.resolveVariable(variable);}return ve;} catch (Throwable e) {throw new ELException("Could not resolve variable: " + variable, e);}}@Overridepublic ValueExpression setVariable(String variable, ValueExpression expression) {if (this.vars == null) {this.vars = new HashMap<String, ValueExpression>();}return this.vars.put(variable, expression);}
}

在taglib XML文件中注册标签处理程序,您就可以完成。

<tag><tag-name>includes</tag-name><handler-class>xxx.taghandler.InlcudesTagHandler</handler-class><attribute><description><![CDATA[The relative path to a XHTML file to be include one or multiple times.]]></description><name>src</name><required>true</required><type>java.lang.String</type></attribute><attribute><description><![CDATA[Objects which should be available in the included XHTML files. This attribute can be eitherof type java.util.List or array. If it is null, the tag handler works as a standard ui:include.]]></description><name>value</name><required>false</required><type>java.lang.Object</type></attribute><attribute><description><![CDATA[The name of the parameter which points to an object of each iteration over the given value.]]></description><name>name</name><required>false</required><type>java.lang.String</type></attribute>
</tag>

现在我可以在复合组件中使用它了

<p:dataTable value="#{cc.attrs.entries}" var="data" rowKey="#{data.id}" ...>...<custom:includes src="#{cc.columnsIncludeSrc}" value="#{cc.attrs.columns}" name="column"><ui:param name="data" value="#{data}"/></custom:includes> </p:dataTable>

典型的facelet文件(和组件树)包含一个非常规则的p:column标记,这意味着我们能够使用DataTable的所有功能!

<ui:composition xmlns="http://www.w3.org/1999/xhtml"xmlns:p="http://primefaces.org/ui"xmlns:ui="http://java.sun.com/jsf/facelets"...><p:column headerText="#{msgs[column.header]}"><p:cellEditor><f:facet name="output"><custom:typedOutput outputType="#{column.outputTypeName}"typedData="#{column.typedData}"value="#{data[column.property]}"timeZone="#{cc.timeZone}"calendarPattern="#{cc.calendarPattern}"       locale="#{cc.locale}"/></f:facet><f:facet name="input"><custom:typedInput inputType="#{column.inputTypeName}"typedData="#{column.typedData}"label="#{column.inputTypeName}"value="#{data[column.property]}"onchange="highlightEditedRow(this)"timeZone="#{cc.timeZone}"calendarPattern="#{cc.calendarPattern}"locale="#{cc.locale}"/></f:facet></p:cellEditor></p:column>
</ui:composition>

注意 :此方法可以应用于其他组件和用例。 InlcudesTagHandler可以正常运行。 例如,我可以想象在没有基础MenuModel的情况下在PrimeFaces中创建一个动态Menu组件。 当然,仍然需要某个模型类的列表或数组。

参考:在我们的软件开发博客上, JCG合作伙伴 Oleg Varaksin的一个JSF标签包含了多个动态 。

翻译自: https://www.javacodegeeks.com/2013/06/multiple-dynamic-includes-with-one-jsf-tag.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java map遍历最快_Java Map遍历速度最优解

第一种:Map map new HashMap();Iterator iter map.entrySet().iterator();while (iter.hasNext()) {Map.Entry entry (Map.Entry) iter.next(); Object key entry.getKey();Object val entry.getValue();}效率高,以后一定要使用此种方式!第二种:Map map new HashMap();It…

[JLOI2014]松鼠的新家

嘟嘟嘟 这还是一道树链剖分板子题呀&#xff01; 从1到n - 1枚举a[i]&#xff0c;每一次使节点a[i]到a[i 1]的路径加1&#xff0c;但这样的话除a[1]&#xff0c;每一个点都多加了一个1&#xff0c;所以输出答案的时候减1即可。 1 #include<cstdio>2 #include<iostrea…

Html5中的Video元素使用方法

现在互联网视频大都使用Flash来实现。但是不同的浏览器可能使用不同的插件。在HTML5中则提供了一个统一的方式来展示视频内容。HTML5 video在Internet Explorer 9, Firefox, Opera, Chrome, 和Safari都支持。IE8及其更早的浏览器不支持。 代码如下 <SPAN style"COLOR:…

CSS3-背景(background-image、background-size、background-origin、background-clip)

CSS3中新的背景属性&#xff1a;background-image、background-size、background-origin、background-clip 背景图片&#xff1a;background-image CSS3中可以通过background-image属性添加背景图片。 不同的背景图像和图像用逗号隔开&#xff0c;所有的图片中显示在最顶端的为…

使用String.intern()减少内存使用

时不时地会有一个垂死的生产应用程序。 而且您知道您需要尽快对其进行修补。 我们也一样&#xff0c;并认为分享最近的一个战争故事将很有趣。 在这种情况下&#xff0c;我们就有机会使用String.intern&#xff08;&#xff09;之类的简单补丁来修补应用程序。 但是&#xff0c…

CSS实现比翼双飞和圣杯布局模型效果

圣杯模型和比翼双飞模型主要的特指1.首先加载的是中间部分&#xff0c;其次是左边&#xff0c;然后是右边 2.中间是自适应&#xff0c;二边是定宽 实现方法1.grid2.margin float position:releative父亲加padding 挤进去3.margin float box-size:border-box 1.gridhtml:&l…

java struts2 excel上传_文件上传方法,使用Struts2,实现Excel文件读取并写入数据库技术...

文件上传方法&#xff0c;使用Struts2&#xff0c;实现Excel文件读取并写入数据库技术如题&#xff1a;文件信息的批量导入……项目中经常会遇到客户的一些单表信息的数据批量导入&#xff0c;也就是提供定制Excel表&#xff0c;再把Excel表中的数据提取到数据库的操作&#xf…

jmeter创建高级测试计划

如果应用程序使用重写地址而不是使用cookie存储信息&#xff0c;需要做一些额外的工作去测试程序 为了正确的响应重写地址&#xff0c;jmeter 需要解析 从服务器获取html 并且检索会话ID, 1 合理利用pre-processors-http url rewriting modifier 来完成&#xff0c;简单的输入s…

从这开始

今天正式加入博客园&#xff01; 今后跟大家分享有关IoT软件方面的知识&#xff0c;包括WIFI 、蓝牙、Zigbee、 Sub-1G 、NB-IoT、GPRS/GPS和单片机等。 有疑问欢迎留言联系&#xff01;转载于:https://www.cnblogs.com/crepse/p/9502342.html

单元测试技巧:创建描述性测试

您的单元测试应尽可能具有描述性。 他们给您的反馈应该非常清楚&#xff0c;您甚至不需要启动调试器并一步一步地检查代码来检查局部变量。 为什么&#xff1f; 因为那需要时间&#xff0c;而且我们很懒&#xff0c;对吗&#xff1f; 为此&#xff0c;您需要创建描述性测试。 有…

Div前台显示自动换行和不自动换行的问题

1、无法自动换行* 问题&#xff1a;如果 div 输入的是英文字母且没有空格&#xff0c;会导致英文字母不换行直接在同一行输出&#xff0c;导致 div 的宽度远远超出设定的大小。* 原因&#xff1a;因为在 div 中&#xff0c;英文字母之间没有空格的话&#xff0c;默认为一个英文…

java 自定义taglib_java – 非常简单的自定义taglib函数无法正常工作

我正在敲打为什么我的自定义taglib功能不起作用.该示例使用Math.cos和Math.sin.这是班级&#xff1a;package foo.tags;public class Math {public java.lang.Double cos(java.lang.Double value) {return java.lang.Math.cos(value);}public java.lang.Double sin(java.lang.D…

python基础知识(二)if语句

if语句是条件判断语句 格式为&#xff1a; if 条件:执行语句 elif 再一个条件:执行语句 else:执行语句注意&#xff1a; if 与elif后不要忘记冒号 例子&#xff1a; #Autor:Decade value156 value2int(input(number:)) #提示用户输入一个整数型的数字 if value1>value2: …

vue.js--基础事件定义,获取数据,执行方法传值

<template><div id"app"> <h1>{{ msg }}</h1> <br> <button v-on:click"run1()"> 第一种写法</button> <br> <button clickrun2()> 第二种写法</button> <br> <button clickgetMsg(…

Spring集成–强大的拆分器聚合器

坚固是什么意思&#xff1f; 在本文的上下文中&#xff0c;健壮性是指在不立即返回到调用者的情况下管理流中的异常条件的能力。 在某些处理方案中&#xff0c; n个 m个回答足以做出结论。 通常具有这些趋势的示例处理场景是&#xff1a; 财务&#xff0c;保险和预订系统的…

CSS字体设置的一些技巧(行高,加粗,强制换行等)

文本是网页中最重要的一种内容形式&#xff0c;文本几乎可以写在任何地方&#xff0c;块级元素中可以写行内元素中也可以写。文本都是由一个个字符组成的&#xff0c;在css布局中&#xff0c;每一个字符都有一个em框&#xff0c;通常font-size设置的大小就是设置的em框的大小&a…

java memcache 队列_基于memcache的java分布式队列实现。

主要有两个类&#xff0c;一个队列类和一个job的抽象类。保证队列类中的key的唯一性&#xff0c;就可以用spring配置多个实例。水平有限&#xff0c;欢迎吐槽。上代码&#xff1a;1、队列类import net.spy.memcached.MemcachedClient;import net.spy.memcached.internal.Operat…

【题解】 [ZJOI2009]假期的宿舍 (二分图匹配)

懒得复制题面&#xff0c;戳我 Solution: 处理出床位、要留校的人&#xff08;注意来访问的人一定住校&#xff09;&#xff0c;和人与人的关系&#xff08;连边&#xff09;再接着就是二分图。注意的就是连向的人必须是有床位的还要注意的就是只用判断住校的同学二分图板子都打…

android-线程池-最顺手的写法

引子 关于线程池&#xff0c;在这里写出几种最顺手的写法&#xff0c;至于原理以及各种细节。放后面再填&#xff1b; 经过查证&#xff0c;凡是 以前new Thread&#xff08;&#xff09;的地方&#xff0c;貌似都可以用线程池来执行&#xff0c;优化内存消耗。 代码 系统提供的…

使用Java和Google GSON解析ESPN API

在我的第一篇文章中&#xff0c;我将解释如何解析ESPN API。 可以在http://developer.espn.com/docs上找到API文档。 首先&#xff0c;您需要请求一个API密钥&#xff0c;然后可以开始查询REST API以检索JSON响应。 在下面的示例中&#xff0c;我将简单地查询在英格兰英超联赛…