Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Status messages on the Spring MVC-based site (annotation controller)

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.

like image 867
olegflo Avatar asked Sep 10 '25 20:09

olegflo


2 Answers

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> 
like image 73
krishnakumarp Avatar answered Sep 12 '25 09:09

krishnakumarp


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.

like image 25
Philipp Jardas Avatar answered Sep 12 '25 10:09

Philipp Jardas