package hello.hellospring.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "home";
}
}
<!DOCTYPE HTML>
<html xmlns:th="<http://www.thymeleaf.org>">
<body>
<div class="container">
<div>
<h1>Hello Spring</h1>
<p>회원 기능</p>
<p>
<a href="/members/new">회원 가입</a>
<a href="/members">회원 목록</a>
</p>
</div>
</div> <!-- /container -->
</body>
</html>
참고 : 컨트롤러가 정적 파일보다 우선순위가 높다. → 기존에 정적파일인 index.html을 만들어 놨었는데 이것도 welcome page 였다. 하지만 컨트롤러가 정적파일보다 우선순위가 높기 때문에 home.html이 매핑이 되어 나타나게 된다.
회원 등록 폼 컨트롤러
@Controller
public class MemberController {
private final MemberService memberService;
@Autowired
public MemberController(MemberService memberService) {
this.memberService = memberService;
}
@GetMapping(value = "/members/new")
public String createForm() {
return "members/createMemberForm";
}
}
회원 등록 폼 HTML ( resources/templates/members/createMemberForm )
<!DOCTYPE HTML>
<html xmlns:th="<http://www.thymeleaf.org>">
<body>
<div class="container">
<form action="/members/new" method="post">
<div class="form-group">
<label for="name">이름</label>
<input type="text" id="name" name="name" placeholder="이름을 입력하세요">
</div>
<button type="submit">등록</button>
</form>
</div> <!-- /container -->
</body>
</html>
package hello.hellospring.controller;
public class MemberForm {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@PostMapping(value = "/members/new")
public String create(MemberForm form) {
Member member = new Member();
member.setName(form.getName());
memberService.join(member);
return "redirect:/";
}
만약
Form html에서 input name을name = “name_test”라고 바꿨다면,MemberFormClass 에서도private String name을private String name_test라고 바꾸고getName과setName도getName_test,setName_test로 바꾸어야 하며, getter의 return값도name에서name_test로 바꾸고, setter의this.name도this.name_test로 바꿔야 한다.
이를 자바 빈 프로퍼티 접근법 이라고 한다.!!
질문 1. 컨트롤러에 MemberForm을 만들 이유가 있나요?
→ 사실 아래처럼 컨트롤러에 MemberForm 대신에 Member를 그대로 받아도 기술적인 문제는 없습니다.@PostMapping("/members/new") public String create(Member member) { // Member member = new Member(); // member.setName(form.getName()); memberService.join(member); return "redirect:/"; }다만 지금은 예제이지만, 실무에서는 컨트롤러에 넘어오는 정보가 Member가 필요한 데이터 이상으로 많은 데이터들이 들어옵니다. 예를 들어서 회원 정보 뿐만 아니라 약관 정보도 들어오고, 화면을 처리하기 위한 추가 정보들도 들어옵니다. 또는 Member에 필요한 정보들이 화면이 아니라 데이터베이스에 더 있을 수도 있습니다. 더 여러가지가 있지만, 주로 이런 이유 때문에 MemberForm과 Member를 분리하는 것이 좋습니다^^
질문 2. MemberForm이라는 클래스는 어떠한 어노테이션도 없이 순수 자바코드인데 어떻게 폼에서 name값을 받아와 setName을 해주는지 궁금합니다.
→ 스프링 MVC가 기본으로 지원하는 기능입니다^^ 웹의 파라미터에 name이라는 이름이 있으면 이 이름을 보고 스프링 MVC가 setName을 호출합니다.
즉, PostMapping 어노테이션을 받는 메서드의 인자에 있는 setName을 호출!!! → 인자가 form이든 member이든 둘 다 setName이 있어서 저장되는것.
@GetMapping(value = "/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>">
<body>
<div class="container">
<div>
<table>
<thead>
<tr>
<th>#</th>
<th>이름</th>
</tr>
</thead>
<tbody>
<tr th:each="member : ${members}">
<td th:text="${member.id}"></td>
<td th:text="${member.name}"></td>
</tr>
</tbody>
</table>
</div>
</div> <!-- /container -->
</body>
</html>