Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access current Model in spring-mvc

Tags:

spring-mvc

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

like image 654
tggm Avatar asked Jul 01 '15 17:07

tggm


People also ask

Why we use ModelAndView in spring?

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 .

What is the use of @ModelAttribute?

@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.

What is model ModelMap and ModelAndView?

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.

What is ModelAndView addObject?

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()


2 Answers

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
}
like image 165
jsc Avatar answered Oct 25 '22 21:10

jsc


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.

like image 21
tggm Avatar answered Oct 25 '22 23:10

tggm