在当前项目中,我需要创建一个面板,其中包含用户在应用程序中其他位置创建的HTML内容。这个内容可以像这样轻松插入:
<h:outputText value="#{myBean.dynamicHTMLContent}" escape="false"/>
示例内容:
<p>User text</p>
现在我们需要为用户提供更多自由,并允许他在HTML代码中使用令牌,稍后将由应用程序解决:
<p>User text</p><p>User image: {niceImage}</p>
应用程序解析 myBean.dynamicHTMLContent 中的用户内容,并用
替换 {niceImage(param)}<a4j:mediaOutput element="img" createContent="{myBean.generateNiceImage}"/>
这已经是一个facelet代码段,无法在 h:outputText 中进行评估和呈现。
我正在寻找一种在EL表达式尚未评估的阶段在facelet中包含此类动态内容的好方法。像
这样的东西<ui:include src="src"/>
但对于动态组件来说,这将是最好的解决方案。
有什么想法吗?
答案 0 :(得分:3)
我同意user423943为此创建组件的想法。但是,我会延长<h:outputText>
。在您的情况下,您将无需做很多工作。首先,创建一个my.taglib.xml
文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE facelet-taglib PUBLIC "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN" "facelet-taglib_1_0.dtd">
<facelet-taglib>
<namespace>http://my.components/jsf</namespace>
<tag>
<tag-name>myComponent</tag-name>
<component>
<component-type>my.component.myComponent</component-type>
<renderer-type>my.renderkit.myComponent</renderer-type>
</component>
</tag>
</facelet-taglib>
此文件只需要存在于应用程序的类路径中,它将由Facelets自动加载(因为它以.taglib.xml
结尾)。
然后,在faces-config.xml
中定义此组件的Java类:
<component>
<component-type>my.component.myComponent</component-type>
<component-class>my.package.component.MyHtmlComponent</component-class>
</component>
<render-kit>
<render-kit-id>HTML_BASIC</render-kit-id>
<renderer>
<component-family>javax.faces.Output</component-family>
<renderer-type>my.renderkit.myComponent</renderer-type>
<renderer-class>my.package.component.MyHtmlComponentRenderer</renderer-class>
</renderer>
然后,您将必须创建两个类:
my.package.component.MyHtmlComponent
将延长javax.faces.component.html.HtmlInputText
并且不做任何其他事情。my.package.component.MyHtmlComponentRenderer
将扩展com.sun.faces.renderkit.html_basic.TextRenderer
类。您的渲染器类将完成所有工作,方法是生成组件值的HTML代码,与<h:outputText>
完全相同。您可以查看本部分中涉及的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页面中使用新组件:
<html xmlns:my="http://my.components/jsf">
...
<my:myComponent value="#{myBean.dynamicHTMLContent}" escape="false"/>
...
除了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组件,您会发现它们的类型和类。
答案 1 :(得分:1)
我认为,这种复杂的原因是#{myBean.dynamicHTMLContent}
不是HTML内容,而是JSF内容。我认为最灵活的解决方案是编写自己的JSF组件。也许有人会纠正我,但我认为没有办法替换像{niceImage}
JSF代码这样的文字。
有一些关于此的文章:
我不是JSF专家,但你可能会:
org.ajax4jsf.MediaOutput
niceImage
或其他#{myBean.generateNiceImage}
之类的内容
org.ajax4jsf.MediaOutput
希望有所帮助!
答案 2 :(得分:1)
您也可以使用includeFacelet(UIComponent, URL)
来包含动态生成的facelets。诀窍是使用data
网址方案和自定义URLStreamHandler
:
String encoded = Base64.encodeBase64String(myDynamicFacelet.getBytes());
context.includeFacelet(uiComponent, new URL(null, "data://text/plain;base64," + encoded, new DataStreamHandler()));
如果您有data://
个网址的通用处理程序,那么它是最佳选择。我只需要这个特定用例的处理程序,所以它非常有限:
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);
}
}
答案 3 :(得分:0)
最后,我采用简单的方法,用相应的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();
}
并在父面孔中:
<ui:include src="#{myBean.userHtmlContentPath}"/>