[TIL] 250610_Spring: 회원 관리 예제 - 백엔드 개발(1)

지코·2025년 6월 11일
1

Today I Learned

목록 보기
72/74
post-thumbnail

🍃 비즈니스 요구사항 정리

  • 데이터: 회원 ID, 이름
  • 기능: 회원 등록, 조회
  • 아직 데이터 저장소가 선정되지 않았다는 가상 시나리오를 가짐.

일반적인 웹 애플리케이션의 계층 구조는 위와 같다. 컨트롤러는 웹 MVC의 컨트롤러 혹은 API의 컨트롤러를 말하며, 서비스는 이 애플리케이션 서비스의 핵심 비즈니스 로직을 말한다. 예를 들어 중복이 허용되지 않는 회원 가입을 들 수 있다. 도메인은 회원, 주문, 쿠폰과 같이 데이터베이스에서 저장하고 관리되는 비즈니스 도메인 객체이고, 리포지토리는 데이터베이스에 접근해, 도메인 객체를 데이터베이스에 저장하고 관리하는 역할을 한다.

클래스 의존 관계를 살펴보자.

먼저 회원 리포지토리를 interface 로 설계하기로 한 것에 대해 보면, 리포지토리는 데이터베이스에 접근해 도메인 객체를 데이터베이스에 저장하고 관리하는 역할을 한다고 했다. 가상 시나리오 상 아직 데이터 저장소가 선정되지 않은 상태이기 때문에, 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계한다. 데이터 저장소는 RDB, NoSQL 등 다양한 데이터베이스를 고려하고 있는 상황으로 가정한다.

또한 개발을 진행하기 위해서, 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소를 사용한다. 추후에 데이터 저장소가 결정되면 메모리에서 해당 데이터 저장소로 변경하기 용이하도록, interface 를 사용하는 것이다.

🍃 회원 도메인과 리포지토리 만들기

이전에 정리한 비즈니스 요구사항을 적용하기 위해 프로젝트 내 controller와 같은 위치에 domainrepository 패키지를 생성한다.

📁 domain > Member.java

package hello.hello_spring.domain;

public class Member {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

domain 패키지에는 데이터베이스에서 저장하고 관리되는 비즈니스 도메인 객체를 담는다. 그 중 Member 객체는 회원의 ID와 이름 정보를 가지기에 private으로 필드를 생성해주고, 각각의 필드에 대해 getter와 setter를 생성한다.

📁 repository > MemberRepository.java

package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id);
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

리포지토리는 interface로 구현하기로 했기 때문에, 클래스를 생성할 때 인터페이스를 선택한다.

이 인터페이스는 총 4가지의 명세를 가진다.

  1. save: 데이터 저장소에 회원 정보가 저장되며, 저장된 회원이 반환된다.
  2. findById: 회원이 가진 id 필드를 통해 회원을 조회한다.
  3. findByName: 회원이 가진 name 필드를 통해 회원을 조회한다.
  4. findAll: 모든 회원들을 조회한다.

여기서 Optional 이란
회원 조회 같은 경우 정보가 없을 때 null을 반환하게 되는데, null을 그냥 반환하지 않고 Optional 에 감싸서 반환함으로써 값의 유무를 명시적으로 표현하고, null로 인한 예외를 방지할 수 있다.

  • Ex> findById() 를 호출했을 때
    찾은 회원이 있으면 → Optional.of(member)
    없으면 → Optional.empty()
    를 반환한다.

📁 repository > MemoryMemberRepository.java

package hello.hello_spring.repository;

import hello.hello_spring.domain.Member;

import java.util.*;

public class MemoryMemberRepository implements MemberRepository{
    private static Map<Long, Member> store = new HashMap<>();
    private static long sequence = 0L; // 키 값을 생성해줌

    @Override
    public Member save(Member member) {
        member.setId(++sequence);
        store.put(member.getId(), member);
        return member;
    }

    @Override
    public Optional<Member> findById(Long id) {
        return Optional.ofNullable(store.get(id));
    }

    @Override
    public Optional<Member> findByName(String name) {
        // 자동으로 Optional로 반환됨!
        return store.values().stream()
                .filter(member -> member.getName().equals(name))
                .findAny();
    }

    @Override
    public List<Member> findAll() {
        return new ArrayList<>(store.values());
    }
}

MemoryMemberRepositoryMemberRepository의 실제 구현체로, MemberRepository에서 적어놓은 명세를 이 파일에서 실제 로직으로 구체화한다. 메서드들을 통해 메모리에 실제 데이터를 적재할 수 있다.

  1. 먼저 id-회원 쌍으로 저장할 수 있는 HashMap 객체 store와 회원들의 id가 될 sequence 변수를 생성한다.
  2. save() -> sequence 값을 통해 회원의 id 값을 설정하고, store 객체에 id-회원 쌍을 저장한다. 그리고 회원 객체를 반환한다.
  3. findById() -> store에서 get 메서드를 통해 해당 id 값을 가진 회원을 가져온다. null일 경우를 대비해, Optional로 감싸 반환한다.
  4. findByName() -> store.values() 는 Map에 저장된 모든 Member 객체들만 뽑아서 Collection으로 반환하며, stream() 을 통해 Collection 객체를 함수형 스타일로 처리할 수 있게 한다. 따라서 후에 filter(), findAny() 함수 체이닝이 가능하다.
    filter 함수를 통해 인수로 들어온 name과 같은 name 값을 가진 회원을 조회하고, 조건에 맞는 회원 객체가 하나라도 있을 경우 반환한다.
  5. findAll() -> Map에 저장된 모든 Member 객체들을 뽑아 리스트 형태로 변환한 후 반환한다.

이렇게 클래스 의존 관계를 대략적으로 구현하였다. 이 관계가 제대로 구현되었는지 어떻게 확인할 수 있을까?
다음 시간에는 테스트 케이스를 작성해보고 회원 서비스 개발을 마무리해보겠다!

Reference

🎥 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술

profile
꾸준하고 성실하게, FE 개발자 역량을 키워보자 !

0개의 댓글