07 웹 계층 개발 - 회원 조회

shin·2023년 11월 19일
0

1. Member Controller

...
@Controller
@RequiredArgsConstructor
public class MemberController {

    private final MemberService memberService;
    
    ...
    
    @GetMapping("/members")
    public String list(Model model){

        List<Member> members = memberService.findMembers();
        model.addAttribute("members", members);

        return "members/memberList";

    }
  • 조회한 상품을 뷰에 전달하기 위해 스프링 MVC가 제공하는 모델(Model) 객체에 보관
  • Member Service에서 findMembers 메서드를 사용해서 데이터를 끌어옴
  • model에 담아서 화면에 넘김
  • 실행할 뷰 이름을 반환함
  • members 아래에 memberList라는 html 파일을 추가하여 데이터 조회를 위한 뷰를 만듦


2. memberList View

templates/members/memberList.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<body>
<div class="container">
    <div th:replace="fragments/bodyHeader :: bodyHeader" />
    <div>
        <table class="table table-striped">
            <thead>
            <tr>
                <th>#</th>
                <th>이름</th>
                <th>도시</th>
                <th>주소</th>
                <th>우편번호</th>
            </tr>
            </thead>
            <tbody>
            <tr th:each="member : ${members}">
                <td th:text="${member.id}"></td>
                <td th:text="${member.name}"></td>
                <td th:text="${member.address?.city}"></td>
                <td th:text="${member.address?.street}"></td>
                <td th:text="${member.address?.zipcode}"></td>
            </tr>
            </tbody>
        </table>
    </div>
    <div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->
</body>
</html>
  • 타임리프는 위와 같이 HTML 태그를 그대로 가져다 쓰는 것이 큰 장점

  • 모델에서 담아서 넘긴 members 리스트가 ${members}에 바인딩됨

  • <tr th:each="member : ${members}">와 같이 th:each 문법을 통해 루프를 돌리면서 데이터를 화면에 뿌리게 됨

  • ${member.address?.city}처럼 타임리프에서 ?를 사용하면 null을 무시함

    • if address가 없으면, then city를 조회해오지 않는다는 의미
    • if 조건문을 사용하여 구현하면 코드가 복잡해지기 때문에, 타임리프는 이와같은 물음표 문법을 지원함
  • 위 코드에서 엔티티를 손을 대지 않아도 되는 상황이기 때문에 멤버 객체를 조회해올 때 member entity를 그대로 출력했지만, dto로 변환을 해서 화면에 필요한 데이터들만 가지고 출력하는 것이 권장됨

    • 어차피 서버 사이드에서 도는 것이기 때문에 위와 같은 템플릿엔진에서는 선택적으로 엔티티를 사용해도 괜찮음


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

  • 요구사항이 정말 단순할 때는 폼 객체(MemberForm) 없이 엔티티(Member)를 직접 등록과 수정 화면에서 사용해도 됨
  • 하지만 요구사항이 실무에서는 그렇게 단순하지 못하고 일대일로 매칭되는 경우는 거의 없음

엔티티를 직접 사용하면 발생하는 문제점

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

폼 객체를 사용해야 하는 이유

  • JPA를 사용할 때 가장 주의해야 할 점은 엔티티를 최대한 순수한 상태로 유지해야 하는 것
  • 어떤 것에 대한 의존성 없이 오직 핵심 비즈니스 로직에만 설계하는 것이 중요함
  • 애플리케이션이 커져서 엔티티를 여러 군데에서 유연하게 사용하더라도 유지 보수가 용이해짐

API 개발 시 주의

  • API를 만들 때는 절대 엔티티를 웹으로 반환하면 안됨
  • API는 스펙이기 때문에, 엔티티의 로직을 추가하게 되면 그로 인해 API 스펙이 변하게 됨
  • 그렇게 되면 불안전한 API 스펙이 되고, 그것을 활용하는 개발팀이 괴로워짐
  • 따라서 엔티티는 절대 API로 외부에 노출하면 안됨

결론🚨

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


회원 조회 테스트😊




강의 : 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

profile
Backend development

0개의 댓글