Spring

Spring [ํšŒ์› ๊ด€๋ฆฌ / ๋ฐฑ์—”๋“œ]

DAHLIA CHOI 2021. 6. 21. 22:54

์ด๋ฒˆ์— ๋ฐฐ์šด ๊ฑด ์ข€ ์–ด๋ ต๋‹ค...๊ทธ๋ž˜๋„ ์—ด์‹ฌํžˆ ๋“ค์–ด์•ผ๊ฒ ๋‹คเน‘๏ฝฅฬ‘โ—ก๏ฝฅฬ‘เน‘

์•„์ง ๊ธฐ์ดˆ๊ณต๋ถ€ํ•˜๊ณ  ์žˆ๋Š”๋ฐ๋„ ์ž๋ฐ” ๊ณต๋ถ€์˜ ๋ถ€์กฑํ•จ์ด ํ™•์‹คํžˆ ๋А๊ปด์ง„๋‹คใ… ใ…  ๋‚ด์ผ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ž๋ฐ” ๊ณต๋ถ€๋ฅผ ํ•ด์•ผ๊ฒ ๋‹ค

 

๊ทธ๋™์•ˆ ์ž˜ ์ž‘๋™๋˜๋˜ intelliJ๊ฐ€ ๊ฐ‘์ž๊ธฐ side-by-side์—๋Ÿฌ๊ฐ€ ๋‚ฌ๋‹ค...visual c++ ๋‹ค์‹œ ๊น”๊ณ  ๊ทธ๋ž˜๋„ ์•ˆ๋ผ์„œ ์ธํ…”๋ฆฌ์ œ์ด ์ง€์šฐ๊ณ  ๋‹ค์‹œ ๊น”์•˜๋”๋‹ˆ ์•„์ฃผ ์ž˜ ์ž‘๋™ ๋๋‹ค...๋‹ค์‹  ์ด๋Ÿฐ ์ผ ๋งŒ๋“ค์ง€ ๋ง์•„๋ผ (๊ฆ°๊’ซ°)

 


์ด๋ฒˆ์— ๋ฐฐ์šด ๊ฑด ํšŒ์› ๊ด€๋ฆฌ ์˜ˆ์ œ์ด๋‹ค!

 

ํšŒ์›๊ฐ€์ž…์„ ํ•˜๊ณ , ์ค‘๋ณต๋œ ์ด๋ฆ„์€ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๊ด€๋ฆฌํ•ด์•ผํ•œ๋‹ค!

 

< ์ผ๋ฐ˜์ ์ธ ์›น ๊ณ„์ธต ๊ตฌ์กฐ >

 

์ปจํŠธ๋กค๋Ÿฌ : ์›น MVC์˜ ์ปจํŠธ๋กค๋Ÿฌ ์—ญํ• 

์„œ๋น„์Šค : ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„

๋ฆฌํฌ์ง€ํ† ๋ฆฌ : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผ. ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ DB์— ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌ

๋„๋ฉ”์ธ : ๋น„์ฆˆ๋‹ˆ์Šค ๋„๋ฉ”์ธ ๊ฐ์ฒด

 

 

1. ํšŒ์› ๋„๋ฉ”์ธ ์ƒ์„ฑ

main - java - hellospring์— domainํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๊ณณ์— Member ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

package hello.hellospring.domain;

public class Member {

    private Long id; //๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•ด ์‹œ์Šคํ…œ์ด ์ง€์ •ํ•œ ์•„์ด๋””
    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;
    }
}

 

get, set์œผ๋กœ id์™€ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ค€๋‹ค! ์ž๋ฐ”๋ฅผ ๋ฐฐ์šธ๋• ๋ชฐ๋ž์—ˆ๋Š”๋ฐ ์ €๋ ‡๊ฒŒ ์‹ค์ œ๋กœ ์ง€์ •ํ•ด์ฃผ๋‹ˆ๊นŒ ๋ญ”๊ฐ€๋ฅผ ๋งŒ๋“ค๊ณ  ์žˆ๋‹ค๋Š” ๋А๋‚Œ์ด ํ™• ๋“ ๋‹ค.

 

