简体   繁体   中英

Can i return two models in ModelAndView in Spring MVC

Suppose i have following code if i have one model

MyBean bean = new MyBean();
bean.setName("Mike");
bean.setMessage("Meow!");

return new ModelAndView("welcomePage","model",bean);

But if i have two or three models like

Suppose on my one view i want the model with userdetails , shoppingcart details and history details

how can i use ModelAnd View to return 2-3 models

You can accomplish this a number of ways, but perhaps the easiest way would be to use a map

Map<String, Object> model = new HashMap<String, Object>();
model.put("bean", bean);
model.put("userdetails", userdetails);
//and so on
return new ModelAndView("welcomePage", "model", model);

Then, in your page, you just have to add an extra level when you access it

User's name is ${ model.userdetails.username }

alternatively, you could also change your handler signature to be something like this

public String handleRequest(Model model){
   //arbitrary handling code
   model.addAttribute("bean", bean);
   model.addAttribute("userdetails", userdetails);
   //etc
   return "welcomePage";
 }

When you do it like this, you don't actually have to return the model because Spring holds on to the reference before you receive it and can then access it afterwards. I personally find this method a little better because it makes unit testing easier. All you have to do is check the string return value and use a Spring mock model (or your own mock object that implements the Model interface).

Edit To address the comments:

This source gives some examples and discusses some of the various supported method signatures. Specifically, check out section 15.3.2.3 for a discussion of the parameters that can be passed to handler methods.

Basically, Spring uses the @RequestMapping annotations to determine which methods should be called based on a given request. Spring is then able to examine the method signature and generate the appropriate parameters before calling the method. In the case where you return a ModelAndView object, the Model is created when the constructor is called based on the parameters you provide. If you don't provide any model objects, then an empty model is created. However, when you specify that you should receive the model as a parameter to your handler method, Spring creates an instance of a Model object for you and passes it to your method. Spring holds on to a reference to that model and, when your method returns, passes that model along to the web view (for example a JSP parser).

It really is effectively the same as returning a ModelAndView object except it makes unit testing a lot easier and frankly, IMO makes for a cleaner and more elegant implementation.

Note: Keep in mind that a Model is really just a special Map object (hence why Spring supports using a Model or Map interchangeably in the method signatures). There are a few additional methods and it also supports implicit attribute naming. For instance, if you were to simply pass an object without giving it a name, the Model object will figure out what to name the object based on object type, etc. However, if you always provide a "key" for the object you add to the model, it behaves exactly the same as a Map .

Yes, you can return arbitrary number of model attributes by placing them into Map :

Map<String, Object> model = new HashMap<String, Object>();
model.put("model", bean);
model.put("userdetails", ...);
model.put("shoppingcart", ...);
return new ModelAndView("welcomePage", model);

Note the terminology - model is a map, it consists of model attributes (individual objects), new ModelAndView("welcomePage","model",bean) is a convenience constructor for creating a model with a single attribute.

There are good examples given. Just to add to the mix, I'm really becoming a fan of the annotations based methodology of doing this. I like it because it provides a very clean way of implementing. Here is an example...

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
@Scope("prototype")
@RequestMapping("/testing")
public class TestController {

    @Autowired
    TestFactory factory;

    @RequestMapping(value = "/test1", method = RequestMethod.POST)
    public void test1(String something, String something2, Model model) {
        List<Map<String, String>> results = 
             factory.getSomethingCool(something1, something2);

        model.addAttribute("something1", something1);
        model.addAttribute("something2", something2);
        model.addAttribute("results", results);
    }

    @RequestMapping(value = "/test2", method = RequestMethod.POST)
    public void test1(String something1, String something2, Model model) {
        List<String> results = 
            factory.getSomethingElseCool(something1, something2);

        model.addAttribute("something1", something1);
        model.addAttribute("something2", something2);
        model.addAttribute("results", results);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM