2013-11-28 85 views
1

我正在研究一個應用程序,我想從流中包含動態XHTML內容。爲了解決這個問題,我寫了taghandler擴展,轉儲動態XHTML內容輸出組件作爲包含來自流的包含JSF標記/組件的動態內容

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

這工作得很好XHTML的內容不具有JSF標籤。如果我在我的動態XHTML內容(如<h:inputText value="#{bean.item}"/>)中包含JSF標記,那麼它們將被打印爲純文本。我希望他們渲染爲輸入字段。我怎樣才能做到這一點?

+0

這是ByteArrayOutputStream這是從我的應用程序的工具填寫。這個ByteArrayOutputStream包含生成的xhtml內容。 – user3027786

+0

寫JSP自定義taglib會有幫助嗎?據我所知他們是在JSF生命週期的頂部。 – user3027786

+0

@BalusC是否爲基於臨時文件的Resourcehandler機制適用於?通常資源處理程序用於靜態資源。我在這裏看不到你的建議代碼片段。 – user3027786

回答

1

基本上,您應該使用<ui:include>結合自定義ResourceHandler,它能夠返回URL的味道的資源。所以當你有一個OutputStream時,你應該把它寫到一個(臨時)文件中,這樣你就可以從中得到一個URL

E.g.

<ui:include src="/dynamic.xhtml" /> 

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

} 

(警告:基本開球例如這造成在每次請求一個新的臨時文件,再使用/緩存系統應該對自己的被創造)

它在faces-config.xml中註冊如下

<application> 
    <resource-handler>com.example.DynamicResourceHandler</resource-handler> 
</application> 

注意:以上全部都是針對JSF 2.2的。對於JSF 2.0/2.1用戶陷入這個問題的答案,您應該使用ResourceResolver而不是此答案中的示例:Obtaining Facelets templates/files from an external filesystem or database。重要說明:ResourceResolver在JSF 2.2中爲deprecated,贊成ResourceHandler#createViewResource()

+0

我正在尋找一種方法,我們不必將臨時文件存儲在Web服務器上。有沒有其他的方式直接與內存數據一起工作?也許用自定義jsf組件/標籤等 – user3027786

+0

你可以,你只需要創建一個自定義的'URLStreamHandlerFactory'和'URLStreamHandler'。不能從頭頂舉例,所以沒有答案。 – BalusC

+0

問題:是否有可能在那裏訪問支持bean對象和/或將某些參數傳遞給資源處理程序? – user3027786

0

我對JSF 2.2和定製URLStream在處理器

公共類DatabaseResourceHandlerWrapper解決方案擴展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")); 
     } 
    } 

} 

}