์—ฌ๊ธฐ์„œ id๋Š” ํšŒ์›์ด ์นœ ์•„์ด๋””๊ฐ€ ์•„๋‹Œ ์‹œ์Šคํ…œ์ด ์ง€์ •ํ•œ ์•„์ด๋””์ด๋‹ค.

 

2. ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค

member repository๋ฅผ ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์„ค๊ณ„ํ•œ๋‹ค. repository๋Š” ์ €์žฅ์†Œ ๊ฐœ๋…์ด๋‹ค.

domain ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์—ˆ๋˜ ์œ„์น˜์— repositoryํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๊ณณ์— MemberRepository ์ธํ„ฐํŽ˜์ด์Šค ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์ค€๋‹ค.

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<Member> findByName(String name);
    List<Member> findAll();
}

 

์—ฌ๊ธฐ์„œ id๋‚˜ name์ด ์—†์„๋•Œ null์ด ๋ฐ˜ํ™˜๋˜๋Š”๋ฐ ์š”์ฆ˜์€ null์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  optional๋กœ ๊ฐ์‹ธ์„œ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์„ ์„ ํ˜ธํ•œ๋‹ค๊ณ  ํ•œ๋‹ค. 

 

3. ํšŒ์› ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌํ˜„์ฒด

 

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import java.util.*;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

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());
    }

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

MemberRepository๋ฅผ ์ƒ์†๋ฐ›์€ MemoryMemberRepository ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

 

 

์ด๋ ‡๊ฒŒ ๋งŒ๋“ค๋ฉด ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ด์•ผ๋œ๋‹ค!! ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ž˜ ์ž‘๋™์ด ๋˜๋Š”์ง€ ์‹คํ–‰ํ•ด๋ณธ๋‹ค.

 

4. ํšŒ์›๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๊ตฌํ˜„์ฒด ํ…Œ์ŠคํŠธ

 

src - test - java - hello.hellospring ์— repository ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค๊ณ  MemoryMemberRepositoryTest ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ ๋‹ค.

package hello.hellospring.repository;

import hello.hellospring.domain.Member;
import org.assertj.core.api.AbstractBigDecimalAssert;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.*;

public class MemoryMemberRepositoryTest {

    MemberRepository repository = new MemoryMemberRepository();
    
    @Test
    public void save() {
        Member member = new Member();
        member.setName("spring");

        repository.save(member);
        Member result = repository.findById(member.getId()).get();
        assertThat(member).isEqualTo(result);
    }

    @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);
    }
}

 

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด 

๋ชจ๋‘ ์ดˆ๋ก์ƒ‰์ฒดํฌ๊ฐ€ ๋œจ๋ฉด์„œ ํ†ต๊ณผ๋˜๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

ํ•˜์ง€๋งŒ ๋น„๊ต๋ฅผ null๋กœ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด 

์ด๋ ‡๊ฒŒ ์˜ค๋ฅ˜๊ฐ€ ๋œฌ๋‹ค!

name์˜ ๊ฒฝ์šฐ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. 

 

์ „์ฒด ๋ช‡๋ช…์˜ ํšŒ์›์ธ์ง€ ์ฐพ๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด๋ณด์ž

    @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);
    }

ํ•˜์ง€๋งŒ ์ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ „์ฒด ์‹คํ–‰์„ ํ•˜๊ฒŒ ๋์„ ๊ฒฝ์šฐ์— ๊ฐœ๋ณ„๋กœ๋Š” ์ž˜ ์ž‘๋™ํ•˜๋˜ ์ฝ”๋“œ๊ฐ€ ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค.

