Spring: @ModelAttribute VS @RequestBody
Asked Answered
S

10

85

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

Semifinal answered 17/2, 2014 at 8:24 Comment(0)
T
60

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.

Tubercle answered 13/8, 2015 at 13:50 Comment(3)
simply put @RequestBody specifies the body of the request . @ResponseBody specifies the body of the Response. @ModelAttribute and @RequestParam are for decoding Queryparameters from URL . the only difference is @modelAttribute will bind all the fields and give a full object . but if you use @RequestParam you have build the entire object by mapping all the fields manually . for more info see hereGreggs
ModelAttribute and RequestParam are for decoding Queryparameters from URL - then what are Get and Post HTTP methods for ? With Post , your parameters are not sent in URLAgripina
@Tubercle - So ModelAttribute will pick data from Request body (with POST method) in form a string of key value pair and RequestBody will pick data in JSON format ?Agripina
R
24

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

Regazzi answered 9/7, 2015 at 11:5 Comment(1)
JSON is also key value only , how is the JSON data different from request param?Agripina
C
16

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;
}
Cheder answered 24/5, 2019 at 16:57 Comment(3)
I confirm that tooMetempsychosis
Can you elaborate on how the request call should be look like? I'm sending a req with image, but I'm getting null values in my object.Yukyukaghir
@AhmedAziz I am also getting null values in my object, can you please help me how did you solve thisAuscultate
A
8

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

Asseveration answered 20/10, 2015 at 4:4 Comment(0)
C
7

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.

Compose answered 17/2, 2014 at 9:56 Comment(0)
U
2

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.

Usurious answered 31/10, 2018 at 10:48 Comment(0)
L
0

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.

Limpet answered 8/10, 2020 at 16:55 Comment(1)
Whether you pass data in URL params or not depends on HTTP method used and not on @ModelAttribute With Post , params will not be passed in URL but in request bodyAgripina
R
0

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
Reassure answered 3/12, 2021 at 9:32 Comment(0)
J
0

@ModelAttribute is basically used when you want to include multipart files as the body. To pass data from the front end you need to convert the data to JSON. Even the test case writing is also a bit different. You need to use contentType(MediaType.APPLICATION_FORM_URLENCODED) as content type and instead of JSON string you need to pass the values as .param("field", value)

Jacqualinejacquard answered 14/6, 2023 at 2:14 Comment(0)
D
0

@RequestBody: This annotation is used to bind the entire request body to a method parameter. It is typically used when the request payload is in JSON or XML format.

@PostMapping("/example")
public ResponseEntity<String> handleRequest(@RequestBody ExampleDto exampleDto) {
   // Do something with the exampleDto object
   return ResponseEntity.ok("Request handled successfully");
}

@ModelAttribute: This annotation is used to bind request parameters (either in the query string or in the form data) to method parameters or model attributes. It is commonly used with HTML forms or when you want to extract individual parameters from the request.

@PostMapping("/example")
public ResponseEntity<String> handleRequest(@ModelAttribute("name") String name, @ModelAttribute("age") int age) {
    // Do something with the name and age parameters
    return ResponseEntity.ok("Request handled successfully");
}
Defoe answered 3/7, 2023 at 8:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.