2010-09-10 67 views
1

在当前项目中,我需要创建一个面板,该面板将包含由应用程序中其他位置创建的HTML内容。此内容可以很容易地插入这样的:包含动态生成的facelet的方法

<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,不能进行评估,并在ħ渲染:的outputText

我正在寻找一种在EL表达式尚未评估的阶段将这种动态内容包含在facelet中的好方法。像

<ui:include src="src"/> 

但动态组件将是最好的解决方案。

任何想法?

回答

0

最终我把简单的方法通过用相应的JSF元件和产生临时ui:composition的facelet文件替换所有自定义(花括号)令牌在用户HTML:

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

和在父的facelet:

<ui:include src="#{myBean.userHtmlContentPath}"/> 
1

是什么让这个复杂的,我认为,#{myBean.dynamicHTMLContent}是不完全的HTML内容,但JSF的内容。我认为最灵活的解决方案是编写自己的JSF组件。也许有人会纠正我,但我认为没有办法替代像{niceImage} JSF代码这样的文本。

有关于这个的一些文章:

我不是JSF专家,但你也可能:

  • 与引用扩展org.ajax4jsf.MediaOutput
  • parse out all the text in curly braces
  • 更换之类的东西niceImage#{myBean.generateNiceImage}或任何
  • 推进实际工作超级,org.ajax4jsf.MediaOutput

希望有所帮助!

+0

我在想创建一个自定义的JSF组件,但JSF内部的工作量不能被简单的工作的组件来真的是有道理的应该做。这是一样的,但一个动态的。所以我决定创建一个临时文件并使用将它包含到facelet中。 – theorm 2010-09-14 06:43:51

+0

我同意创建组件是最好的解决方案(可能不是通过扩展'MediaOutput')。看到我的答案。 – romaintaz 2010-09-14 07:24:31

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组件,您将找到它们的类型和类。

+0

这绝对是包括图像或链接等简单情况的最佳解决方案。但是,如果我们需要支持几乎任何可能的facelet组件,最好将这些任务卸载到JSF引擎。在我的情况下,我避免重复已经在a4j中的代码:mediaOutput,因为替换该令牌的映像是动态生成的。 – theorm 2010-09-14 12:03:14

1

您也可以使用includeFacelet(UIComponent, URL)来包含动态生成的facelets。诀窍是使用data URL方案和定制URLStreamHandler:如果你有一个通用的处理程序data://网址

String encoded = Base64.encodeBase64String(myDynamicFacelet.getBytes()); 
context.includeFacelet(uiComponent, new URL(null, "data://text/plain;base64," + encoded, new DataStreamHandler())); 

,它的使用是最好的选择。我需要一个处理程序只适用于本具体使用情况,所以它是非常有限的:

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); 
    } 
}