ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 부트 - 회원 관리 예제 실습(회원 도메인과 리포지토리 생성)
    Spring Framework 2022. 1. 26. 00:01

    비즈니스 요구사항 정리

    데이터 : 회원 ID, 이름

    기능 : 회원 등록, 조회

    아직 데이터 저장소가 선정되지 않은 가상의 시나리오(어떤 데이터베이스를 사용할지 정해지지 않음)

     

    일반적인 웹 애플리케이션 계층 구조

    웹 애플리케이션 계층 구조

    컨트롤러 : 웹 MVC의 컨트롤러 역할

    서비스 : 도메인을 기반으로 핵심 비즈니스 로직 구현(회원은 중복가입이 안된다 등의 로직)

    리포지토리 : 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리

    도메인 : 회원, 주문, 쿠폰 등 데이터베이스에 저장되고 관리되는 비즈니스 도메인 객체

     

    클래스 의존관계

    클래스 의존관계

    핵심 비즈니스 로직을 구현 서비스에는 MemberService가 있습니다.

    리포지토리에는 MemberRepository가 있는데 아직 데이터베이스 저장소(RDB, NoSQL 등)가 선정되지 않았으므로 인터페이스로 선언하고 우선은 메모리 기반의 데이터 저장소를 사용합니다.

    인터페이스로 선언함으로써 추후에 구현 클래스를 변경할 수 있습니다.

     

    실습과정

     

    1. hello.hellospring.domain 패키지를 생성합니다.

     

    2. domain 패키지안에 Member 클래스를 생성합니다.

     

    경로

    3. Member 클래스에 요구사항으로 주어진 id와 name을 멤버 변수로 갖게 합니다.

    이때 id는 데이터를 구분하기 위해 시스템이 지정하는 id이며 name은 회원의 이름을 의미합니다.

     

    다음은 Member 클래스의 코드입니다.

    package hello.hellospring.domain;
    
    public class Member {
    	private Long id;
    	private String name;
    	
    	
    	public String getName() {
    		return name;
    	}
    	
    	
    	public void setName(String name) {
    		this.name = name;
    	}
    	
    	
    	public Long getId() {
    		return id;
    	}
    	
    	
    	public void setId(Long id) {
    		this.id = id;
    	}
    }

     

    4. hello.hellospring.repository 패키지를 생성합니다.

     

    5. 위의 요구사항에서 데이터베이스가 선정되지 않아 interface를 구현하기로 했으므로 repository 패키지안에  MemberRepository 인터페이스를 생성합니다.

     

    다음은 MemberReposiotry 인터페이스 코드입니다.

    package hello.hellospring.repository;
    
    import java.util.List;
    import java.util.Optional;
    
    import hello.hellospring.domain.Member;
    
    public interface MemberRepository {
    	Member save(Member member);
    	Optional<Member> findById(Long id);
    	Optional<Member> findByName(String name);
    	List<Member> findAll();
    }

    save 메서드는 회원을 저장하면 저장된 회원을 반환합니다.

    findById 메서드는 ID를 기반으로 회원을 탐색하여 반환합니다.

     

    이때 Optional<>은 Java8부터 추가된 기능으로 만약에 null이 반환될 때 null을 그대로 반환하지 않고 Optional으로 감싸서 반환합니다.

     

    findByName 메서드는 Name을 기반으로 회원을 탐색하여 반환합니다.

    findAll 메서드는 지금까지 저장된 모든 회원을 List로 반환합니다.

     

    6. 인터페이스를 생성했으므로 repository 패키지안에 MemoryMemberRepository 클래스를 생성합니다.

     

    다음은 MemoryMemberRepository 클래스 코드입니다.

    package hello.hellospring.repository;
    
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Optional;
    
    import hello.hellospring.domain.Member;
    
    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) {		
    		return store.values().stream()
    		.filter(member -> member.getName().equals(name))
    		.findAny();						
    	}
    
    	
    	@Override
    	public List<Member> findAll() {
    		return new ArrayList<>(store.values());
    	}
    
    }

    id와 Name을 Key Value로 다루기 위해 Map을 사용합니다.

    sequence는 0, 1, 2...처럼 Key 값을 생성하는 변수입니다.

    실무에서는 공유되는 변수에 동시성 문제를 고려해야 하지만 여기서는 단순함을 추구하기 때문에 고려하지 않습니다.

     

    save() 메서드에서는 회원의 id를 지정합니다.(setId)

    이후에 store 변수에 Id값과 맴버값을 저장하고 반환합니다.

    name을 저장하지 않는 이유는 name은 이미 고객이 회원 가입할 때 입력하여 이미 넘어온 상태입니다.

    따라서 회원의 id값만 시스템이 등록합니다.

     

    findByID() 메서드는 store.get(id); 를 하면 되지만 만약 해당 값이 존재하지 않는다면 null이 반환되므로 Optional.ofNullable(store.get(id))를 사용하여 값을 감싸서 보냅니다.

     

    findByName() 메서드는 store.values().stream()을 통해 store에 저장된 member(id, 고객의 이름)들을 스트림으로 만들고. filter(member -> member.getName(). equals(name)). findAny() 람다식을 통해 고객의 이름과 매개변수가 일치한다면 그것을 반환합니다. 만약 찾지 못한다면 null을 Optional로 감싸 반환합니다.

     

    findAll() 메서드는 store에 저장된 member들을 ArrayList로 변환하여 반환합니다.

     

     

    이렇게 코드를 다 작성해보았는데 구현을 올바르게 했는지 어떻게 확인해야 할까요?!

    테스트코드 작성을 통하여 이를 확인합니다.

    테스트 코드는 테스트 코드 카테고리에서 작성해보도록 하겠습니다.

     

    https://junuuu.tistory.com/74

     

     

    출처

    https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

     

    [무료] 스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술 - 인프런 | 강의

    스프링 입문자가 예제를 만들어가면서 스프링 웹 애플리케이션 개발 전반을 빠르게 학습할 수 있습니다., 스프링 학습 첫 길잡이! 개발 공부의 길을 잃지 않도록 도와드립니다. 📣 확인해주세

    www.inflearn.com

     

    댓글

Designed by Tistory.