JSF:从自定义组件访问组件主体的文本

时间:2014-01-15 22:53:07

标签: java jsf-2 facelets custom-component

假设我有一个带有静态方法Formatter的Java类format,它可以进行一些简单的文本处理。我想编写一个组件,将组件中的文本传递给Formatter#format方法,如下所示:

<test:format>
  Hello, #{user.name}!
</test:format>

为了论证,假设Formatter看起来像这样(实际上它是Markdown库):

public class Formatter {
  public static format(String s) { return s.toUpperCase(); }
}

我希望上面标记的渲染结果为HELLO, DANIEL!

这可行吗?我需要做些什么来获取组件下的渲染文本内容才能像这样处理?

1 个答案:

答案 0 :(得分:0)

我已经找到了一种方法来做到这一点,但我怀疑这是一个很好的方法。代码:

@FacesComponent("MyComponent")
public class MyComponent 
    extends UIComponentBase 
    implements NamingContainer {

  @Override public String getFamily() { 
    return UINamingContainer.COMPONENT_FAMILY; 
  }

  @Override public boolean getRendersChildren() { return true; }

  @Override public void encodeChildren(FacesContext fc) throws IOException {
    StringWriter writer = new StringWriter();
    ResponseWriter rw = fc.getResponseWriter();

    // create the response writer
    ResponseWriter replacement = rw.cloneWithWriter(writer);

    // this tag wrapping step is necessary for the MyFaces ResponseWriter to 
    // work correctly
    replacement.startDocument();
    replacement.startElement("div", this);

    // mask the response writer temporarily    
    fc.setResponseWriter(replacement);

    // perform the render to get the text in our string
    super.encodeChildren(fc);

    // unmask the response writer
    fc.setResponseWriter(rw);

    // finish the wrapping calls
    replacement.endElement("div");
    replacement.endDocument();

    // this strips the rendered <div> tag wrapper from the generated text.
    final String renderedText = writer.toString()
            .substring(5, writer.toString().length()-6);

    // process the text and send it out
    rw.append(Formatter.format(renderedText));
  }
}

这一切都取决于ResponseWriter#cloneWithWriter方法。但是,如果你只是在那里拍一个StringWriter并期望它去,MyFaces会爆炸 - 你需要至少创建一个包装标签来为要呈现的文本创建一个安全的上下文。我的格式化程序不期望包装元素,所以我之后使用粗略的子字符串删除它。除此之外,实施getRendersChildren似乎足以实现这一目标。然后,您可以使用taglib.xml将其连接起来。