[Spring ์ž…๋ฌธ] 3. ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ

2023. 9. 25. 16:49ยท๐Ÿฅ Web/โ›… Back-end | Spring
728x90

1. ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ ์ •๋ฆฌ

  • ๋ฐ์ดํ„ฐ
    • ํšŒ์› ID
    • ์ด๋ฆ„
  • ๊ธฐ๋Šฅ
    • ํšŒ์› ๋“ฑ๋ก
    • ์กฐํšŒ
  • ์•„์ง DB ์„ ์ •ํ•˜์ง€ ์•Š์€ ์ƒํ™ฉ ← ์ด๋ผ๋Š” ์„ค์ •

  • ์ปจํŠธ๋กค๋Ÿฌ : ์›น MVC์˜ ์ปจํŠธ๋กค๋Ÿฌ (API ์ƒ์„ฑ ๋“ฑ)
  • ์„œ๋น„์Šค : ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
  • ๋„๋ฉ”์ธ : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ / ๊ด€๋ฆฌ๋˜๋Š” ๊ฒƒ
  • ๋ฆฌํฌ์ง€ํ† ๋ฆฌ : ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ์ ‘๊ทผ / ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ DB์— ์ €์žฅ ๋ฐ ๊ด€๋ฆฌ

  • ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๊ตฌํ˜„ ํด๋ž˜์Šค ๋ณ€๊ฒฝ ๊ฐ€๋Šฅํ•˜๊ฒŒ ์„ค๊ณ„(DB ์„ ์ • ์•ˆ ํ•จ)
    • ๊ตฌํ˜„์ฒด๋กœ ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜์˜ ๊ฐ€๋ฒผ์šด ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ๋กœ ๊ฐœ๋ฐœ ์ง„ํ–‰

2. ํšŒ์› ๋„๋ฉ”์ธ๊ณผ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋งŒ๋“ค๊ธฐ

1. Member ํด๋ž˜์Šค ์ƒ์„ฑ

package hello.hellospring.domain;

public class Member {
    private Long id; // database index์— ๊ฐ€๊นŒ์›€
    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;
    }
}

2. Member ๊ด€๋ฆฌ repository interface ์„ ์–ธ

package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.List;
import java.util.Optional;

public interface MemberRepository {
    Member save(Member member);
    Optional<Member> findById(Long id); // Optional = nullable, ์—†์„ ์ˆ˜ ์žˆ์Œ
    Optional<Member> findByName(String name);
    List<Member> findAll();
}

3. Member ๊ด€๋ฆฌ repository ๊ตฌํ˜„์ฒด

package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import java.util.*;
public class MemoryMemberRepository implements MemberRepository{
    // id, object
    private static Map<Long, Member> store = new HashMap<>();
    // key ๊ฐ’ ์ƒ์„ฑ
    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)); // nullable, ์—†์„ ์ˆ˜ ์žˆ์Œ. 
    }

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

    @Override
    public Optional<Member> findByName(String name) {
        return store.values().stream() // store์˜ ๋‚ด์šฉ๋“ค ์ค‘์—์„œ
                .filter(member -> member.getName().equals(name)) // name์ด ๊ฐ™์œผ๋ฉด
                .findAny();
    }
	// = select * from store where name = {name};

    public void clearStore() {
        store.clear();
    }
}

 

3. ํšŒ์› ๋ ˆํฌ์ง€ํ† ๋ฆฌ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค ์ž‘์„ฑ

  • ์ฝ”๋“œ๋ฅผ ์ฝ”๋“œ๋กœ ๊ฒ€์ฆ!
  • Java์—์„œ๋Š” JUnit ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋„๋ก ํ•จ.
package hello.hellospring.repository;

import hello.hellospring.domain.Member;
//import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;

class MemoryMemberRepositoryTest {

    MemberRepository repository = new MemoryMemberRepository();

    @Test
    public void save() {
        Member member = new Member();
        member.setName("sprint");

        repository.save(member);

        Member result = repository.findById(member.getId()).get();
//        System.out.println("result = " + (result == member));
//        Assertions.assertEquals(result, member);
        assertThat(member).isEqualTo(result);
    }

}
  • assertion That์ด junit ์˜ Assertion์œผ๋กœ๋Š” ํ˜ธํ™˜๋˜์ง€ ์•Š์Œ
  • import static org.assertj.core.api.Assertions.assertThat; ์œผ๋กœ ํ•ด๊ฒฐ ๊ฐ€๋Šฅ

