본문 바로가기

WINK-(Web & App)/Spring Boot 스터디

[2025 1학기 스프링부트 스터디] 류현준 #3&4주차

반응형

섹션 4.  회원 관리 예제-백엔드 개발

 

비즈니스 요구사항 정리

데이터: 회원ID,이름

기능: 회원 등록,조회

아직 데이터 저장소가 선정되지 않음(가상의 시나리오)

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

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

서비스: 핵심 비즈니스 로직 구현

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

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

DB: 실제 데이터들이 저장되는 곳

클래스 의존관계

아직 데이터 저장소가 선정되지 않아 인터페이스로 구현클래스를 변경할 수 있도록 설계

데이터 저장소는 RDB,NoSQL 등 다양한 저장소 고민

초기 개발 단계에서 구현체로 가벼운 메모리 기반 DB사용

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

 

Member save(Member member): 회원 저장

Optional<Member> findById(Long id):ID로 회원을 찾음

Optional<Member> findByName(String name):회원 이름을 찾음

List<Member> findAll():저장소에 있는 모든 회원 목록 반환

값이 없을 수도 있는 경우 optional 사용

회원 리포지토리 테스트 케이스 작성

command+shift+enter: 바로 다음줄로 넘어가짐

package hello.hello.spring.repository;
import hello.hello.spring.domain.Member;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.*;
class MemoryMemberRepositoryTest {
    MemoryMemberRepository repository = new MemoryMemberRepository();
    @AfterEach
    public void afterEach() {
        repository.clearStore();
    }
    @Test
    public void save() {
//given
        Member member = new Member();
        member.setName("spring");
//when
        repository.save(member);
//then
        Member result = repository.findById(member.getId()).get();
        assertThat(result).isEqualTo(member);
    }
    @Test
    public void findByName() {
//given
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);
        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);
//when
        Member result = repository.findByName("spring1").get();
//then
        assertThat(result).isEqualTo(member1);
    }
    @Test
    public void findAll() {
//given
        Member member1 = new Member();
        member1.setName("spring1");
        repository.save(member1);
        Member member2 = new Member();
        member2.setName("spring2");
        repository.save(member2);
//when
        List<Member> result = repository.findAll();
//then
        assertThat(result.size()).isEqualTo(2);
    }
}

MemoryMemberRepositoryTest는 MemoryMemberRepository 클래스의 단위 테스트를 위한 테스트 클래스

@AfterEach는 각 테스트가 끝난 후마다 실행되는 메서드를 지정

save() 메서드가 Member 객체를 제대로 저장하는지 테스트

findByName() 메서드가 제대로 동작하는지 테스트

findAll() 메서드가 저장된 모든 회원을 제대로 반환하는지 테스트

회원 서비스 개발 

public Long join(Member member) {
    validateDuplicateMember(member); //중복 회원 검증 memberRepository.save(member);
    return member.getId();
}

중복되는 회원이 있는지 검증

   public List<Member> findMembers() {
        return memberRepository.findAll();
    }
    public Optional<Member> findOne(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

전체 회원 조회

회원 서비스 테스트

 

command+shift+t 테스트 생성 단축키

@BeforeEach
public void beforeEach() {
    memberRepository = new MemoryMemberRepository();
    memberService = new MemberService(memberRepository);
}

독립적 환경을 만들어줌

@AfterEach
public void afterEach() {
    memberRepository.clearStore();
}

저장된 데이터를 삭제해서 다음 테스트가 이전 테스트에 영향을 주지 않도록 함

extract method를 할때 뭔가 잘못해서 오류가 떴었지만 수정을 한 뒤 잘 돌아가는 모오습~

 

섹션 5.  스프링 빈과 의존관계

컴포넌트 스캔과 자동 의존관계 설정

컨트롤러 파일 생성

 

    @Autowired
    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }
}

생성자에 Autowired로 되어 있으면 멤버서비스를 스피링이 스프링 컨테이너에 있는 멤버 서비스를 가져다가 연결을 시켜줌

 

오류 발생

MemberService가 순수 자바코드기 때문

@Service를 위에 입력해주면 스프링컨테이너에 멤버 서비스를 등록해줌

 

의존성 주입 (Dependency Injection, DI)

의존성 주입(Dependency Injection)은 소프트웨어 디자인 패턴의 하나로 객체가 필요로 하는 의존성(다른 객체)을 직접 생성하거나 찾지 않고, 외부로부터 제공(주입)받는 방식을 의미. 이는 객체 간의 결합도를 낮추고 코드의 재사용성, 테스트 용이성, 유지보수성을 향상시키는 중요한 원칙이다.

@Autowired 어노테이션을 생성자에 붙여서 스프링 컨테이너에게 해당 타입의 빈을 찾아 생성 시점에 주입하도록 지시.

자바 코드로 직접 스프링 빈 등록하기

package hello.hello.spring.service;

import hello.hello.spring.repository.MemberRepository;
import hello.hello.spring.repository.MemoryMemberRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SpringConfig {

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository());
    }

    @Bean
    public MemberRepository memberRepository() {
        return new MemoryMemberRepository();
    }
}

DI에는 필드 주입, setter 주입, 생성자 주입 이렇게 3가지 방법이 있다. 의존관계가 실행중에 동적으 로 변하는 경우는 거의 없으므로 생성자 주입을 권장.

주의: @Autowired를 통한 DIhelloController, memberService 등과 같이 스프링이 관리하 는 객체에서만 동작한다. 스프링 빈으로 등록하지 않고 내가 직접 생성한 객체에서는 동작하지 않는다.

반응형