Способы включения динамически генерируемого лица - PullRequest
1 голос
/ 10 сентября 2010

В текущем проекте мне нужно создать панель, которая будет содержать контент 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}"/>

Это уже фрагмент фейслета, который не может быть обработан и обработан в h: outputText .

Я искал хороший способ включить этот вид динамического контента в лицевую сторону на этапе, когда выражения EL еще не оценены. Что-то вроде

<ui:include src="src"/>

но для динамических компонентов будет лучшим решением.

Есть идеи?

Ответы [ 4 ]

3 голосов
/ 14 сентября 2010

Я согласен с 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>

Этот файл просто должен присутствовать в classpath вашего приложения, и он будет автоматически загружаться 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"/>
    ...
<Ч />

Две ссылки, которые могут помочь вам в дополнение к тем, которые предоставлены пользователем423943:

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 голос
/ 01 августа 2013

Вы можете использовать includeFacelet(UIComponent, URL) также для включения динамически генерируемых граней.Хитрость заключается в использовании data схемы URL и пользовательской URLStreamHandler:

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

Если у вас есть универсальный обработчик для data:// URL, это лучший вариант для использования.Мне нужен обработчик только для этого конкретного случая использования, поэтому он довольно ограничен:

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);
  }
}
1 голос
/ 10 сентября 2010

Что делает этот комплекс, я думаю, это то, что #{myBean.dynamicHTMLContent} не совсем HTML-контент, а JSF-контент. Я думаю, что наиболее гибким решением было бы написать свой собственный компонент JSF. Возможно, кто-то исправит меня, но я не думаю, что есть способ заменить текст, такой как {niceImage} JSF-код.

Есть несколько статей по этому поводу:

Я не эксперт по JSF, но вы могли бы:

Надеюсь, это поможет!

0 голосов
/ 14 сентября 2010

В конце концов я выбрал простой путь, заменив все пользовательские (фигурные скобки) токены в пользовательском HTML соответствующими элементами JSF и сгенерировав временный ui:composition файл лицевой стороны:

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}"/>
...