왜냐하면 Thymeleaf가 해당 form을 활용하여 html파일을 렌더링 하기 때문이다.
spring의 실행과정:
1. 요청을 보내면
2. DispatcherServlet에서 HandlerMapping을 보고
3. Controller에 연결시킨다.
4. 이후 Controller에서 처리를 다하면 model에 데이터를 담고(안 담을 수도 있음)
5. view이름을 return하면
6. DispatcherServlet이 viewResolver를 호출하여 view이름을 전달한다.
7. viewResolver는 해당 view이름을 가진 html or jsp등을 model데이터나, request저장소를 활용하여 렌더링한다.
우리가 집중해야하는 것은 7번이다. 만약 빈 form을 model담고 return "페이지"를 한다면 viewResolver(Thymeleaf)는 해당 model을 가지고 렌더링을 한다는 것이다.
따라서 html 작성할때
form의 값을 추적하여 사용할 수 있게 되는 것이고 form의 값을 잘못사용한것을 컴파일 과정에서 오류로 보여주거나
BindingResult를 통해 알 수 있는 오류를 감지하여 데이터에 오류가 있음을 html에 표시할 수 있게 해주는 것이다.
@GetMapping("/members/new")
public String createForm(Model model) {
model.addAttribute("memberForm", new MemberForm());
return "members/createMemberForm";
}
@PostMapping("/members/new")
public String create(@Valid MemberForm form, BindingResult result) {
if (result.hasErrors()) {
return "members/createMemberForm";
}
Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());
Member member = new Member();
member.setName(form.getName());
member.setAddress(address);
memberService.join(member);
return "redirect:/";
}
<div class="form-group">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요"
th:class="${#fields.hasErrors('name')}? 'form-control
fieldError' : 'form-control'">
<p th:if="${#fields.hasErrors('name')}"
th:errors="*{name}">Incorrect date</p>
</div>
package jpabook.jpashop.domain;
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Getter@Setter
public class Member {
@Id
@GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@Embedded
private Address address;
@OneToMany(fetch = FetchType.LAZY,mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
package jpabook.jpashop.controller;
import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping("/members/new")
public String createForm(Model model) {
//model로 담아서 보내줘야지 thymeleaf 작성할때 편하게 쓸 수 있는듯
//안보내주면 엔티티속성 자동완성 안됨
model.addAttribute("memberForm", new MemberForm());
return "members/createMemberForm";
}
/**
*
* http post요청으로
* name = xx
* city = xx 이런식으로 보내지는데
* 이름보고 MemberForm.name = name이런식으로 매핑되는듯
*
*/
@PostMapping("/members/new")
public String create(@Valid MemberForm form, BindingResult result) {
if (result.hasErrors()) {
return "members/createMemberForm";
}
Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());
Member member = new Member();
member.setName(form.getName());
member.setAddress(address);
memberService.join(member);
return "redirect:/";
}
@GetMapping("/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<style>
.fieldError {
border-color: #bd2130;
}
</style>
<body>
<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>
<form role="form" action="/members/new" th:object="${memberForm}"
method="post">
<div class="form-group">
<label th:for="name">이름</label>
<input type="text" th:field="*{name}" class="form-control"
placeholder="이름을 입력하세요"
th:class="${#fields.hasErrors('name')}? 'form-control
fieldError' : 'form-control'">
<p th:if="${#fields.hasErrors('name')}"
th:errors="*{name}">Incorrect date</p>
</div>
<div class="form-group">
<label th:for="city">도시</label>
<input type="text" th:field="*{city}" class="form-control"
placeholder="도시를 입력하세요">
</div>
<div class="form-group">
<label th:for="street">거리</label>
<input type="text" th:field="*{street}" class="form-control"
placeholder="거리를 입력하세요">
</div>
<div class="form-group">
<label th:for="zipcode">우편번호</label>
<input type="text" th:field="*{zipcode}" class="form-control"
placeholder="우편번호를 입력하세요">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<br/>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
'2022 > spring' 카테고리의 다른 글
[Thymeleaf] Th:field란 (0) | 2022.08.30 |
---|---|
static도 아닌 인스턴스 메서드를 어떤 방법으로 실행해주는가? (0) | 2022.05.25 |