64
votes

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!!

7

7 Answers

40
votes

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.

16
votes

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

9
votes

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;
}
6
votes

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

5
votes

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.

2
votes

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.

0
votes

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.