ModelAndView or ResponseEntity return type for controllers? - spring

So far in my experience with Spring I have mainly seen ResponseEntity return types for controllers. However, I have seen ModelAndView return types. Why would someone use ModelAndView over ResponseEntity or vice versa?
In other words, what are the benefits and negatives of either, as I can't really find a comparison of such online?

ResponseEntity is used for RestController, where you want to return a response (200, 400, etc..) with a payload (Json, etc..).
#GetMapping("/hello")
ResponseEntity<String> hello() {
return new ResponseEntity<>("Hello World!", HttpStatus.OK);
}
ModelAndView is used for MVC Controller, where you return the view (HTML, jsp, etc..) templates with data fields set to values you fill the templates with.
Example: an HTML page named employeeDetails with two fields (employeeObj, msg)
ModelAndView model = new ModelAndView("employeeDetails");
model.addObject("employeeObj", new EmployeeBean(123));
model.addObject("msg", "Employee information.");
return model;

Related

How can I return a response Body with Spring Rest MVC when i have also to return a Web page for MVC process?

This is my Code, i know that i should not make 2 return statements, but just for explaining my issue. Thanks
#PostMapping
#ResponseStatus(HttpStatus.Created)
public String addStudent(#RequestBody Student student){
return StudentRep.save(Student);// Should be PayLoad Client Response
return “Student”; // Should be redirect to Student.html
}
You don't need to return a ResponseBody. You can simply add attributes to your Model and then use them in your views.
#PostMapping
#ResponseStatus(HttpStatus.Created)
public String addStudent(#RequestBody Student student, Model model){
String id = StudentRep.save(Student);// Should be PayLoad Client Response
model.addAttribute("studentId", id);
// Will redirect to Student.html where you can use the id attribute.
return “Student”;
}
Now, if you were using Thymeleaf, you could use this new attribute anywhere you want in your template. I am not sure how you are creating your templates, so I just used Thymeleaf as an example.
<p th:text=${id}></p>
Now if you want to return a Stundet object, you would need to the following changes to your controller.
#PostMapping
#ResponseStatus(HttpStatus.Created)
public String addStudent(#RequestBody Student student, Model model){
StudentRep.save(Student);// Should be PayLoad Client Response
model.addAttribute("student", student);
// Will redirect to Student.html where you can use the student attribute.
return “Student”;
}
I think that i find the solution of my answer.
I should annotate the controller that contains my method by #RestController instead of #Controller.
So then, the response will automatically return a JSON HTTP response.

What is the benefit of Model / ModelMap over ModelAndView in Spring MVC?

What is the benefit of Model / ModelMap over ModelAndView in Spring MVC? When we should use Model/ModelMap instead of ModelAndView.
I checked many sites but answers are not clear!
I have read few pages and answers and there doesn't seem to be any differences really. Matter of taste. ModelAndView object wraps model and view. It seems that that is also done implicitly when returning a String. Use the way you prefer.
You can read here about the return types:
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-return-types
Model
Let’s start with the most basic concept here – the Model. Simply put, the model can supply attributes used for rendering views.
To provide a view with usable data, we simply add this data to its Model object. Additionally, maps with attributes can be merged with Model instances:
#GetMapping("/showViewPage")
public String passParametersWithModel(Model model) {
Map<String, String> map = new HashMap<>();
map.put("spring", "mvc");
model.addAttribute("message", "Baeldung");
model.mergeAttributes(map);
return "viewPage";
}
ModelMap
Just like the Model interface above, ModelMap is also used to pass values to render a view. The advantage of ModelMap is it gives us the ability to pass a collection of values and treat these values as if they were on a Map:
#GetMapping("/printViewPage")
public String passParametersWithModelMap(ModelMap map) {
map.addAttribute("welcomeMessage", "welcome");
map.addAttribute("message", "Baeldung");
return "viewPage";
}
ModelAndView
The final interface to pass values to a view is the ModelAndView.
This interface allows us to pass all the information required by Spring MVC in one return:
#GetMapping("/goToViewPage")
public ModelAndView passParametersWithModelAndView() {
ModelAndView modelAndView = new ModelAndView("viewPage");
modelAndView.addObject("message", "Baeldung");
return modelAndView;
}

What is the difference between return ModelAndView and return String in Spring MVC?

I want to know the different between ModelAndView and String.
#RequestMapping(value="/")
public ModelAndView mainPage() {
return new ModelAndView("home");
}
and the second piece of code is about returning String:
#RequestMapping(value="/")
public String mainPage() {
return "home";
}
You can return many things from a controller, and Spring will automatically try to deduce what to do from there.
When you return a ModelAndView all information that needs to be passed from the controller is embedded inside it. No suprise there.
If you return a String, it will assume that this is the name of the view to use. It will wrap this in a ModelAndView object with the string as the view and the existing model embedded as well.
Spring does a lot of 'magic' on the return types, but also on the parameter types.
This allows you to write code in a style that is more intuitive for you, i.e. the following two examples are the same:
#RequestMapping(value="/")
public ModelAndView mainPage() {
Model m = new Model();
m.put("key", "value");
return new ModelAndView(m,"main");
}
and
#RequestMapping(value="/")
public String mainPage(Model m) {
m.put("key", "value");
return "main";
}
This second variant is a little less verbose and easier to test separately. The model passed in will be an empty model (unless forwarded from some other controller).

Spring preprocess request in another controller method

In one of my controllers I have:
#RequestMapping(value = "search", method = RequestMethod.GET)
public ModelAndView searchUsers(HttpSession session, HttpServletRequest request) {
UiUserSearchCriteria userSearchCriteria = (UiUserSearchCriteria) session
.getAttribute("UsersController_userSearchCriteria");
if (null == userSearchCriteria) {
userSearchCriteria= defaultUserSearchCriteria;
}
// Here be dragons
return searchUsers(userSearchCriteria, new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria"), session, request);
}
#RequestMapping(value = "search", method = RequestMethod.POST)
public ModelAndView searchUsers(
#ModelAttribute("userSearchCriteria") UiUserSearchCriteria userSearchCriteria,
BindingResult bindingResult, HttpSession session, HttpServletRequest request) {
userSearchCriteriaValidator.validate(userSearchCriteria, bindingResult);
if (bindingResult.hasErrors()) {
// Here be dragons
return new ModelAndView("searchUsers");
}
ModelAndView result = new ModelAndView("redirect:listUsers");
PagedListHolder<UiUser> userList = new PagedListHolder<UiUser>(
usersService.searchUsers(userSearchCriteria));
userList.setPageSize(10);
userList.setSort(defaultSort);
userList.resort();
session.setAttribute("UsersController_userList", userList);
session.setAttribute("UsersController_userSearchCriteria", userSearchCriteria);
return result;
}
The logic is simple: when the user navigates to search page I actually perform a search with default criteria and return him a list (this is the result of requirements changing, huh).
I found a problem in this code, accidentally. When default search criteria is not valid the behavior is: navigate to search -> populate search criteria with invalid criteria -> call another method (the second one, with POST) -> perform validation -> errors are not empty, so return searchUsers view. But the BindingResult bindingResult is actually syntethic, from previous method (new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")). So I got an error No binding result is bound to session (I agree with this).
I cannot have #ModelAttribute and BindingResult parameters (that, which are bound by Spring) pair in GET method to call POST with them.
So what is the best solutions for this?
I think you can simply associate your new BeanPropertyBindingResult(userSearchCriteria,
"userSearchCriteria") with an appropriate Spring model attribute name, this way:
BindingResult bindingResult = new BeanPropertyBindingResult(userSearchCriteria, "userSearchCriteria")
model.addAttribute(BindingResult.MODEL_KEY_PREFIX + "userSearchCriteria", bindingResult);
This is the default Spring MVC behavior of binding the validation results of a specific model attribute and should help you avoid the No binding result.. error

Spring MVC Controllers Return Type

I've seen examples where a controller returns a String (which indicates the view)
#RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(#PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner"
}
And I also see examples where a controller returns a "ModelAndView" object type
public ModelAndView helloWorld() {
ModelAndView mav = new ModelAndView();
mav.setViewName("helloWorld");
mav.addObject("message", "Hello World!");
return mav;
}
What is the difference between the two and which should I use? Cause either way I can get my view resolved.
It's the same logic but it's not the same version of spring.
The ModelAndView object is the spring 2.x way of handling model and views.
In the example you gave, the modelandview object will load the "helloWorld" view (depending on your templating engine could be helloWorld.jsp, or helloWorld.html, ...) with one data "message" in the model.
The other way is the spring 3.x way. You could have wrote exactly the same example as your helloworld.
#RequestMapping(value="/helloWorld", method=RequestMethod.GET)
public String helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
return "helloWorld";
}
The model is automaticly populated at request.
And we can simplify this notation as the url mapping "helloWorld" is directly the view name.
#RequestMapping(value="/helloWorld", method=RequestMethod.GET)
public void helloWorld(Model model) {
model.addAttribute("message", "Hello World!");
}
the helloWorld view will be automaticly loaded
If we are talking about MVC 3, than, both are correct. But directly returning ModelAndView is the old way, and more verbal.
If you are returning just a string (without #ResponseBody which is something else), this string is treated as view name, and spring pushes it to view resolvers - so, you dont have to worry (at least, while you are writing controllers), what type of view renderer you'll use (let it be jsp or velocity, it doesn't matter). You only propagate the Model instance, and returnes a hint what to do with it next. Proper ModelAndView object is made later internally by string.
Generally, spring 3 gives you more flexibility with arguments and return types (see Defining #RequestMapping handler methods section in Spring documentaton).
In Spring MVC, you should return ModelAndView if you want to render jsp page
For example:
#RequestMapping(value="/index.html", method=RequestMethod.GET)
public ModelAndView indexView(){
ModelAndView mv = new ModelAndView("index");
return mv;
}
this function will return index.jsp when you are hitting /index.html
In addition you can return any JSON or XML object using #ResponseBody annotation and serializer.
For example:
#RequestMapping(value="/getStudent.do",method=RequestMethod.POST)
#ResponseBody
public List<Student> getStudent(#RequestParam("studentId") String id){
List<Student> students = daoService.getStudent(id);
return students;
}
In this example you will return List as JSON in case and you have enabled Jackson serializer. In order to enable that you need to add the following to your Spring XML:
<context:annotation-config/>
And the Serializer itself:
<bean id="jacksonMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jacksonMessageConverter"/>
</list>
</property>
</bean>
Hope it helps.
Returning ModelAndView or a string does the same job. It resolves into a view (a jsp page) and giving a model object to be rendered in the view. If you return a string, spring internally resolves to a view using viewResolver, create a ModelAndView Object and return it. The returning of ModelAndView object is from the older version. You can do either of this based on your convenient.
Have a look at this question
Also bunch of answers are pointing out to #RequestBody. Its not exactly related to your question. But keep in mind that it will convert your object based on content-type using available converters and the resuly will be part of the document body.
If you are using a template language like freemarker or velocity to create the response then you can return the ModelAndView.
If you want to return a json/xml or some string as the response(ex: ajax requests) then you can use the first method. I think it should be public #ResponseBody String findOwner(#PathVariable String ownerId, Model model), you need to add a annotation called #ResponseBody to indicate that the returned value should be converted as the response text. Using #ResponseBody will enable you to use libraries like Jackson or JaxB to create json/xml responses respectively.
These returned values will be converted using the messageConverters registered with AnnotationMethodHandlerAdapter.
Ref: http://blog.springsource.com/2010/01/25/ajax-simplifications-in-spring-3-0/
public String findOwner(#PathVariable String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner"
}
in this method the return type is String and we adding Model as a parameter so to add a value with model we will add like
modelparam.addAttribute("obj",value);
and return to the displayowner to jsp as per view resolver
public ModelAndView helloWorld() {
ModelAndView mav = new ModelAndView();
mav.setViewName("helloWorld");
mav.addObject("message", "Hello World!");
return mav;
}
in this method the return type is ModelAndView so we will return the model
and here the mav is the object of ModelAndView so here we should add like
model.addObject("object","value");
here the viewname is returned to helloworld.jsp as per the viewResolver

Resources