[DMD] 6-1. 웹 개발 - Member

sorzzzzy·2021년 12월 12일
0

Spring Project

목록 보기
6/18
post-thumbnail

웹 개발을 시작해보자!

후에 개발할 API를 위해서는 홈 화면 및 레이아웃을 보기좋게 꾸며야 하는데, 하하 타임리프 사용과 변경감지와 병합 부분만 깊게 이해를 하고 템플릿은 저번 프로젝트 때 썼던 템플릿을 그대로 가져오려고 한다😂

보기 좋게 하기 위해 부트스트랩을 사용했다!

이번 시간에는 폼 객체를 사용해서 화면 계층과 서비스 계층을 명확하게 분리할 것이다.


🏷 회원 등록 폼 객체

MemberForm.java

package sorzzzzy.dearmydog.controller;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.NotEmpty;

@Getter @Setter
public class MemberForm {
    // 컨트롤러에서 @Valid로 쉽게 가져다 쓸 수 있음
    @NotEmpty(message = "회원 이름은 필수 입니다")
    private String name;

    private String city;
    private String street;
    private String zipcode;
}

➡️ @NotEmpty 어노테이션은 스프링에서 제공하는 검증 기능인데 뒤에 나오는 컨트롤러 부분에서 자세히 설명하겠다.
회원 등록 폼은 이렇게 필요한 요소들로만 간단히 구성된다.


🏷 회원 등록 컨트롤러

MemberController.java

package sorzzzzy.dearmydog.controller;

import sorzzzzy.dearmydog.domain.Address;
import sorzzzzy.dearmydog.domain.Member;
import sorzzzzy.dearmydog.service.MemberService;
import lombok.RequiredArgsConstructor;
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(value = "/members/new")
        public String createForm(Model model) {
            model.addAttribute("memberForm", new MemberForm());
            return "members/createMemberForm";
        }

회원 등록 관련해서 GET 요청이 들어왔을 땐 회원 등록 폼을 그대로 보여주면 된다.

반면 POST 요청이 들어왔을 때는,

.
.
@PostMapping("/members/new")
    // @Valid 를 사용하면 여러 검증 기능을 편하게 사용할 수 있음
    // -> 예를 들면, MemberForm 의 @NotEmpty 기능
    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:/";
    }

회원 등록을 한 후 회원의 데이터가 들어있는 상태이기 때문에 알맞게 처리해주어야 한다.
여기서 @Valid 어노테이션을 사용하면, MemberForm에서 여러 검증 기능을 편리하게 가져다 사용할 수 있게 된다!

📌 타임리프가 제공하는 유용한 기능(1)
회원 등록 폼 화면에서,

<input type="text" th:field="*{name}" .... >

이와 같이 필드 옵션을 설정해주면, 소스를 확인했을 때 따로 지정해주지 않아도, idname 의 값이 지정해준 이름으로 한번에 설정이 가능하다.


🏷 회원 목록 조회 컨트롤러

MemberController.java

.
.
    @GetMapping("/members")
    public String list(Model model) {
        List<Member> members = memberService.findMembers();
        model.addAttribute("members", members);
        return "members/memberList";
    }

➡️ 조회한 상품을 뷰에 전달하기 위해 스프링 MVC가 제공하는 모델 객체에 보관 후, 실행할 뷰 이름을 반환한다.

📌 타임리프가 제공하는 유용한 기능(2)

<td th:text="${member.address?.city}"></td>

이와 같이 타임리프에서 ? 를 사용하면 null 을 무시한다.


🤔 폼 객체 vs 엔티티 직접 사용

폼 객체를 굳이 사용해야 하나? 라는 생각이 들 수 있다.
만약 요구사항이 정말 단순할 때는 폼 객체(=MemberForm)없이 엔티티(=Member)를 직접 등록과 수정 화면에서 사용해도 된다.

하지만 화면 요구사항이 복잡해지기 시작하면, 엔티티에 화면을 처리하기 위한 기능이 점점 증가한다.
결과적으로 엔티티는 점점 화면에 종속적으로 변하고, 이렇게 화면 기능 때문에 지저분해진 엔티티는 결국 유지보수하기 어려워진다🥲!!

실무에서 엔티티는 핵심 비즈니스 로직만 가지고 있고, 화면을 위한 로직은 없어야 한다.
화면이나 API에 맞는 폼객체나 DTO를 사용하여 화면이나 API 요구사항을 이것들로 처리하고,
엔티티는 최대한 순수하게 유지하는 습관을 들이자!!


다음 시간에는 상품 관련 폼과 컨트롤러를 생성해보자😉

profile
Backend Developer

0개의 댓글