Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display info messages in jsp for Spring WebFlow 2.0

I have a model with a list of selected topics. Every topic can be presented in a room and there are more rooms that need to be chosen depending of availability. The user can set preferred room for presenting. If it is unavailable, but some other is available, at selected time there should be an info message that the room is changed. Something like the:

<form:errors path="selectedTopics[${loop.index}].room" />

loop is a varStatus attribute in c:foreach tag
I add the messages to the messageContext like this:

MessageContext messages = context.getMessageContext();
String source= "selectedTopics[" + i + "].room";
messages.addMessage(new MessageBuilder().info()
          .source(source)
          .code("topic.room.changed")
          .build());

The error tag works if I add them as errors, but they are not errors. Is there any way that I can display those info messages in an elegant way like the errors?

like image 422
vl4d1m1r4 Avatar asked Dec 14 '11 13:12

vl4d1m1r4


1 Answers

From the DefaultMessageContext I saw that there is a getter for all messages which gives an array of the messages in the message context and than by looping over the array I can find the messages for the field that is currently rendering:

<c:forEach var="topic" items="${model.selectedTopics}" varStatus="loop">
    //omitted displaying of topic details
  <c:forEach items="${flowRequestContext.messageContext.allMessages}" var="message">
    <c:set var="msgSrc" value="selectedTopics[${loop.index}].room"></c:set>
    <c:if test="${message.source eq msgSrc}">
        <c:if test="${message.severity eq 'INFO'}">
            <span class="infoText">${message.text}</span>
        </c:if>
     </c:if>
  </c:forEach>
</c:forEach>

But this way the iteration over all messages is done for every field that has to be renderd and if you have a lot of fields, this may be slow.

Another way that this can be achieved is to get the map of messages that is in the message context. Here is a sample of the context outputed in jsp, I used ${flowRequestContext.messageContext}:

[DefaultMessageContext@2de69e99 sourceMessages = map[[null] -> list[[empty]], 'selectedTopics[2].room' -> list[[Message@12329bcb source = 'selectedTopics[2].room', severity = INFO, text = 'Room changed from ALU1-M1 to ALU1-M2']], 'selectedTopics[4].room' -> list[[Message@87abf31 source = 'selectedTopics[4].room', severity = INFO, text = 'Room changed from ALU1-M1 to ALU2-M1']]]] 

There is a map sourceMessages that holds all messages for a field that can be retrieved with the source as a key. But the problem is that there is no getter for the map in the implementation org.springframework.binding.message.DefaultMessageContext. However, there is a method getMessagesBySource(java.lang.Object source) that gives an array of messages for the specified source. So we can use that in the EL expression.

IMPORTANT! Passing method arguments in EL is only by EL spec supported in EL 2.2. EL 2.2 is by default shipped in Servlet 3.0 / JSP 2.2 containers. See JSTL or JSP 2.0 EL for getter with argument

So now the info can be displayed with:

<c:forEach var="message" items="${flowRequestContext.messageContext.getMessagesBySource(msgSrc)}">
    <c:if test="${message.severity eq 'INFO'}">
        <span class="info">${message.text}</span></td>
    </c:if>
</c:forEach>

If you need to use previous version than Servlet 3.0 / JSP 2.2 containers than I think the best way is to reconstruct the sourceMessages map and insert it in flashScope before rendering the view.

like image 178
vl4d1m1r4 Avatar answered Nov 01 '22 06:11

vl4d1m1r4