What is the best way to organize status messages ("Your data has been successfully saved/added/deleted") on the Spring MVC-based site using annotation controller?
So, the issue is in the way of sending the message from POST-method in contoller.
As mentioned by muanis, since spring 3.1, the best approach would be to use RedirectAttributes. I added i18n to the sample given in the blog. So this would be a complete sample.
@RequestMapping("/users")
@Controller
public class UsersController {
@Autowired
private MessageSource messageSource;
@RequestMapping(method = RequestMethod.POST, produces = "text/html")
public String create(@Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest, Locale locale, RedirectAttributes redirectAttributes) {
...
...
redirectAttributes.addFlashAttribute("SUCCESS_MESSAGE", messageSource.getMessage("label_user_saved_successfully", new String[] {user.getUserId()}, locale));
return "redirect:/users/" + encodeUrlPathSegment("" + user.getId(), httpServletRequest);
}
...
...
}
Add appropriate message in your message bundle, say messages.properties.
label_user_saved_successfully=Successfully saved user: {0}
Edit your jspx file to use the relevant attribute
<c:if test="${SUCCESS_MESSAGE != null}">
<div id="status_message">${SUCCESS_MESSAGE}</div>
</c:if>
A proven approach is to use a special flash scope for messages that should be retained until the next GET request.
I like to use a session scoped flash object:
public interface Flash {
void info(String message, Serializable... arguments);
void error(String message, Serializable... arguments);
Map<String, MessageSourceResolvable> getMessages();
void reset();
}
@Component("flash")
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public class FlashImpl implements Flash {
...
}
A special MVC interceptor will read the flash values from the flash object and place them in the request scope:
public class FlashInterceptor implements WebRequestInterceptor {
@Autowired
private Flash flash;
@Override
public void preHandle(WebRequest request) {
final Map<String, ?> messages = flash.getMessages();
request.setAttribute("flash", messages, RequestAttributes.SCOPE_REQUEST);
for (Map.Entry<String, ?> entry : messages.entrySet()) {
final String key = "flash" + entry.getKey();
request.setAttribute(key, entry.getValue(), RequestAttributes.SCOPE_REQUEST);
}
flash.reset();
}
...
}
Now in your controller you can simply place messages in "flash scope":
@Conteroller
public class ... {
@Autowired
private Flash flash;
@RequestMapping(...)
public void doSomething(...) {
// do some stuff...
flash.info("your.message.key", arg0, arg1, ...);
}
}
In your view you iterate over the flash messages:
<c:forEach var="entry" items="${flash}">
<div class="flash" id="flash-${entry.key}">
<spring:message message="${entry.value}" />
</div>
</c:forEach>
I hope this helps you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With