728x90
우선, 비즈니스 요구 사항을 정리한다
- 데이터 : 회원 ID, 이름
- 기능 : 회원 등록, 조회
- DB는 선정되지 않음(이라고 가정)
- 컨트롤러 : 웹 MVC의 컨트롤 역할
- 서비스 : 핵심 비즈니스 로직 구현
- 리포지토리 : DB에 접근, 도메인 객체를 DB에 저장하고 관리
- 도메인 : 비즈니스 도메인 객체 (ex. 회원, 주문, 쿠폰 등 주로 DB에 저장되고 관리됨)
- 아직 데이터 저장소가 선정되지 않아서, 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계(MemberRepository)
- 데이터 저장소는 RDB, NoSQL 등등 다양한 저장소를 고민중인 상황으로 가정(개발을 진행하기 위해서 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용)
---------------------------------------------------------------------------------------------------
도메인 - Member
리포지토리 - MemberRepository(interface)
리포지토리 - MemoryMemberRepository (inferface 상속 받아서 구현)
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.*;
// 리포지토리는 개발적인(?) naming 사용
/**
* 동시성 문제가 고려되어 있지 않음, 실무에서는 ConcurrentHashMap, AtomicLong 사용 고려
*/
public class MemoryMemberRepository implements MemberRepository{
// map<key,value>
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)); //get이 null이어도 괜찮게 만들어주는 것
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name)) // 람다식 이용, 루프를 돌면서
// 넘어온 name과 동일한거 필터링
.findAny(); // 그리고 찾아지면 바로 return, optional로
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
} // values는 멤버들
public void clearStore(){
store.clear();
}
}
서비스 - MemberService
package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import java.util.List;
import java.util.Optional;
// 보통 서비스 클래스의 name은 비지니스에 가깝게 naming 해야 함
public class MemberService {
private final MemberRepository memberRepository;
// 회원 서비스 코드를 DI(의존성 주입) 가능하게 변경한다.
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
/**
* 회원 가입
*/
public Long join(Member member){
// 가정) 같은 이름을 가진 중복 회원 x
validateDuplicateMember(member);
memberRepository.save(member);
return member.getId();
}
private void validateDuplicateMember(Member member){
memberRepository.findByName(member.getName()) // findByName의 리턴타입은 optional
// 만약 findByName의 리턴값이 null이 아니라 뭐가 있으면
// throw
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
/**
* 전체 회원 조회
*/
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
}
그리 어렵지 않은 예제라서 자바를 조금 다뤄봤다면 금방 이해할 수 있을 것이다.
다음 포스팅에서는 회원 리포지토리와 서비스에 대한 테스트 코드를 살펴보자.
728x90
'스프링(JAVA)' 카테고리의 다른 글
스프링 DB 접근 기술 #1 JDBC, JDBC Template (0) | 2022.09.25 |
---|---|
Spring 웹mvc 간단 회원 관리 예제(홈 화면, 등록, 조회) (0) | 2022.09.25 |
Spring 스프링 빈과 의존관계 (0) | 2022.09.25 |
Spring 회원 관리 예제 - 테스트 코드 (0) | 2022.09.25 |
Spring 입문 (0) | 2022.07.12 |