0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

コントローラのメソッドの引数列に@ModelAttributeアノテーションが付けたら何があった

Posted at

ソースコードはサンプルアプリケーションからとった。

Thymeleafテンプレートの入力フォーム'resources/templates/private/message.html'

<!DOCTYPE html>
<html th:lang="${#locale.language}" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
  <title>[[#{applicationName}]] - [[${isEdit}? #{editMessage}: #{newMessage}]]</title>
  <meta charset="utf-8">
  <link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
</head>
<body>
<div class="ui container">
  <h4 th:text="${isEdit}? #{editMessage}: #{newMessage}"></h4>
  <form th:action="@{/manage/__${postHandler}__}" method="post" th:object="${message}" class="ui form">
    <fieldset>
      <legend>[[#{message}]]</legend>
      <div class="field">
        <label>[[#{message.publishDate}]]</label>
        <input type="text" th:field="*{publishDate}" />
      </div>
      <div class="field">
        <label>[[#{message.removeDate}]]</label>
        <input type="text" th:field="*{removeDate}" />
      </div>
      <div class="field">
        <label>[[#{message.description}]]</label>
        <textarea name="description" th:text="*{description}"></textarea>
      </div>
      <button class="ui mini primary button">[[#{save}]] <i class="send icon"></i></button>
    </fieldset>
  </form>
</div>
</body>
</html>

ブラウザがhttp://localhost:8080/manage/newにアクセスし、下のHTMLコードがもらえる

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Notice board - New message</title>
  <meta charset="utf-8">
  <link type="text/css" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css">
</head>
<body>
<div class="ui container">
  <h4>New message</h4>
  <form action="/manage/new/save" method="post" class="ui form"><input type="hidden" name="_csrf" value="87baeee6-deea-4c4b-8b2b-b17e9be876e0"/>
    <fieldset>
      <legend>Message</legend>
      <div class="field">
        <label>Publish Date</label>
        <input type="text" id="publishDate" name="publishDate" value="" />
      </div>
      <div class="field">
        <label>Remove Date</label>
        <input type="text" id="removeDate" name="removeDate" value="" />
      </div>
      <div class="field">
        <label>Message</label>
        <textarea name="description"></textarea>
      </div>
      <button class="ui mini primary button">Save <i class="send icon"></i></button>
    </fieldset>
  </form>
</div>
</body>
</html>

下のように資料を入れ

form_filled.png

'Save'をクリックし、HTTP POSTリクエストと下のパラメータがhttp://localhost:8080/manage/new/saveに送る

post.png

クラスinfo.saladlam.example.spring.noticeboard.controller.PrivateControllerのメソッド**saveCreateMessage()**がリクエストを処理する

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

	@PostMapping("/new/save")
	public String saveCreateMessage(@ModelAttribute MessageDto message, BindingResult errors) {
		message.setOwner(this.getLoginName());
		this.messageService.save(message);
		return "redirect:/manage";
	}
	// ...
}

インスタンスMessageDtoはクラスorg.springframework.web.method.annotation.ModelAttributeMethodProcessorが建てる。実際建てる手順のはメソッド**resolveArgument()**に定義される

	@Override
	@Nullable
	public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
		Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");

		String name = ModelFactory.getNameForParameter(parameter);
		ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
		if (ann != null) {
			mavContainer.setBinding(name, ann.binding());
		}

		Object attribute = null;
		BindingResult bindingResult = null;

		if (mavContainer.containsAttribute(name)) {
			attribute = mavContainer.getModel().get(name);
		}
		else {
			// Create attribute instance
			try {
				attribute = createAttribute(name, parameter, binderFactory, webRequest);
			}
			catch (BindException ex) {
				if (isBindExceptionRequired(parameter)) {
					// No BindingResult parameter -> fail with BindException
					throw ex;
				}
				// Otherwise, expose null/empty value and associated BindingResult
				if (parameter.getParameterType() == Optional.class) {
					attribute = Optional.empty();
				}
				bindingResult = ex.getBindingResult();
			}
		}

		if (bindingResult == null) {
			// Bean property binding and validation;
			// skipped in case of binding failure on construction.
			WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
			if (binder.getTarget() != null) {
				if (!mavContainer.isBindingDisabled(name)) {
					bindRequestParameters(binder, webRequest);
				}
				validateIfApplicable(binder, parameter);
				if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
					throw new BindException(binder.getBindingResult());
				}
			}
			// Value type adaptation, also covering java.util.Optional
			if (!parameter.getParameterType().isInstance(attribute)) {
				attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
			}
			bindingResult = binder.getBindingResult();
		}

		// Add resolved attribute and BindingResult at the end of the model
		Map<String, Object> bindingResultModel = bindingResult.getModel();
		mavContainer.removeAttributes(bindingResultModel);
		mavContainer.addAllAttributes(bindingResultModel);

		return attribute;
	}

ここにMessageDtoインスタンスがもらえる

bindRequestParameters(binder, webRequest);

そしてもしValidatorが定義されたら、ここに実行する

validateIfApplicable(binder, parameter);

最後にMessageDtoインスタンスは引数messageとしてコントローラに渡す。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?