Ответ 1
К сожалению, это невозможно в стандартной реализации JSF. Компонент и рендеринг официально не поддерживают этот атрибут. Однако вы можете провести рендеринг рендерера, который обрабатывает это.
Поскольку это довольно распространенное требование/пожелание, я подумал, что все возможно.
Вначале некоторая справочная информация: JSF по умолчанию использует ResponseWriter#writeText()
, чтобы написать тело тега, которое по умолчанию экранирует HTML. Мы хотели бы позволить ему использовать ResponseWriter#write()
, как и в случае с <h:outputText escape="false" />
. Мы хотели бы расширить MessagesRenderer
стандартной реализации JSF и соответственно переопределить метод encodeEnd()
. Но так как MessagesRenderer#encodeEnd()
содержит довольно много кода (~ 180 строк), который мы предпочитаем не копировать, а просто меняем одну или две строки, мне было лучше заменить ResponseWriter
на пользовательскую реализацию с помощью ResponseWriterWrapper
, в котором writeText()
был переопределен для обработки экранирования.
Итак, я закончил с этим:
package com.example;
import java.io.IOException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.context.ResponseWriterWrapper;
import javax.faces.render.FacesRenderer;
import com.sun.faces.renderkit.html_basic.MessagesRenderer;
@FacesRenderer(componentFamily="javax.faces.Messages", rendererType="javax.faces.Messages")
public class EscapableMessagesRenderer extends MessagesRenderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
final ResponseWriter originalResponseWriter = context.getResponseWriter();
try {
context.setResponseWriter(new ResponseWriterWrapper() {
@Override
public ResponseWriter getWrapped() {
return originalResponseWriter;
}
@Override
public void writeText(Object text, UIComponent component, String property) throws IOException {
String string = String.valueOf(text);
String escape = (String) component.getAttributes().get("escape");
if (escape != null && !Boolean.valueOf(escape)) {
super.write(string);
} else {
super.writeText(string, component, property);
}
}
});
super.encodeEnd(context, component); // Now, render it!
} finally {
context.setResponseWriter(originalResponseWriter); // Restore original writer.
}
}
}
Несмотря на аннотацию @FacesRenderer
, она перестает использоваться по умолчанию MessagesRenderer
. Я подозреваю, что здесь ошибка, поэтому я сообщил вопрос 1748. Чтобы заставить его работать в любом случае, мы должны вернуться к faces-config.xml
:
<render-kit>
<renderer>
<component-family>javax.faces.Messages</component-family>
<renderer-type>javax.faces.Messages</renderer-type>
<renderer-class>com.example.EscapableMessagesRenderer</renderer-class>
</renderer>
</render-kit>
Затем, чтобы вызвать его, просто выполните:
<h:messages escape="false" />
И это работает!:)
Примечание: приведенное выше относится только к <h:messages>
. Чтобы сделать то же самое для <h:message>
, просто сделайте то же самое, но замените где-нибудь "Messages"
на "Message"
(семейство компонентов, тип визуализатора и классные имена).