包含流中包含 JSF 标签/组件的动态内容

use*_*786 4 facelets dynamic-content jsf-2 jsf-2.2

我正在开发一个应用程序,我想在其中包含来自流的动态 XHTML 内容。为了处理这个问题,我编写了一个标记处理程序扩展,它将动态 XHTML 内容转储到输出组件,如下所示

UIOutput htmlChild = (UIOutput) ctx.getFacesContext().getApplication().createComponent(UIOutput.COMPONENT_TYPE);
htmlChild.setValue(new String(outputStream.toByteArray(), "utf-8"));
Run Code Online (Sandbox Code Playgroud)

这对于没有 JSF 标签的 XHTML 内容效果很好。如果我的动态 XHTML 内容中有 JSF 标记(例如 )<h:inputText value="#{bean.item}"/>,那么它们会以纯文本形式打印。我希望它们呈现为输入字段。我怎样才能实现这个目标?

Bal*_*usC 5

本质上,您应该将<ui:include>与自定义结合使用ResourceHandler,该自定义能够以 的风格返回资源URL。因此,当拥有 时OutputStream,您确实应该将其写入(临时)文件,以便您可以从中获取URL

例如

<ui:include src="/dynamic.xhtml" />
Run Code Online (Sandbox Code Playgroud)

public class DynamicResourceHandler extends ResourceHandlerWrapper {

    private ResourceHandler wrapped;

    public DynamicResourceHandler(ResourceHandler wrapped) {
        this.wrapped = wrapped;
    }

    @Override
    public ViewResource createViewResource(FacesContext context, String resourceName) {
        if (resourceName.equals("/dynamic.xhtml")) {
            try {
                File file = File.createTempFile("dynamic-", ".xhtml");

                try (Writer writer = new FileWriter(file)) {
                    writer
                        .append("<ui:composition")
                        .append(" xmlns:ui='http://java.sun.com/jsf/facelets'")
                        .append(" xmlns:h='http://java.sun.com/jsf/html'")
                        .append(">")
                        .append("<p>Hello from a dynamic include!</p>")
                        .append("<p>The below should render as a real input field:</p>")
                        .append("<p><h:inputText /></p>")
                        .append("</ui:composition>");
                }

                final URL url = file.toURI().toURL();
                return new ViewResource(){
                    @Override
                    public URL getURL() {
                        return url;
                    }
                };
            }
            catch (IOException e) {
                throw new FacesException(e);
            }
        }

        return super.createViewResource(context, resourceName);
    }

    @Override
    public ResourceHandler getWrapped() {
        return wrapped;
    }

}
Run Code Online (Sandbox Code Playgroud)

(警告:基本启动示例!这会在每个请求上创建一个新的临时文件,您应该自己发明一个重用/缓存系统)

注册faces-config.xml如下

<application>
    <resource-handler>com.example.DynamicResourceHandler</resource-handler>
</application>
Run Code Online (Sandbox Code Playgroud)

注意:以上所有内容都是针对 JSF 2.2 的。对于偶然发现此答案的 JSF 2.0/2.1 用户,您应该使用ResourceResolver此答案中提供的示例:从外部文件系统或数据库获取 Facelets 模板/文件。重要提示:在 JSF 2.2 中已弃用,ResourceResolver取而代之的是.ResourceHandler#createViewResource()