[이슈해결] Neither BindingResult nor plain target object for bean name 'questionForm' available as request attribute 예외

MinSeong Kang·2022년 8월 19일
2

이슈해결

목록 보기
1/12

Spring boot와 thymeleaf를 사용하여 질문게시판 토이 프로젝트를 진행하다가, Get /question/new 요청시 다음과 같은 예외가 발생했다.
예외가 발생하기 전 코드는 아래와 같다.

<QuestionController.java>

@GetMapping("/question/new")
public String createForm(Model model) {
    return "question_form";
}

@PostMapping("/question/new")
public String createQuestion(@Validated @ModelAttribute QuestionForm questionForm, BindingResult bindingResult) {

	if (bindingResult.hasErrors()) {
		return "question_form";
    }

	service.save(questionForm.getTitle(), questionForm.getContent());
	return "redirect:/qbp/question";
}

<question_form.html>

<html layout:decorate="~{layout}">
    <div layout:fragment="content" class="container">
        <h5 class="my-3 border-bottom pb-2">질문등록</h5>
        <form th:action="@{/qbp/question/new}" th:object="${questionForm}" method="post">
            <div class="mb-3">
                <label for="title" class="form-label">제목</label>
                <input type="text" th:field="*{title}" th:errorclass="field-error" name="title" class="form-control">
                <div th:if="${#fields.hasErrors('title')}" th:errorclass="field-error" th:errors="*{title}">
                    제목 오류
                </div>
            </div>
            <div class="mb-3">
                <label for="content" class="form-label">내용</label>
                <textarea name="content" th:field="*{content}" th:errorclass="field-error" class="form-control" rows="10">
                </textarea>
                <div th:if="${#fields.hasErrors('content')}" th:errorclass="field-error" th:errors="*{content}">
                    본문 오류
                </div>
            </div>
            <input type="submit" value="저장하기" class="float-end btn btn-info btn-sm my-2">
        </form>
    </div>
</html>

thymeleaf 문법

  • th:object="${questionForm}" 문법은 <form>에서 사용할 객체를 지정할 때 사용한다.
  • 따라서 * (선택 변수식) 을 통해 object가 선택한 변수를 사용할 수 있다.

예외 발생 과정

  • Spring validation을 통해 입력 폼의 값을 검증하는 기능을 추가하면서
    • QuestionForm DTO를 생성하여 Spring validation의 검증 어노테이션(@NotEmpty)을 통해 검증 조건을 걸어주고,
    • 폼을 통해 입력 받은 값을 questionForm 객체 담아 컨트롤러에 전달해주기 위해 th:object 문법을 추가하였다.
    • 컨트롤러에서 @ModelAttribute QuestionForm questionForm를 통해 폼을 통해 값을 받아올 수 있게 하고,
    • Spring validation 기능을 사용하기 위해 @Validated, @BindingResult 를 알맞게 사용하였다.

단순히 th:object="${questionForm}" 문법을 통해 폼의 입력값을 컨트롤러에게 넘겨만 주면 된다고 생각을 해서 입력폼 페이지를 조회하는 아래의 함수를 수정하지 않았다.

@GetMapping("/question/new")
public String createForm(Model model) {
    return "question_form";
}

Neither BindingResult nor plain target object for bean name 'questionForm' available as request attribute
예외 자체도 BindingResult라고 쓰여져 있어, thyemleaf 코드에 error 와 관련된 문법(th:errors나 th:errorclass)에 오타나 잘못된 문법이 있거나 @BindingResult을 잘못 사용한 것이라 생각을 해서 이리 저리 수정해보았지만 해당 예외를 해결하지 못했다.

구글링 결과,
결국 예외가 발생한 이유는 입력폼 페이지 조회시(/question/new Get 요청), 템플릿에서 th:object="${questionForm}에서 questionForm에 대한 정보를 전달받지 못해 발생한 것이었다. 따라서 아래와 같이 model에 questionForm에 대한 객체 정보를 저장하여 템플릿에게 전달해야 한다.
이 때, 처음 입력 폼 페이지를 조회할 때 입력 폼은 모두 비어져있어야 하기 때문에 빈 객체(new QuestionForm())을 전달해야 한다.

@GetMapping("/question/new")
public String createForm(Model model) {
	model.addAttribute("questionForm", new QuestionForm());
	return "question_form";
}

0개의 댓글