코드 그라데이션

shop 구현 (2) Controller, Model 본문

Spring/SpringShop

shop 구현 (2) Controller, Model

완벽한 장면 2023. 7. 8. 12:55

Controller 단에서

@Controller
@RequiredArgsConstructor
public class ItemController {

  @GetMapping(value = "/admin/item/new")
  public String itemForm() {
    return "/item/itemForm";
  }

리턴타입이 String이고, 문자열 리턴이 있으면, 이건 view로 인식한다.

templates 가 기본 탐색 경로인데, 

templates에서 /item 폴더 안에 있는 itemForm을 의미한다.

반환이라기보다는 "파일경로"라고 생각하는 게 더 옳은 판단.

 

만약 문자열 자체를 반환하고 싶다면?

view 이름이 아닌...

그럴 때 메서드 위에 @ResponseBody를 붙인다.

-> view이름으로 해석하는 게 아니라 사용자에게 돌려주는 응답값이라고 인식해서 이 결과가 화면에 그대로 반환.

 

@Controller + @ResponseBody = @RestController

 


@Controller
@RequestMapping("/members")
@RequiredArgsConstructor // final 또는 @NonNull 명령어가 붙으면 객체를 자동 붙여준다.
public class MemberController {

  private final MemberService memberService;
  private final PasswordEncoder passwordEncoder;
  // 빈으로 등록해놓은 경우라서 그냥 가져올 수 있음(SecurityConfig에)


  @GetMapping(value = "/new")
  public String memberForm(Model model){
    model.addAttribute("memberFormDto",new MemberFormDto());
    return "member/memberForm";
  }


  @PostMapping(value = "/new")
  public String memberForm(@Valid MemberFormDto memberFormDto, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
      return "member/memberForm"; // 돌려보내면, 페이지 에러에 설정해놓은 것대로 맞춰서 나온다.
    }
    try {
      Member member = Member.createMember(memberFormDto,passwordEncoder);
      memberService.saveMember(member);
    }
    catch (IllegalStateException e){
      model.addAttribute("errorMessage",e.getMessage());
      return "member/memberForm";
    }

    return "redirect:/";
  }
  /*
  참고로 이건 처음 가입하면 페이지 없다는 메시지 나오고, 뒤로가기 한 번 후 다시 submit버튼 눌러야 가입됨
  이후 한 번 더 시도하면 그때 alert 나온다.
   */

  @GetMapping(value = "/login")
  public String loginMember() {
    return "/member/memberLoginForm";
  }

  @GetMapping(value = "/login/error")
  public String loginError(Model model) {
    model.addAttribute("loginErrorMsg", "아이디 또는 비밀번호를 확인하세요");
    return "/member/memberLoginForm";
  }
}

 

예를 들어

  @GetMapping(value = "/new")
  public String memberForm(Model model){
    model.addAttribute("memberFormDto",new MemberFormDto());
    return "member/memberForm";
  }

 

여기서 model.addAttribute가 무엇인가?

일단 이것은 시큐리티랑 관련있는 게 아니라 web과 관련 있는 것.

일단 Model model은 사용자가 주는 값 아니다.

(cf. @PathVariable이나 @RequestParam은 사용자가 주는 값을 받는 것)

 

컨트롤러의 핸들러로 Model이 있으면, 스프링은 여기다가 모델의 객체를 만들어서 넣어준다.

모델의 역할은 MVC에서 M.

데이터를 들고다니는 역할을 함. Dto랑 가까움.

그래서 살펴보면 컨트롤러는 모델의 값을 설정하고 그 값을 view에 전달하는 것 까지가 역할이다.

 

 

모델은 Map이다.

Map에서는

map.put(key, value) 했다면

모델에서는

model.addAttribute(키, 값) 한다고 생각하면 된다.

 

Map은 그냥 데이터를 저장하는 자료구조이므로, MemberFormDto가 오면 함수처럼 뭔가가 실행되는 게 아니라 여기서 만들어진 객체 자체가 그냥 반환이 된다. 

Model이 있으면 리턴값을 view에 전달할 때 Model도 같이 전달해준다 스프링이.

 

MemberForm.html 가보면

<form action="/members/new" role="form" method="post" th:object="${memberFormDto}">

 

${memberFormDto} 이게 지금 위에서의 Key.

 

 

최종적으로 정리하면, 모델은 데이터를 저장하는 용도. 모델은 그냥 Map이다. 

Map에 키, 밸류를 저장하면 스프링이 자동으로 View에 전달할 때 Model 까지 함께 전달해준다.

 


  @PostMapping(value = "/new")
  public String memberForm(@Valid MemberFormDto memberFormDto, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
      return "member/memberForm"; // 돌려보내면, 페이지 에러에 설정해놓은 것대로 맞춰서 나온다.
    }
    try {
      Member member = Member.createMember(memberFormDto,passwordEncoder);
      memberService.saveMember(member);
    }
    catch (IllegalStateException e){
      model.addAttribute("errorMessage",e.getMessage());
      return "member/memberForm";
    }

    return "redirect:/";
  }

 

이런 걸 컨벤션(자동으로 인지하는 공통된 약속 같은 개념)

@Valid 가 붙어있을 때, bindingResult라는 매개변수를 주면, 

@Valid 뒤에 있는 것을 검증을 해서 검증 결과를 바인딩리절트에 넣어준다.

MemberFormDto에 가면 검증 어노테이션이 붙어 있음.

그럼 코드가 없어도 자동으로 실행해준다.

 

 나는 따로 설정해준 것이 없는데 바인딩 리절트를 붙여놓은 것만으로도 결과를 return "member/memberForm";에 전달할 때 에러 결과까지 같이 붙여서 보내준다. 

(에러가 있다면 사용자는 화면을 볼 때 에러 원인까지 함께 확인 가능)

 

세 번째 매개변수로 Model model이 있는 것은 

이 컨트롤러가 봤을 때,  member/memberForm 이 뷰에 전달할 때 뭔가를 더 전달하고 싶은 거예요.

=> 이 코드에선 에러 메시지.

이 에러는 createMember, saveMember를 할 때 생길 수 있는 에러.

 

if (bindingResult.hasErrors()) {
      return "member/memberForm"; // 돌려보내면, 페이지 에러에 설정해놓은 것대로 맞춰서 나온다 이 에러는 아니고

검증은 한 번 통과했으나 saveMember했을 때 발생할 수 있는 에러. 

그 에러메시지를 뷰에 전달하겠다는 목표를 이루기 위해서 Model을 여기에 추가함.

(여기서는 중복회원이면 가입이 실패하니까 그 메시지를 전달하기 위해서 model을 박았을 듯)

 

 

728x90
Comments