包含动态生成的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代码这样的文本。

有一些关于这个的文章:

我不是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(); } 

并在父面孔中: