Итогом полученных ограничений, которые получились в итоге стало появление "собственной" системы сообщений. Итак, по-порядку:
1. FlashScope
Сегодняшняя работа будет очень тесна связана в возможностью показать сообщение после редиректа страницы. Поэтому с механизма, который позволит это сделать и начнем.
Метод, позволяющий отображать сообщения (речь идет о FacesMessage) после смены страницы описан тут. Но будем использовать, в некотором смысле, более универсальный механизм, который позволит передавать параметры между запросами и не занимать sessionScope или applicationScope - это FlashScope. Я использую немного не эту реализацию, а реализацию от Jesse Gallagher. Еще нужно в faces-config.xml прописать:
1 | < 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>
и
1 | < lifecycle > |
<phase-listener>frostillicus.FlashScopePhaseListener</phase-listener>
</lifecycle>
А так же иметь метод по получению flashScope, например:
1 | @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. Добавляем класс под свои уведомления:
1 | 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 вспомогательным метода для очистки стека сообщений.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | @SuppressWarnings ( "unchecked" ) public static void postMessage( final Message.MessageType messageType, final String summary, final String detail) {<span class = "Apple-tab-span" style= "white-space: pre;" > </span> <span class = "Apple-tab-span" style= "white-space: pre;" > </span>Message message = new Message(summary, detail); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>String channelName = messageType.getTypeName().toLowerCase(); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>Map<Object, Object> flashScope = getFlashScope(); <span class = "Apple-tab-span" style= "white-space: pre;" > </span> <span class = "Apple-tab-span" style= "white-space: pre;" > </span>List<Object> messages = (List<Object>) flashScope.get(channelName + "Messages" ); <span class = "Apple-tab-span" style= "white-space: pre;" > </span> if (messages == null ) { <span class = "Apple-tab-span" style= "white-space: pre;" > </span>messages = new ArrayList<Object>(); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>flashScope.put(channelName + "Messages" , messages); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>} <span class = "Apple-tab-span" style= "white-space: pre;" > </span>messages.add(message); } public static void clearMessages( final MessageType messageType) { <span class = "Apple-tab-span" style= "white-space: pre;" > </span>Map<Object, Object> flashScope = getFlashScope(); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>String channelName = messageType.getTypeName().toLowerCase(); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>flashScope.put(channelName + "Messages" , null );<span class = "Apple-tab-span" style= "white-space: pre;" > </span> } public static void clearMessages() { <span class = "Apple-tab-span" style= "white-space: pre;" > </span> for (MessageType type : Message.messagesTypes) { <span class = "Apple-tab-span" style= "white-space: pre;" > </span>clearMessages(type); <span class = "Apple-tab-span" style= "white-space: pre;" > </span>} } |
4. CustomControl для отображения сообщений
Основной:
1 | < 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 для отображения индивидуального сообщения:
1 | < 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-по-русски
Комментарии
Отправить комментарий