๋ถ„๋ช… ์ž˜ ๋Œ์•„๊ฐ€๋˜ ์ฝ”๋“œ๊ฐ€ ํ•œ๋ฒˆ์— ๋Œ๋ฆฌ๋‹ˆ๊นŒ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธด๋‹ค!

findAll์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์žฅ ๋‚˜์ค‘์— ์ž‘์„ฑํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์€ ์ˆœ์„œ๊ฐ€ ๋ณด์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋ฉ”์„œ๋“œ๋ณ„๋กœ ๋”ฐ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ์„ค๊ณ„๋œ๋‹ค. 

์œ„๋ฅผ ๋ณด๋ฉด findAll์ด ๋จผ์ € ์‹คํ–‰์ด ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์—  spring ์ด๋ฆ„์ด ์ €์žฅ๋˜์–ด๋ฒ„๋ ค์„œ ๊ทธ ๋‹ค์Œ findByName์ด ์‹คํ–‰๋  ๋•Œ ์˜ค๋ฅ˜๊ฐ€ ์ƒ๊ธด๋‹ค!

๋˜ํ•œ ํ…Œ์ŠคํŠธ๋Š” ์˜์กด๊ด€๊ณ„์—†์ด ํ†ต๊ณผ๋˜์–ด์•ผํ•˜๊ฒŒ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ ํ…Œ์ŠคํŠธ๊ฐ€ ๋๋‚˜๊ณ ๋‚˜๋ฉด ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ฆฌ์–ดํ•ด์ค˜์•ผํ•œ๋‹ค. 

์ €์žฅ์†Œ๋‚˜ ๊ณต์šฉ๋ฐ์ดํ„ฐ๋ฅผ ์ง€์šฐ๋Š” ์ฝ”๋“œ๋ฅผ ์จ์ฃผ์—ˆ๋‹ค!

 

    MemoryMemberRepository repository = new MemoryMemberRepository();
    //MemoryMemberRepository๋งŒ ์‹คํ–‰ํ•˜๋Š” ๊ฑฐ๋‹ˆ๊นŒ ์•ž์— ์žˆ๋˜ MemberRepository์—์„œ MemoryMemberRepository๋กœ ๋ฐ”๊ฟˆ

    @AfterEach // ๋ฉ”์„œ๋“œ ๋๋‚ ๋•Œ๋งˆ๋‹ค ๋™์ž‘ํ•˜๋Š” ๊ฑฐ
    public void afterEach(){
        repository.clearStore();
    }

์œ„์— ์ €์žฅ๋˜์–ด์žˆ๋˜ MemoryMemberRepository๋ฅผ ์‹คํ–‰ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์— MemberRepository์—์„œ MemoryMemberRepository๋กœ ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.

 

์ž˜ ์ž‘๋™๋œ๋‹ค !_!

 

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

domain์„ ๋งŒ๋“ค์—ˆ๋˜ ๊ณณ์— ์ƒˆ๋กœ์šด ํŒจํ‚ค์ง€๋ฅผ ๋งŒ๋“ค์–ด์ค€๋‹ค.

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;

import java.util.List;
import java.util.Optional;

public class MemberService {

    //private  final MemberRepository memberRepository = new MemoryMemberRepository();
    //๋ฐ”๊พธ๊ธฐ ์ „์— ์“ด ์ฝ”๋“œ
    private  final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository){
        this.memberRepository = memberRepository;
    }//๋ฉค๋ฒ„์„œ๋น„์Šค ์ž…์žฅ์—์„œ ๋ณด๋ฉด ๋ฉค๋ฒ„๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์™ธ๋ถ€์—์„œ ๋„ฃ์–ด์คŒ = DI (Dependency Injection)

    /**
     * ํšŒ์›๊ฐ€์ž…
     */
    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(("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."));
                });
    }

    /**
     * ์ „์ฒด ํšŒ์› ์กฐํšŒ
     */
    public List<Member> findMembers(){
        return memberRepository.findAll();
    }

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

 