@Test
public void findByName() {
    Member member1 = new Member();
    member1.setName("spring1");
    repository.save(member1);

    Member member2 = new Member();
    member2.setName("spring2");
    repository.save(member2);

    Member result = repository.findByName("spring1").get();

    assertThat(result).isEqualTo(member1);
}
@Test
public void findAll() {
    Member member1 = new Member();
    member1.setName("spring1");
    repository.save(member1);

    Member member2 = new Member();
    member2.setName("spring2");
    repository.save(member2);

    List<Member> result = repository.findAll();

    assertThat(result.size()).isEqualTo(2);
}
test์˜ method ์‹คํ–‰ ์ˆœ์„œ๋Š” ๋žœ๋ค → ๋ชจ๋‘ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜๋„๋ก ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ…Œ์ŠคํŠธ ํ›„ repository(๋“  ๋ญ๋“ )๋ฅผ ํด๋ฆฌ์–ดํ•ด์ค˜์•ผํ•จ.
// MemoryMemberRepository.java
...
public void clearStore() {
        store.clear();
}
  • ์ €์žฅ๋œ ๊ฐ์ฒด๋ฅผ ์‹น ๋น„์›Œ์ฃผ๋Š” ์ฝ”๋“œ
@AfterEach
public void afterEach() {
    repository.clearStore();
}

TDD ⇒ Test ์ฃผ๋„ ๊ฐœ๋ฐœ, ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋จผ์ € ๋งŒ๋“ค๊ณ  ๋‚˜์„œ ๊ตฌํ˜„์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ.

 

4. ํšŒ์› ์„œ๋น„์Šค ๊ฐœ๋ฐœ

public Long join(Member member) {
      // ๋ฉค๋ฒ„ ์ด๋ฆ„ ์ค‘๋ณต ๋ฐฉ์ง€
      memberRepository.findByName(member.getName())
                .ifPresent(m -> {
                    throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
                });;
      memberRepository.save(member);
      return member.getId();
  }
  • ifPresent = ์กด์žฌํ•œ๋‹ค๋ฉด ์ดํ›„ function ์‹คํ–‰
  • ์ข€ ๋” ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋ฉ”์†Œ๋“œ๋กœ ๋นผ๋‚ด๋ฉด
