뚜룽

[Spring] 인프런 스프링 입문 정리 (6) / Service, 회원 등록, 회원 조회 본문

카테고리 없음

[Spring] 인프런 스프링 입문 정리 (6) / Service, 회원 등록, 회원 조회

ddooroong 2023. 10. 23. 23:12

목차

  1. 프로젝트 구조
  2. 회원 등록, 조회

 

 

1. 프로젝트 구조

 

지난 글에서는 도메인(domain)과 리포지토리(repository)에 대해서 정리했었다. 이번에는 실제로 비즈니스 로직을 담당하는 Service 코드를 작성해보았다. 프로젝트 구조는 아래와 같다. 

프로젝트 구조

패키지가 벌써 4개나 되었다. 이쯤에서 각 패키지의 역할을 다시 한 번 정리하고 가자!

  • controller: 실제 URI 요청을 처리할 Controller 클래스를 모아둔 패키지
  • domain: (DB가 정해지지 않은 상황을 가정) 회원의 정보로 저장할 변수를 정의한 클래스가 있는 패키지
  • repository: (DB가 정해지지 않은 상황을 가정) 회원 정보를 메모리에 추가하거나 회원 아이디, 이름으로 정보를 조회하는 패키지
  • service: 회원 가입이나 회원 전체 목록 조회, 회원 1명 조회 등 실제 비즈니스 로직을 담은 패키지

이번 글에서는 service 패키지를 하나 만들고, 하위에 MemberService.java 클래스를 만들고 시작한다. 

 

2. 회원 등록, 조회

 

2.1 Service

Service는 로그인, 회원 검색 등 실제 비즈니스 서비스를 담당한다. 지금은 DB가 정해지지 않은 상황을 가정하고 java 자료형으로 메모리에 기반하여 회원의 정보를 저장했다. 회원 정보로 사용할 변수는 domain의 Member 클래스에, 그 필드를 이용해서 회원을 메모리에 등록하거나 메모리에 있는 값을 단순 조회하는 코드는 repository의 MemberRepository 인터페이스와 MemberMemoryRepository 클래스에 작성했다. 로그인, 회원 검색은 메모리(실무에서는 DB)에 저장된 정보를 인터페이스에 정의한 메소드를 통해 접근하는 방식이다. 따라서 Service 코드에는 반드시 repository를 선언해주어야 한다. 

  • MemberService.java (C)
    package hello.hellospring.service;
    
    import hello.hellospring.domain.Member;
    import hello.hellospring.repository.MemberRepository;
    import hello.hellospring.repository.MemoryMemberRepository;
    
    public class MemberService {
        // 회원 등록이나 조회 작업을 할 것
        //- 회원 정보를 가진 MemberRepository가 있어야 한다.
        private final MemberRepository memberRepository = new MemoryMemberRepository();
    
    }​

2.2 회원 등록

회원 등록은 회원 ID, 회원 이름 정보를 가지는 Member 클래스를 인자로 받아서 리포지토리에 save하는 메소드로 간단히 구현할 수 있다. 이때, 회원의 이름이 중복되지 않아야 한다는 비즈니스 로직에 맞춰서 새로 등록하는 회원과 기존에 등록된 회원의 이름이 같은지 비교하는 코드를 넣어준다. 

public class MemberService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    // 회원 가입
    //- 같은 이름이 있는 중복 회원은 가입할 수 없도록 처리
    //- 1. findByName()로 이미 등록된 회원이 있는지 조회
    //- 2. 등록된 회원이 있으면 가입 할 수 없도록 처리
    //- 3. 등록된 회원이 없으면 가입 할 수 있도록 처리
    public Long join(Member member) {

        memberRepository.findByName(member.getName())
                        .ifPresent(m -> {
                            throw new IllegalStateException("이미 존재하는 회원입니다.");
        });

        memberRepository.save(member);
        return member.getId();
    }

}

먼저 findByName(member.getName())으로 동일한 이름이 있는지 조회한다. 리턴값은 Optional <Member> 인데, Java의 Optional은 예상치못한 NullException을 처리해주는 문법이다. Optional의 ifPresent() 메소드를 사용하였다. ifPresent()는 Optional의 값이 있으면 실행되고 null이면 실행하지 않는다. 

여기서는 이름을 찾고 - 그 이름이 있으면 - IllegalStateException이라는 예외를 발생시켜서 회원 가입을 하지 못하도록 처리한다. 만약 동일한 이름이 없다면 아무 것도 실행되지 않고 바로 save(member)가 호출되어 회원 가입이 이루어진다. 

이때 새로운 메소드로 로직을 처리하는 경우에는 별도의 메소드로 분리하여 사용하는 것이 좋다. 그래서 findByName으로 검색하고 ifPresent() 검사를 하는 코드를 validateDuplictaeMember 메소드로 분리하였다. 

public class MemberService {

    private final MemberRepository memberRepository = new MemoryMemberRepository();

    public Long join(Member member) {
    
        validateDuplicateMember(member);

//        이렇게 어떤 메소드를 호출해서 로직이 발생하는 경우에는 별도의 메소드로 분리하는게 좋다.
//        memberRepository.findByName(member.getName())
//                        .ifPresent(m -> {
//                            throw new IllegalStateException("이미 존재하는 회원입니다.");
//                        });

        memberRepository.save(member);
        return member.getId();
    }

    // 중복 회원 가입 방지
    private void validateDuplicateMember(Member member) {
        // 1.
        Optional<Member> result = memberRepository.findByName(member.getName());

        // 2.
        result.ifPresent(m -> {
            throw new IllegalStateException("이미 존재하는 회원입니다. ");
        });
    }

}

 


2.3 회원 조회

회원 조회는 앞서 repository에 정의했던 findById(Long id)와 findAll() 메소드를 그대로 호출해주면 된다. findById 메소드는 그 결과가 null일 수도 있으니 Null 처리를 하기 위해 Optional<Member>를 리턴해야 한다. 

public class MemberService {

	private final MemberRepository memberRepository = new MemoryMemberRepository();

    public Long join(Member member) {
        validateDuplicateMember(member);

        memberRepository.save(member);
        return member.getId();
    }

    // 전체 회원 조회
    public List<Member> findMembers() {
        return memberRepository.findAll();
    }

    // 회원 1명 조회
    public Optional<Member> findOne(Long id) {
        return memberRepository.findById(id);
    }
}