Jsf 2 从流中包含包含JSF标记/组件的动态内容

Jsf 2 从流中包含包含JSF标记/组件的动态内容,jsf-2,facelets,jsf-2.2,dynamic-content,Jsf 2,Facelets,Jsf 2.2,Dynamic Content,我正在开发一个应用程序,其中我希望包含来自流的动态XHTML内容。为了处理这个问题,我编写了一个taghandler扩展,它将动态XHTML内容转储到输出组件 UIOutput htmlChild = (UIOutput) ctx.getFacesContext().getApplication().createComponent(UIOutput.COMPONENT_TYPE); htmlChild.setValue(new String(outputStream.toByteArray(),

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

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

这对于没有JSF标记的XHTML内容很好。如果我的动态XHTML内容中有JSF标记,比如
,那么它们将以纯文本形式打印。我希望它们呈现为输入字段。我怎样才能做到这一点

基本上,您应该将
与能够以
URL
的风格返回资源的自定义组合使用。因此,当有一个
OutputStream
时,您实际上应该将其写入一个(temp)文件中,以便从中获取
URL

例如



注意:以上所有内容都是针对JSF2.2的。对于遇到这个问题的JSF 2.0/2.1用户,您应该使用
ResourceResolver
,在这个问题的答案中有一个示例:。重要提示:
ResourceResolver
在JSF 2.2中支持
ResourceHandler\createViewResource()

我的JSF 2.2和自定义URLStream处理程序解决方案

公共类数据库ResourceHandlerWrapper扩展了ResourceHandlerWrapper{

private ResourceHandler wrapped;

@Inject
UserSessionBean userBeean;

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

@Override
public Resource createResource(String resourceName, String libraryName) {
    return super.createResource(resourceName, libraryName); //To change body of generated methods, choose Tools | Templates.
}

@Override
public ViewResource createViewResource(FacesContext context, String resourceName) {
    if (resourceName.startsWith("/dynamic.xhtml?")) {
        try {
            String query = resourceName.substring("/dynamic.xhtml?".length());
            Map<String, String> params = splitQuery(query);
            //do some query to get content
            String content = "<ui:composition"
                    + " xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets'"
                    + " xmlns:h='http://java.sun.com/jsf/html'> MY CONTENT"
                    + "</ui:composition>";

            final URL url = new URL(null, "string://helloworld", new MyCustomHandler(content));
            return new ViewResource() {
                @Override
                public URL getURL() {
                    return url;
                }
            };
        } catch (IOException e) {
            throw new FacesException(e);
        }
    }

    return super.createViewResource(context, resourceName);
}

public static Map<String, String> splitQuery(String query) throws UnsupportedEncodingException {
    Map<String, String> params = new LinkedHashMap<>();
    String[] pairs = query.split("&");
    for (String pair : pairs) {
        int idx = pair.indexOf("=");
        params.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
    }
    return params;
}

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

static class MyCustomHandler extends URLStreamHandler {

    private String content;

    public MyCustomHandler(String content) {
        this.content = content;
    }

    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        return new UserURLConnection(u, content);
    }

    private static class UserURLConnection extends URLConnection {

        private String content;

        public UserURLConnection(URL url, String content) {
            super(url);
            this.content = content;
        }

        @Override
        public void connect() throws IOException {
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(content.getBytes("UTF-8"));
        }
    }

}
私有资源处理器包装;
@注入
UserSessionBean userBeean;
公共数据库ResourceHandlerWrapper(ResourceHandler包装){
this.wrapped=wrapped;
}
@凌驾
公共资源createResource(字符串resourceName、字符串libraryName){
return super.createResource(resourceName,libraryName);//若要更改生成的方法体,请选择工具|模板。
}
@凌驾
公共ViewResource createViewResource(FacesContext上下文,字符串resourceName){
if(resourceName.startsWith(“/dynamic.xhtml?”)){
试一试{
String query=resourceName.substring(“/dynamic.xhtml?”.length());
Map params=splitQuery(查询);
//执行一些查询以获取内容
String content=“我的内容”
+ "";
最终URL=新URL(空)string://helloworld“,新的MyCustomHandler(内容));
返回新的ViewResource(){
@凌驾
公共URL getURL(){
返回url;
}
};
}捕获(IOE异常){
抛开新面孔(e);
}
}
返回super.createViewResource(上下文,resourceName);
}
公共静态映射拆分查询(字符串查询)引发UnsupportedEncodingException{
Map params=新建LinkedHashMap();
String[]pairs=query.split(&);
for(字符串对:对){
int idx=pair.indexOf(“=”);
参数put(urldecker.decode(成对子串(0,idx),“UTF-8”)、urldecker.decode(成对子串(idx+1),“UTF-8”);
}
返回参数;
}
@凌驾
公共资源处理程序getWrapped(){
返回包装;
}
静态类MyCustomHandler扩展了URLStreamHandler{
私有字符串内容;
公共MyCustomHandler(字符串内容){
this.content=内容;
}
@凌驾
受保护的URL连接openConnection(URL u)引发IOException{
返回新的UserURLConnection(u,内容);
}
私有静态类UserURLConnection扩展了URLConnection{
私有字符串内容;
公共用户URL连接(URL、字符串内容){
超级链接(url);
this.content=内容;
}
@凌驾
public void connect()引发IOException{
}
@凌驾
公共InputStream getInputStream()引发IOException{
返回新的ByteArrayInputStream(content.getBytes(“UTF-8”);
}
}
}

}

这是由我的应用程序中的工具填写的ByteArrayOutputStream。此ByteArrayOutputStream包含生成的xhtml内容。编写JSP自定义标记库是否有帮助?据我所知,它们处于JSF生命周期的顶端。@BalusC基于临时文件的Resourcehandler机制是否适用?通常,资源处理程序用于静态资源。我在这里再也看不到你建议的代码片段了。它肯定能工作,否则我不会把它作为答案发布。除非明确提到,否则我从不发布未经测试的代码。我删除了它,因为根据评论,这种方法不被您所接受,并且我无法在没有事先调查/测试的情况下从顶部说出一个包含完整工作代码示例的非临时文件方法(但理论上,这肯定是可能的)。您能在这里提供基于临时文件的解决方案吗?我希望在未来几天内至少有一个有效的解决方案。也许以后有人可以提供一个动态解决方案建议。我正在寻找一种不必在web服务器上存储临时文件的方法。是否没有直接处理内存中数据的替代方法?也许使用自定义jsf组件/标记等,您可以创建自定义的
URLStreamHandlerFactory
URLStreamHandler
。无法从头开始给出示例,因此对此没有答案。问题:是否可以访问支持bean对象并/或将某些参数传递给资源处理程序?您可以在资源处理程序中使用CDI
@Inject
,或通过
应用程序#evaluateExpressionGet()
以编程方式计算EL。传递参数当然可能是“通常的方式”,通过相应地操纵
src
,就像这样
src=“/dynamic.xhtml?param=value”
,您只需要自己使用
resourceName
上的
String#split()
来解析它。请注意,
src
中的路径格式完全由您自由选择。例如,
src=“dynamic:foo,bar,baz”
等与
if(resourceName.startsWith(“dynamic:”)
检查相结合。我尝试了这个方法,效果如预期。但我无法在那里注入我的豆子。我们需要什么特别的东西来注射豆子吗?
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;
    }

}
<application>
    <resource-handler>com.example.DynamicResourceHandler</resource-handler>
</application>
private ResourceHandler wrapped;

@Inject
UserSessionBean userBeean;

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

@Override
public Resource createResource(String resourceName, String libraryName) {
    return super.createResource(resourceName, libraryName); //To change body of generated methods, choose Tools | Templates.
}

@Override
public ViewResource createViewResource(FacesContext context, String resourceName) {
    if (resourceName.startsWith("/dynamic.xhtml?")) {
        try {
            String query = resourceName.substring("/dynamic.xhtml?".length());
            Map<String, String> params = splitQuery(query);
            //do some query to get content
            String content = "<ui:composition"
                    + " xmlns='http://www.w3.org/1999/xhtml' xmlns:ui='http://java.sun.com/jsf/facelets'"
                    + " xmlns:h='http://java.sun.com/jsf/html'> MY CONTENT"
                    + "</ui:composition>";

            final URL url = new URL(null, "string://helloworld", new MyCustomHandler(content));
            return new ViewResource() {
                @Override
                public URL getURL() {
                    return url;
                }
            };
        } catch (IOException e) {
            throw new FacesException(e);
        }
    }

    return super.createViewResource(context, resourceName);
}

public static Map<String, String> splitQuery(String query) throws UnsupportedEncodingException {
    Map<String, String> params = new LinkedHashMap<>();
    String[] pairs = query.split("&");
    for (String pair : pairs) {
        int idx = pair.indexOf("=");
        params.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
    }
    return params;
}

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

static class MyCustomHandler extends URLStreamHandler {

    private String content;

    public MyCustomHandler(String content) {
        this.content = content;
    }

    @Override
    protected URLConnection openConnection(URL u) throws IOException {
        return new UserURLConnection(u, content);
    }

    private static class UserURLConnection extends URLConnection {

        private String content;

        public UserURLConnection(URL url, String content) {
            super(url);
            this.content = content;
        }

        @Override
        public void connect() throws IOException {
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return new ByteArrayInputStream(content.getBytes("UTF-8"));
        }
    }

}