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";
}
// ...
}
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>
<!-- ... -->
#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.
Top comments (0)