包含动态生成的facelet的方法
在当前项目中,我需要创建一个面板,其中包含用户在应用程序中其他位置创建的HTML内容。 这个内容可以像这样轻松插入:
示例内容:
User text
现在我们需要为用户提供更多的自由,并允许他在HTML代码中使用令牌,稍后将由应用程序解析:
User text
User image: {niceImage}
该应用程序解析myBean.dynamicHTMLContent中的用户内容,并将{niceImage(param)}替换为
这已经是facelet片段,无法在h:outputText中进行评估和呈现。
我正在寻找一种在EL表达式尚未评估的阶段将这种动态内容包含在facelet中的好方法。 就像是
但对于动态组件来说,这将是最佳解决方案。
有任何想法吗?
我同意user423943为此创建组件的想法。 但是,我会扩展
。 在您的情况下,您将无需做很多工作。 首先,创建一个my.taglib.xml
文件:
http://my.components/jsf myComponent my.component.myComponent my.renderkit.myComponent
此文件只需要存在于应用程序的类路径中,它将由Facelets自动加载(因为它以.taglib.xml
)。
然后,在faces-config.xml
定义此组件的Java类:
my.component.myComponent my.package.component.MyHtmlComponent HTML_BASIC javax.faces.Output my.renderkit.myComponent my.package.component.MyHtmlComponentRenderer
然后,您将必须创建两个类:
-
my.package.component.MyHtmlComponent
将扩展javax.faces.component.html.HtmlInputText
并且不做任何其他事情。 -
my.package.component.MyHtmlComponentRenderer
将扩展com.sun.faces.renderkit.html_basic.TextRenderer
类。
您的渲染器类将完成所有工作,方法是生成组件值的HTML代码,与
完全相同。 您可以查看本部分中涉及的HtmlBasicRenderer.encodeEnd(FacesContext, UIComponent)
和TextRenderer.getEndTextToRender(FacesContext, UIComponent, String)
方法。 当然,当您在文本中面对{niceImage}
代码时,您只需要生成HTML img
标记。 为此,您可以使用ResponseWriter
的适当方法来构建HTML标记和属性:
writer.startElement("img", component); writer.writeAttribute("src", urlToImage); writer.endElement("img");
创建完所有内容后,您必须在JSF页面中使用新组件:
... ...
除了user423943提供的链接之外,还有两个可以帮助您的链接:
http://www.jsftutorials.net/helpDesk/standardRenderKit_component-class_renderer-slass.html
http://www.jsftutorials.net/helpDesk/standardRenderKit_component-type_renderer-type.html
您会发现,对于所有HTML JSF组件,它们的类型和类。
我认为,这种复杂的原因是#{myBean.dynamicHTMLContent}
不是HTML内容,而是JSF内容。 我认为最灵活的解决方案是编写自己的JSF组件。 也许有人会纠正我,但我认为没有办法替换像{niceImage}
JSF代码这样的文本。
有一些关于这个的文章:
- http://www.theserverside.com/news/1364786/Building-Custom-JSF-UI-Components
- http://www.ibm.com/developerworks/library/j-jsf1/
- http://www.theserverside.com/news/1364786/Building-Custom-JSF-UI-Components
- http://download.oracle.com/javaee/5/tutorial/doc/bnavh.html
- http://www.ibm.com/developerworks/java/library/j-jsf4/
- https://matthiaswessendorf.wordpress.com/2008/02/29/custom-jsf-components-with-facelets/
我不是JSF专家,但你可能:
- 扩展
org.ajax4jsf.MediaOutput
- 解析大括号中的所有文本
- 用
niceImage
#{myBean.generateNiceImage}
等替换#{myBean.generateNiceImage}
东西 - 将实际工作转发给超类
org.ajax4jsf.MediaOutput
希望有所帮助!
您还可以使用includeFacelet(UIComponent, URL)
来包含动态生成的facelets。 诀窍是使用data
URL方案和自定义URLStreamHandler
:
String encoded = Base64.encodeBase64String(myDynamicFacelet.getBytes()); context.includeFacelet(uiComponent, new URL(null, "data://text/plain;base64," + encoded, new DataStreamHandler()));
如果您有data://
URL的通用处理程序,那么它是最好的选择。 我只需要这个特定用例的处理程序,所以它非常有限:
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import org.apache.commons.codec.binary.Base64; public class DataStreamHandler extends URLStreamHandler { private static class DataURLConnection extends URLConnection { @Override public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(this.content.getBytes()); } private static String PREFIX = "data://text/plain;base64,"; private static int PREFIX_LEN = PREFIX.length(); protected DataURLConnection(URL url) { super(url); this.url = url; String encoded = this.url.toString().substring(PREFIX_LEN); this.content = new String(Base64.decodeBase64(encoded)); } @Override public void connect() throws IOException { // Do nothing } private URL url; private String content; } @Override protected URLConnection openConnection(URL url) throws IOException { return new DataURLConnection(url); } }
最后,我采用简单的方法,用相应的JSF元素替换用户HTML中的所有自定义(花括号)标记,并生成一个临时的ui:composition
facelet文件:
public String getUserHtmlContentPath() { File temp = File.createTempFile("userContent", ".tmp"); temp.deleteOnExit(); FileWriter fw = new FileWriter(temp); fw.write(getUserHtmlContentComposition()); fw.close(); return "file://" + temp.getAbsolutePath(); }
并在父面孔中: