Spring: @ModelAttribute VS @RequestBody

SpringSpring MvcData Binding

Spring Problem Overview


Please correct me if I am wrong. Both can be used for Data Binding.

The question is when to use @ModelAttribute?

@RequestMapping(value="/owners/{ownerId}/pets/{petId}/edit", method = RequestMethod.POST)
public String processSubmit(@ModelAttribute Pet pet) { }

In addition, when to use @RequestBody?

@RequestMapping(value = "/user/savecontact", method = RequestMethod.POST
public String saveContact(@RequestBody Contact contact){ }

According to my understanding both serves the similar purpose.

Thanks!!

Spring Solutions


Solution 1 - Spring

The simplest way for my understanding is, the @ModelAttribute will take a query string. so, all the data are being pass to the server through the url.

As for @RequestBody, all the data will be pass to the server through a full JSON body.

Solution 2 - Spring

@ModelAttribute is used for binding data from request param (in key value pairs),

but @RequestBody is used for binding data from whole body of the request like POST,PUT.. request types which contains other format like json, xml.

Solution 3 - Spring

If you want to do file upload, you have to use @ModelAttribute. With @RequestBody, it's not possible. Sample code

@RestController
@RequestMapping(ProductController.BASE_URL)
public class ProductController {

    public static final String BASE_URL = "/api/v1/products";

    private ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public ProductDTO createProduct(@Valid @ModelAttribute ProductInput productInput) {
        return productService.createProduct(productInput);
    }

}

ProductInput class

@Data
public class ProductInput {

    @NotEmpty(message = "Please provide a name")
    @Size(min = 2, max = 250, message = "Product name should be minimum 2 character and maximum 250 character")
    private String name;

    @NotEmpty(message = "Please provide a product description")
    @Size(min = 2, max = 5000, message = "Product description should be minimum 2 character and maximum 5000 character")
    private String details;

    @Min(value = 0, message = "Price should not be negative")
    private float price;

    @Size(min = 1, max = 10, message = "Product should have minimum 1 image and maximum 10 images")
    private Set<MultipartFile> images;
}

Solution 4 - Spring

I find that @RequestBody (also annotating a class as @RestController) is better for AJAX requests where you have complete control over the contents of the request being issued and the contents are sent as either XML or JSON (because of Jackson). This allows the contents to easily create a model object. Conversely, @ModelAttribute seems to be better suited to forms where there is a "command" object backing a form (which may not necessarily be a model object).

Solution 5 - Spring

You can directly access your "pet" object in view layer, if you use ModelAttribute annotation. Also, you can instantiate this object in a method on your controller to put your model. see this.

ModelAttribute gives you a chance to use this object partial, but with RequestBody, you get all body of request.

Solution 6 - Spring

I think @ModelAttribute and @RequestBody both are having same use, only difference is @ModelAttribute use for normal spring MVC and @RequestBody use for REST web service. It is @PathVariable and @PathParam. But in in both the cases we can mix it. we can use @PathVariable in REST and vice versa.

Solution 7 - Spring

We need to have the following jsp tag to data bind your entity to the jsp form fields:
The form is from the spring tag library:
The following is the not the full html, but I hope you can relate your self:

<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

		<form:form action="save" method="post" modelAttribute="patient">
			<table>
				<tr>
					<td>Name</td>
					<td>
						<form:input path="patient.patient_name"  /> <br />
						
					</td>
				</tr>
				<tr>
					<td>Phone</td>
					<td>
						<form:input path="patient.phone_number" /> <br />
					</td>
				</tr>
				<tr>
					<td colspan="2"><button type="submit">Submit</button></td>
				</tr>
			</table>
		</form:form>

The form has to be processed twice , once before rendering the form, during which we need to give the appropriate bean instantiation for the property value modelAttribute="patient".

  1. For this the controller class(at the class defintion level) you need to have @RequestMapping annotation.
  2. You need to have the handler method parameters as follows
@GetMapping("logincreate")

public String handleLoginCreate(@ModelAttribute("login") Login login, Model model)
{
    System.out.println(" Inside handleLoginCreate  ");
    model.addAttribute("login",login);
	return "logincreate";
}

Spring will scan all handler methods @ModelAttribute and instantiate it with default constructor of Login class, and call all of its getters and setters (for the jsp binding from form to the "login"). In case of missing any of the following the jsp will not be shown, various exceptions are thrown

  1. getters/setters
  2. default constructor
  3. model.addAttribute("login",login);
  4. class level @RequestMapping
  5. method parameter level @ModelAttribute

Also, the handler method of action in the jsp, the in the above form action="save", also the handler method might look like this:

@PostMapping("save")

public String saveLoginDetails(@ModelAttribute("login") Login login, Model model) {
	
	//write codee to insert record into DB
	System.out.println(" Inside save login details  ");
	System.out.println("The login object is " + login.toString());
	System.out.println("The model object contains the login attribute"+ model.getAttribute("login"));	
	loginService.saveLogin(login);
	return "welcome";
}

Important learning is:

  1. Before form is launched, spring should have appropriate annotation to indicate the backing bean of the form, in the above example the "backing bean" or "binding object" is Login login with appropriate handler method's parameter annotation @ModelAttribute("login") Login login

Solution 8 - Spring

With @ModelAttribute, you pass data in URL params and with @RequestBody you pass it as JSON body. If you're making a REST API then it's better to use @RequestBody. Over most youtube tutorials you might find use of @ModelAttribute - That's simply because they might be demonstrating concepts regarding Spring MVC and are using URL's to pass data.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTouchstoneView Question on Stackoverflow
Solution 1 - SpringCharlesCView Answer on Stackoverflow
Solution 2 - SpringNaveen rajView Answer on Stackoverflow
Solution 3 - SpringA M S RejuanView Answer on Stackoverflow
Solution 4 - SpringkondrakView Answer on Stackoverflow
Solution 5 - SpringokoView Answer on Stackoverflow
Solution 6 - Springshubham bellaleView Answer on Stackoverflow
Solution 7 - SpringfullstackdeveloperView Answer on Stackoverflow
Solution 8 - SpringVaibhav PratiharView Answer on Stackoverflow