DEV Community

Salad Lam
Salad Lam

Posted on

About org.springframework.web.bind.annotation.ModelAttribute annotation of Spring Web MVC

Controller

Following is a Controller to handle POST requests of HTTP form.

@Controller
@RequestMapping("/manage")
public class PrivateController {

    @PostMapping("/new")
    public String saveCreateMessage(@Valid @ModelAttribute("message") MessageMvcDto message, BindingResult errors, Model model) {
        if (errors.hasErrors()) {
            model.addAttribute("isEdit", false);
            model.addAttribute("postHandler", "new");
            return "private/message";
        }

        MessageDto dto = new MessageDto();
        dto.setPublishDate(message.getPublishDate());
        dto.setRemoveDate(message.getRemoveDate());
        dto.setDescription(message.getDescription());
        dto.setOwner(this.getLoginName());
        this.messageService.save(dto);
        return "redirect:/manage";
    }

    // ...
}
Enter fullscreen mode Exit fullscreen mode

Before executing saveCreateMessage() method, the framework will bind values sent by POST to MessageMvcDto instance, perform validation and build BindingResult instance.

Then execute saveCreateMessage() and pass MessageMvcDto, BindingResult instance as parameter. Assume that validation failed and has an error, a template string is returned.

Since parameter message is annotated with @ModelAttribute("message"), the binded MessageMvcDto and BindingResult instance will write into Model as follows.

Key Value
message MessageMvcDto instance
org.springframework.validation.BindingResult.message BindingResult instance

If annotated with @ModelAttribute (without name), will become the following.

Key Value
messageMvcDto MessageMvcDto instance
org.springframework.validation.BindingResult.messageMvcDto BindingResult instance

Rendering

Values in the Model will become attributes of HttpServletRequest (but not in Session). WebEngineContext instance is built for Thymeleaf to lookup the value of expression.

Using the following template

<!-- ... -->
  <form th:action="@{/manage/__${postHandler}__}" method="post" th:object="${message}" th:classappend="${#fields.hasErrors()}?error" class="ui form">
    <fieldset>
      <legend th:text="#{message}"></legend>
      <div th:if="${#fields.hasErrors()}" th:classappend="${#fields.hasErrors()}?error" class="ui message">
        <ul class="list">
          <li th:each="error:${#fields.allErrors()}" th:text="${error}"></li>
        </ul>
      </div>
      <div class="field">
        <label th:text="#{message.publishDate}"></label>
        <div class="two fields">
          <div th:classappend="${#fields.hasErrors('publishDateDate')}?error" class="field">
            <input id="edPublishDateDate" type="date" th:field="*{publishDateDate}" />
          </div>
          <div th:classappend="${#fields.hasErrors('publishDateTime')}?error" class="field">
            <input id="edPublishDateTime" type="time" th:field="*{publishDateTime}" />
          </div>
        </div>
      </div>
      <!-- ... -->
      <button id="edSave" class="ui mini primary button">[[#{save}]] <i class="send icon"></i></button>
      <button id="edCancel" type="button" class="ui mini button" onclick="document.location='../manage'; return false;">[[#{cancel}]] <i class="window close icon"></i></button>
    </fieldset>
  </form>
<!-- ... -->
Enter fullscreen mode Exit fullscreen mode

#fields expression can be used within form tag with th:object only.

When processing form tag, attribute th:object will save into HttpServletRequest attribute springBoundObjectExpression (i.e. "${message}").

When processing #fields expression, first lookup HttpServletRequest attribute springBoundObjectExpression, then prepend the result with org.springframework.validation.BindingResult. (i.e. org.springframework.validation.BindingResult.message) and lookup HttpServletRequest attribute again. Afterward a BindingResult instance is found (BindingResult is the child interface of Errors) and a related method is called.

The reason why nothing happened on using #fields expression is not to set name on @ModelAttribute annotation.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Immerse yourself in a wealth of knowledge with this piece, supported by the inclusive DEV Community—every developer, no matter where they are in their journey, is invited to contribute to our collective wisdom.

A simple “thank you” goes a long way—express your gratitude below in the comments!

Gathering insights enriches our journey on DEV and fortifies our community ties. Did you find this article valuable? Taking a moment to thank the author can have a significant impact.

Okay