第3節.メンバー管理の例-バックエンド開発

6499 ワード

ビジネスニーズの整理


データ:メンバーid、名前
機能:会員登録、照会
データストレージが選択されていません(仮想スキーマ)

コントローラ:Web MVCのコントローラロール
サービス:重要なビジネスロジックの実装
≪リポジトリ|Library|oem_src≫:データベースにアクセスし、ドメイン・オブジェクトをデータベースに保存して管理します.
≪ドメイン|Domain|ldap≫:ビジネス・ドメイン・オブジェクトの例)主にデータベースに保管および管理されるメンバー、受注およびクーポン.

まずメモリ実装体を作成し,後でrdb/jpaなどの具体的な技術を選定して置き換える.これを実現するためには,インタフェースで実現する必要がある.
  • はまだ選択されていないため、
  • を設計し、まず実装クラスをインタフェースに変更することができる.
  • データストアがRDB、NoSQLなどの複数のリポジトリの使用を検討していると仮定する
  • は開発初期段階で実装体であり、メモリベースのデータ・リポジトリを使用する(
  • )

    メンバードメインとリポジトリの作成


    java/hello.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;
        }
    }
    
    main/java/hello.hellospring.repository/MemberRepository
    package hello.hellospring.repository;
    
    import hello.hellospring.domain.Member;
    
    import java.util.Optional;
    
    public interface MemberRepository {
        Member save(Member member);
        // java8에 들어가있는 기능. null 값을 반환할 때 optional로 감싸서 반환한다.
        Optional<Member> findById(Long id);
        Optional<Member> findByName(String name);
        List<Member> findAll();
    }
    
    main/java/hello.hellospring.repository/MemoryMemberRepository
    package hello.hellospring.repository;
    
    import hello.hellospring.domain.Member;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Optional;
    
    public class MemoryMemberRepository  implements MemberRepository{
    
        private static Map<Long, Member>store= new HashMap<>();
        private static longsequence= 0L;
    
        @Override
        public Member save(Member member) {
            member.setId(++sequence);
    store.put(member.getId(), member);
            return member;
        }
    
        @Override
        public Optional<Member> findById(Long id) {
            // null 이 반환될 가능성이 있으면 optional로 감싸서 반환. 그러면 client에서 다른 것을 할 수 있다.
            return Optional.ofNullable(get(id));
        }
    
        @Override
        public Optional<Member> findByName(String name) {
            returnstore.values().stream()
                .filter(member -> member.getName().equals((name)))
                .findAny();
        }
    
        @Override
        public List<Member> findAll() {
            return new ArrayList<>(store.values());
        }
    }
    

    会員リポジトリのテストケースの作成


    テスト時にmainメソッドで実行するか、Webアプリケーションのコントローラで実行します.この場合、繰り返し実行、複数回のテストは同時に実行することが難しく、時間がかかります.Javaは、JUnitというフレームワークを使用してテストを実行し、問題を解決します.
    クラス範囲内で回転すると、すべてのテストが一度に開始されます.
    package hello.hellospring.repository;
    
    import hello.hellospring.domain.Member;
    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 {
    
         MemoryMemberRepository repository = new MemoryMemberRepository();
    // 테스터기는 순서가 보장이 안됨. 그렇기 때문에 각 메소드별로 따로 움직여야된다.
    // 객체를 중복하게 사용하지 않기 위해서 매번 해제 시켜줘야한다.
    // MemoryMemberRepository 클래스에 추가.
    /* public void clearStore() {
    *        store.clear();
    *    }
    */
         @AfterEach
         public void afterEach() {\
            repository.clearStore();
         }
         @Test
        public void save() {
            Member member = new Member();
            member.setName("spring");
    
            repository.save(member);
    
            Member result = repository.findById(member.getId()).get();
    //        System.out.println("result = " + (result == member));
    //         println으로 매번 확인 할 수 없어서 Assertion으로 확인한다. 출력되는 것은 없음. 다를 경우, expected값이 무엇인데 actual은 다른 값이 나왔다고 나옴.
    //         Assertions.assertEquals(result, member);
    //         option +_enter누르면 static으로 Assertions를 선언가능하다. 그러면 다음부터 Assertions.assert~라고 안쓰고 뒷부분만 사용하면 됨.
    assertThat(member).isEqualTo(result);
         }
    
         @Test
        public void findByName() {
             Member member1 = new Member();
             member1.setName("spring1");
             repository.save(member1);
    
    //         shift+F6 하면 리네임, 리팩토링 가능
             Member member2 = new Member();
             member2.setName("spring2");
             repository.save(member2);
    
             Member result = repository.findByName("spring1").get();
    
    assertThat(result).isEqualTo(member1); // true
    assertThat(result).isEqualTo(member2); // false();
         }
    
         @Test
        public void findAll() {
             Member member1 = new Member();
             member1.setName("spring1");
             repository.save(member1);
    
    //         shift+F6 하면 리네임, 리팩토링 가능
             Member member2 = new Member();
             member2.setName("spring2");
             repository.save(member2);
    
             List<Member> result = repository.findAll();
    
    assertThat(result.size()).isEqualTo(2); // true
    assertThat(result.size()).isEqualTo(3); // false
         }
    }
    
    まずテストを作成し,次に実装クラスを作成して変換する開発をTDDと呼ぶ.実装クラスを先に作成してテストしたのでTDDではありません.
    gradleでtestをクリックし、すべてのテストを一度に返します.職ごと