public Long join(Member member) {
    // ๋ฉค๋ฒ„ ์ด๋ฆ„ ์ค‘๋ณต ๋ฐฉ์ง€
    validateDuplicateMember(member);
    memberRepository.save(member);
    return member.getId();
}
private void validateDuplicateMember(Member member) {
    memberRepository.findByName(member.getName())
            .ifPresent(m -> {
                throw new IllegalStateException("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
            });
}
  • ๋‚˜๋จธ์ง€ find ๊ด€๋ จ ์„œ๋น„์Šค ๊ตฌํ˜„
// select all members
public List<Member> findMembers() {
    return memberRepository.findAll();
}

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

 

5. ํšŒ์› ์„œ๋น„์Šค ํ…Œ์ŠคํŠธ

  • ํด๋ž˜์Šค ์ด๋ฆ„ → Control + Shift + T ํ•˜๋ฉด ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธ ์ƒ์„ฑ

  • !? ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ํ•จ์ˆ˜ ์ด๋ฆ„ ํ•œ๊ธ€๋กœ ์จ๋„ ๋จ
  • given / when / then ๊ตฌ๋ฌธ์œผ๋กœ ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
    • ์ฃผ์–ด์ง„ input์„ ๋ฐ›์•˜์„ ๋•Œ → when ์ด๋ผ๋Š” ์ผ€์ด์Šค์— ๋Œ€ํ•ด์„œ → then์ด๋ผ๋Š” ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋„๋ก
class MemberServiceTest {

    MemberService memberService = new MemberService(memberRepository);
    MemoryMemberRepository memberRepository = new MemoryMemberRepository();

...
  • member service์—์„œ new MemberService() ๋งŒ์œผ๋กœ ์ƒ์„ฑ์„ ํ•˜๋ฉด ์œ„์—์„œ ๋งŒ๋“  memberRepository ์™€๋Š” ๋‹ค๋ฅธ repository๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋จ.
    • ๋‹น์žฅ์€ MemoryMemberRepository์˜ store ๊ฐ€ static์ด๋ผ ๊ดœ์ฐฎ์ง€๋งŒ ์•„๋‹ˆ๋ฉด ๋ฌธ์ œ๋จ
  • Member Service์—์„œ ์ƒˆ๋กœ MemberRepository๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ฐ›์•„์™€์„œ service๋ฅผ ๊ตฌ๋™ํ•˜๊ฒŒ ๋˜๋ฉด ๊ฐ™์€ repository๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๊ฒ ์ฃ ?
public class MemberService {

		// ๊ธฐ์กด 
		// private final MemberRepository memberRepository = new MemoryMemberRepository();

		// ๋ณ€๊ฒฝ
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }
  • ์•„๋ž˜์™€ ๊ฐ™์ด ์™ธ๋ถ€์—์„œ ๋„ฃ์–ด์ฃผ๋„๋ก ์„ค๊ณ„ํ•˜๋Š” ๊ฒƒ์„ Dependency Injection(์˜์กด์„ฑ ์ฃผ์ž…) ์ด๋ผ๊ณ  ๋ถ€๋ฆ„
class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memberRepository;

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

    @AfterEach
    public void afterEach() {
        memberRepository.clearStore();
    }
728x90
์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'๐Ÿฅ Web > โ›… Back-end | Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Spring ์ž…๋ฌธ] 5. ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - ์›น MVC ๊ฐœ๋ฐœ  (0) 2023.09.25
[Spring ์ž…๋ฌธ] 4. ์Šคํ”„๋ง ๋นˆ๊ณผ ์˜์กด๊ด€๊ณ„  (0) 2023.09.25
[Spring ์ž…๋ฌธ] 2. ์Šคํ”„๋ง ์›น ๊ฐœ๋ฐœ ๊ธฐ์ดˆ  (0) 2023.06.30
[Spring ์ž…๋ฌธ] 1. ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ ์„ค์ •  (0) 2023.06.29
'๐Ÿฅ Web/โ›… Back-end | Spring' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Spring ์ž…๋ฌธ] 5. ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - ์›น MVC ๊ฐœ๋ฐœ
  • [Spring ์ž…๋ฌธ] 4. ์Šคํ”„๋ง ๋นˆ๊ณผ ์˜์กด๊ด€๊ณ„
  • [Spring ์ž…๋ฌธ] 2. ์Šคํ”„๋ง ์›น ๊ฐœ๋ฐœ ๊ธฐ์ดˆ
  • [Spring ์ž…๋ฌธ] 1. ํ”„๋กœ์ ํŠธ ํ™˜๊ฒฝ ์„ค์ •
darly213
darly213
ํ˜ธ๋ฝํ˜ธ๋ฝํ•˜์ง€ ์•Š์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ณด์ž
  • darly213
    ERROR DENY
    darly213
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (97)
      • ๐Ÿฌ ML & Data (50)
        • ๐ŸŒŠ Computer Vision (2)
        • ๐Ÿ“ฎ Reinforcement Learning (12)
        • ๐Ÿ“˜ ๋…ผ๋ฌธ & ๋ชจ๋ธ ๋ฆฌ๋ทฐ (8)
        • ๐Ÿฆ„ ๋ผ์ดํŠธ ๋”ฅ๋Ÿฌ๋‹ (3)
        • โ” Q & etc. (5)
        • ๐ŸŽซ ๋ผ์ดํŠธ ๋จธ์‹ ๋Ÿฌ๋‹ (20)
      • ๐Ÿฅ Web (21)
        • โšก Back-end | FastAPI (2)
        • โ›… Back-end | Spring (5)
        • โ” Back-end | etc. (9)
        • ๐ŸŽจ Front-end (4)
      • ๐ŸŽผ Project (8)
        • ๐ŸงŠ Monitoring System (8)
      • ๐Ÿˆ Algorithm (0)
      • ๐Ÿ”ฎ CS (2)
      • ๐Ÿณ Docker & Kubernetes (3)
      • ๐ŸŒˆ DEEEEEBUG (2)
      • ๐ŸŒ  etc. (8)
      • ๐Ÿ˜ผ ์‚ฌ๋‹ด (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ๋ฐฉ๋ช…๋ก
    • GitHub
    • Notion
    • LinkedIn
  • ๋งํฌ

    • Github
    • Notion
  • ๊ณต์ง€์‚ฌํ•ญ

    • Contact ME!
  • 250x250
  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.3
darly213
[Spring ์ž…๋ฌธ] 3. ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ - ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”