Итогом полученных ограничений, которые получились в итоге стало появление "собственной" системы сообщений. Итак, по-порядку:
1. FlashScope
Сегодняшняя работа будет очень тесна связана в возможностью показать сообщение после редиректа страницы. Поэтому с механизма, который позволит это сделать и начнем.
Метод, позволяющий отображать сообщения (речь идет о FacesMessage) после смены страницы описан тут. Но будем использовать, в некотором смысле, более универсальный механизм, который позволит передавать параметры между запросами и не занимать sessionScope или applicationScope - это FlashScope. Я использую немного не эту реализацию, а реализацию от Jesse Gallagher. Еще нужно в faces-config.xml прописать:
<managed-bean>
<managed-bean-name>flashScope</managed-bean-name>
<managed-bean-class>java.util.HashMap</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
и
<lifecycle>
<phase-listener>frostillicus.FlashScopePhaseListener</phase-listener>
</lifecycle>
А так же иметь метод по получению flashScope, например:
@SuppressWarnings("unchecked")
public static Map<Object, Object> getFlashScope() {
return (Map<Object, Object>)resolveVariable("flashScope");
}
public static Object resolveVariable(final String varName) {
FacesContext context = FacesContext.getCurrentInstance();
return context.getApplication().getVariableResolver().resolveVariable(context, varName);
}
2. Добавляем класс под свои уведомления:
import java.io.Serializable;
import javax.faces.application.FacesMessage;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
private static final String TYPE_INFO_NAME = "INFO";
public static final MessageType TYPE_INFO = new MessageType(TYPE_INFO_NAME);
private static final String TYPE_WARNING_NAME = "WARNING";
public static final MessageType TYPE_WARNING = new MessageType(TYPE_WARNING_NAME);
private static final String TYPE_SUCCESS_NAME = "SUCCESS";
public static final MessageType TYPE_SUCCESS = new MessageType(TYPE_SUCCESS_NAME);
private static final String TYPE_ERROR_NAME = "ERROR";
public static final MessageType TYPE_ERROR = new MessageType(TYPE_ERROR_NAME);
private static final String TYPE_FATAL_NAME = "FATAL";
public static final MessageType TYPE_FATAL = new MessageType(TYPE_FATAL_NAME);
public static final MessageType[] messagesTypes = {TYPE_FATAL, TYPE_ERROR, TYPE_WARNING, TYPE_SUCCESS, TYPE_INFO};
private String summary;
private String detail;
public Message(final String summary, final String detail) {
this.summary = summary;
this.detail = detail;
}
public String getSummary() {
return summary;
}
public String getDetail() {
return detail;
}
public static class MessageType {
String typeName;
protected MessageType(final String typeName) {
this.typeName = typeName;
}
public String getTypeName() {
return typeName;
}
}
}
3. Учим MessageBean отправлять "наши" уведомления:
- для каждого типа сообщения будет свой канал, например infoMessages
- канал это просто список (List) сообщений, который лежит вo flashScope (а это Map) с ключом, соответствующем названию канала
- flashScope очищается после, условно говоря, смены страницы, поэтому, если через него отображать сообщения в рамках одной страницы - они будут накапливаться. Иногда это может быть нужно, мне кажется, а иногда нет. И
- для того, чтобы наши уведомления отправлялись единообразно как в рамках одной страницы, так и при ее смене, добавим 2 вспомогательным метода для очистки стека сообщений.
@SuppressWarnings("unchecked") public static void postMessage(final Message.MessageType messageType, final String summary, final String detail) { Message message = new Message(summary, detail); String channelName = messageType.getTypeName().toLowerCase(); Map<Object, Object> flashScope = getFlashScope(); List<Object> messages = (List<Object>) flashScope.get(channelName + "Messages"); if (messages == null) { messages = new ArrayList<Object>(); flashScope.put(channelName + "Messages", messages); } messages.add(message); } public static void clearMessages(final MessageType messageType) { Map<Object, Object> flashScope = getFlashScope(); String channelName = messageType.getTypeName().toLowerCase(); flashScope.put(channelName + "Messages", null); } public static void clearMessages() { for (MessageType type : Message.messagesTypes) { clearMessages(type); } }
4. CustomControl для отображения сообщений
Основной:
<xp:div id="msgDisplay">
<xp:div rendered="#{javascript:flashScope.fatalMessages != null}">
<xp:repeat id="repeat2" rows="30" var="message"
disableOutputTag="true" value="#{flashScope.fatalMessages}">
<xc:cc_Core_MessageEntry messageStyleClass="alert-danger"></xc:cc_Core_MessageEntry>
</xp:repeat>
</xp:div>
<xp:div rendered="#{javascript:flashScope.errorMessages != null}">
<xp:repeat id="repeat1" rows="30" var="message"
disableOutputTag="true" value="#{flashScope.errorMessages}">
<xc:cc_Core_MessageEntry messageStyleClass="alert-danger"></xc:cc_Core_MessageEntry>
</xp:repeat>
</xp:div>
<xp:div rendered="#{javascript:flashScope.warningMessages != null}">
<xp:repeat id="repeat3" rows="30" var="message"
disableOutputTag="true" value="#{flashScope.warningMessages}">
<xc:cc_Core_MessageEntry messageStyleClass="alert-warning"></xc:cc_Core_MessageEntry>
</xp:repeat>
</xp:div>
<xp:div rendered="#{javascript:flashScope.successMessages != null}">
<xp:repeat id="repeat4" rows="30" var="message"
disableOutputTag="true" value="#{flashScope.successMessages}">
<xc:cc_Core_MessageEntry messageStyleClass="alert-success"></xc:cc_Core_MessageEntry>
</xp:repeat>
</xp:div>
<xp:div rendered="#{javascript:flashScope.infoMessages != null}">
<xp:repeat id="repeat5" rows="30" var="message"
disableOutputTag="true" value="#{flashScope.infoMessages}">
<xc:cc_Core_MessageEntry></xc:cc_Core_MessageEntry>
</xp:repeat>
</xp:div>
</xp:div>
cc_Core_MessageEntry для отображения индивидуального сообщения:
<div class="alert fade in #{compositeData.messageStyleClass}">
<a class="close" data-dismiss="alert" href="#">×</a>
<xp:text escape="false" id="computedField1"
value="#{message.summary}" style="font-weight:bold"
rendered="#{not empty message.summary}">
</xp:text>
<xp:br></xp:br>
<xp:text escape="false" id="computedField2"
value="#{message.detail}" rendered="#{not empty message.detail}">
</xp:text>
<br />
</div>
Для этого Custom Control добавлено строковое свойство messageStyleClass. Оно не обязательно
Итоговый результат можно пощупать и рассмотреть в Demo-приложении.
Если вам понравился пост, жмите +1, делитесь в соц. сетях и форумах! #xPages-по-русски
Комментарии
Отправить комментарий