I'm learning Spring-MVC 4 comming from asp.net MVC and I was looking for a way to pass data to the View without having to declare a Model Atrribute in every call.
For example, now I have this.
public class BaseController {
public void AddMessage(Model model, String m) {
Model.addAttribute("msg", m);
}
}
public class PersonController extends BaseController{
@RequestMapping("details/{Id}")
public String details(@PathVariable int Id, Model model) {
Person p = service.LoadById(Id);
if(p == null) {
AddMessage(model, "Record not found...");
} else {
model.addAttribute("bean", q);
}
return "person/details";
}
}
But what I would really like is to have a way to acess that Model instance in my base controller methods without having to pass it on as an argument. Similar to the usage of ViewData or TempData in asp.net MVC.
Is it possible to pass data to the view in this fashion?
Thank you
ModelAndView is a holder for both Model and View in the web MVC framework. These two classes are distinct; ModelAndView merely holds both to make it possible for a controller to return both model and view in a single return value. The view is resolved by a ViewResolver object; the model is data stored in a Map .
@ModelAttribute is an annotation that binds a method parameter or method return value to a named model attribute, and then exposes it to a web view. In this tutorial, we'll demonstrate the usability and functionality of this annotation through a common concept, a form submitted from a company's employee.
ModelMap is an extension of Model with the ability to store attributes in a map and chain method calls. ModelAndView is a holder for a model and a view; it allows to return both model and view in one return value.
public ModelAndView addObject(Object attributeValue) Add an attribute to the model using parameter name generation. Parameters: attributeValue - the object to add to the model (never null ) See Also: ModelMap.addAttribute(Object) , getModelMap()
If you want to avoid passing the Model as a method parameter, you can use ModelAttribute annotation in a method: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ModelAttribute.html
Just annotate the method and Spring will automatically add what the method returns to the model.
@ModelAttribute
public Stuff addStuffToModel() {
Stuff stuff = new Stuff("dummy data");
return stuff; // stuff is added to the model
}
I managed to work around this issue using a request interceptor. Essentially:
On my base controller class:
public abstract class BaseController {
protected List<UserViewMessage> viewMessages;
public List<UserViewMessage> getViewMessages() {
if (viewMessages == null) {
viewMessages = new ArrayList<UserViewMessage>();
}
return viewMessages;
}
public void addMessage(String message, UserViewMessageType type) {
getViewMessages().add(new UserViewMessage(message, type));
}
public void clearMessages() {
if (viewMessages != null) {
viewMessages.clear();
}
}
}
Then, I added an interceptor to copy the messages collection to the Model:
public class RequestInterceptor extends HandlerInterceptorAdapter {
private static String MODEL_MESSAGES_KEY = "ModelMessageList_";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
if (handler instanceof org.springframework.web.method.HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod != null) {
Object bean = handlerMethod.getBean();
if (bean != null && bean instanceof BaseController) {
BaseController bc = (BaseController) bean;
bc.clearMessages();
}
}
}
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
if (handler instanceof org.springframework.web.method.HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod != null && modelAndView != null) {
Object bean = handlerMethod.getBean();
if (bean != null && bean instanceof BaseController) {
BaseController bc = (BaseController) bean;
if (bc.getViewMessages() != null) {
modelAndView.addObject(MODEL_MESSAGES_KEY, bc.getViewMessages());
}
}
}
}
super.postHandle(request, response, handler, modelAndView);
}
}
Which, on PreHandle, clears any messages on the base controller collection. After the request (PostHandle) and since the Model is available, I copy the message collection to the Model, thus making it available on my views like so:
<div class="row">
<div class="col-lg-12">
<c:forEach var="messageItem" items="${_ModelMessageList_}">
<div class="alert alert-info"><c:out value="${messageItem.message}" /></div>
</c:forEach>
</div>
</div>
It's not optimal, but it works.
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