์—ฌ๊ธฐ์„œ๋„ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด์ค€๋‹ค!

์œ„์— ํด๋ž˜์Šค ์ด๋ฆ„์„ ํด๋ฆญํ•œ ๋‹ค์Œ์— shift + ctrl + T๋ฅผ ๊ฐ™์ด ๋ˆŒ๋Ÿฌ์ฃผ๋ฉด class test๊ฐ€ ์ €์ ˆ๋กœ ์ƒ์„ฑ๋œ๋‹ค!!!!

 

 

package hello.hellospring.service;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemoryMemberRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.*;

class MemberServiceTest {

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

    MemberService memberService;
    MemoryMemberRepository memberRepository;

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

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

    @Test
    void ํšŒ์›๊ฐ€์ž… () {
        //given
        Member member = new Member();
        member.setName("spring");

        //when
        Long saveId = memberService.join(member);

        //then
       Member findMember = memberService.findOne(saveId).get();
       assertThat(member.getName()).isEqualTo(findMember.getName());

        //๋ญ”๊ฐ€๊ฐ€ ์ฃผ์–ด์กŒ๋Š”๋ฐ ์ด๋Ÿฐ๊ฑธ ์‹คํ–‰ํ–ˆ์„๋•Œ ๊ฒฐ๊ณผ๊ฐ€ ์ด๋ ‡๊ฒŒ ๋‚˜์™€์•ผ๋ผ ์ด๋Ÿฐ ํ˜•์‹์œผ๋กœ ๋งŒ๋“ค๊ธฐ

    }

    @Test
    public void ์ค‘๋ณต_ํšŒ์›_์˜ˆ์™ธ(){
        //given
        Member member1 = new Member();
        member1.setName("spring");

        Member member2 = new Member();
        member2.setName("spring");

        //when
        memberService.join(member1);
        IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));

        assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
        /*
        try{
            memberService.join(member2);
            fail();
        }catch(IllegalStateException e){
            assertThat(e.getMessage()).isEqualTo("์ด๋ฏธ ์กด์žฌํ•˜๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค.");
        }
        */

        //then
    }

    @Test
    void findMembers() {
    }

    @Test
    void findOne() {
    }
}

์ „์— ๋งŒ๋“ค์—ˆ๋˜ ์ฝ”๋“œ(์ฃผ์„์ฒ˜๋ฆฌํ•œ ์ฝ”๋“œ)๋Š” ์ด๋ฆ„์€ ๊ฐ™์ง€๋งŒ ๋‹ค๋ฅธ ๋ฉค๋ฒ„๋ฆฌํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค.

@BeforeEach ๋ฅผ ์ ์œผ๋ฉด ๊ฐ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์ „์— ํ˜ธ์ถœ์ด ๋˜๊ณ , ํ…Œ์ŠคํŠธ๊ฐ€ ์„œ๋กœ ์˜ํ–ฅ์ด ์—†๋„๋ก ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์˜์กด๊ด€๊ณ„๋ฅผ ์ƒˆ๋กœ ๋งบ์–ด์ค€๋‹ค.

 


์œผ์•„...์ ์  ์–ด๋ ค์›Œ์ง€๋Š” ๊ฒƒ ๊ฐ™๋‹ค..๋‚˜ ์ •๋ง ๊ฐˆ ๊ธธ์ด ๋ฉ€๊ตฌ๋‚˜!!!!

๊ทธ๋ž˜๋„ ํšŒ์› ์„œ๋น„์Šค๋ฅผ ์ด๋Ÿฐ์‹์œผ๋กœ ๋งŒ๋“ ๋‹ค๋Š”๊ฒŒ ์‹ ๊ธฐํ•˜๋‹ค ์›น์‚ฌ์ดํŠธ ์–ผ๋ฅธ ๋งŒ๋“ค์–ด๋ณด๊ณ  ์‹ถ๋‹ค( *เธ…ฬห˜เธ…ฬ€*)