...
<a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
...
@GetMapping("/create")
public String questionCreate() {
return "question_form";
}
<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container">
<h5 class="my-3 border-bottom pb-2">질문등록</h5>
<form th:action="@{/question/create}" method="post">
<div class="mb-3">
<label for="subject" class="form-label">제목</label>
<input type="text" name="subject" id="subject" class="form-control">
</div>
<div class="mb-3">
<label for="content" class="form-label">내용</label>
<textarea name="content" id="content" class="form-control" rows="10"></textarea>
</div>
<input type="submit" value="저장하기" class="btn btn-primary my-2">
</form>
</div>
</html>
@PostMapping("/create")
public String questionCreate(@RequestParam String subject, @RequestParam String content) {
// TODO 질문을 저장한다.
return "redirect:/question/list"; // 질문 저장후 질문목록으로 이동
}
public void create(String subject, String content) {
Question q = new Question();
q.setSubject(subject);
q.setContent(content);
q.setCreateDate(LocalDateTime.now());
this.questionRepository.save(q);
}
...
this.questionService.create(subject, content);
...
항목 | 설명 |
---|---|
@Size | 문자 길이를 제한 |
@NotNull | Null을 허용하지 않는다. |
@NotEmpty | Null 또는 빈 문자열("")을 허용하지 않는다. |
@Past | 과거 날짜만 가능 |
@Future | 미래 날짜만 가능 |
@FutureOrPresent | 미래 또는 오늘날짜만 가능 |
@Max | 최대값 |
@Min | 최소값 |
@Pattern | 정규식으로 검증 |
...
@NotEmpty(message="제목은 필수항목입니다.")
@Size(max=200)
private String subject;
@NotEmpty(message="내용은 필수항목입니다.")
private String content;
...
@PostMapping("/create")
public String questionCreate(@Valid QuestionForm questionForm, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "question_form";
}
this.questionService.create(questionForm.getSubject(), questionForm.getContent());
return "redirect:/question/list";
}
th:object
꼭 필요!<h5 class="my-3 border-bottom pb-2">질문등록</h5>
<form th:action="@{/question/create}" th:object="${questionForm}" method="post">
<div class="alert alert-danger" role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="err : ${#fields.allErrors()}" th:text="${err}" />
</div>
...
th:object
에 의해 QuestionForm 객체가 필요
questionCreate
의 매개변수 QuestionForm questionForm
으로 변경th:field
각 필드 매핑해주는 역할<input ~~~ th:field="*{subject}" ~~~>
<textarea ~~~ th:field="*{content}" ~~~>
답변등록도 질문등록과 동일
th:fragment
: 반복되는 코드를 재사용th:replace
: 현재 태그를 fragment 태그로 교체<div th:fragment="formErrorsFragment" class="alert alert-danger"
role="alert" th:if="${#fields.hasAnyErrors()}">
<div th:each="err : ${#fields.allErrors()}" th:text="${err}" />
</div>
th:replace
: 공통 템플릿을 템플릿 내에 삽입, 즉 꺼내쓰기"~{form_errors :: formErrorsFragment}"
: form_errors.html의 formErrorsFragment 인 것으로 교체 <div th:replace="~{form_errors :: formErrorsFragment}"></div>