스프링부트 JPA활용 1 - 회원 도메인 개발(4)

목차

  • 📌회원 리포지토리 개발
  • 📌회원 서비스 개발
  • 📌회원 기능 테스트

구현 기능

  • 회원 등록
  • 회원 목록 조회

순서

  • 회원 엔티티 코드 다시보기
  • 회원 리포지토리 개발
  • 회원 서비스 개발
  • 회원 기능 테스트





📌회원 리포지토리 개발

회원 리파지토리

package jpabook.jpashop.repository;

import jpabook.jpashop.domain.Member;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;

@Repository // 빈 자동 등록
@RequiredArgsConstructor
public class MemberRepository {

    //@PersistenceContext //스프링 엔티티메니저 생성후 여기로 인젝션
    private  final EntityManager em;

    public void save(Member member){  //회원 저장
        em.persist(member);
    }

    public Member findOne(Long id){  //한명 조회
        return em.find(Member.class,id);
    }

    public List<Member> findAll(){  //리스트 조회
        return em.createQuery("select m from Member m" , Member.class) //JSQL,클래스 타입
                .getResultList();

    }
    public List<Member> findByName(String name){ //특정회원 이름 조회
        return em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
    }
}

어노테이션 기술 설명

@Repository

  • 스프링 빈 자동 등록, JPA예외를 스프링 기반 예외로 예외 변환@PersistenceContext
  • 엔티티 매니져(EntutyManager) 주입@PersistenceUnit
  • 엔티티 메니터 팩토리 (EntituManagerFactory) 주입

메서드 기능 설명

save()

findOne()

findeAll()

findByName()





📌회원 서비스 개발

회원 서비스

package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class MemberService {

    private final MemberRepository memberRepository;

  /*
  @RequiredArgsConstructor 가 밑 생성자 자동 생성(롬북기능)
  @Autowired
    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }*/

    //회원가입
    @Transactional
    public Long join(Member member){

        validateDuplicateMember(member); //중복 회원 조회
        memberRepository.save(member);
        return member.getId();
    }

    private void validateDuplicateMember(Member member){
        List<Member> findMembers = memberRepository.findByName(member.getName());
        if(!findMembers.isEmpty()){
            throw new IllegalStateException("이미 존재하는 회원입니다.");
        }
    }

    //회원 전체 조회
    public List<Member> findMember(){
        return memberRepository.findAll();
    }

    public Member findOne(Long memberId){
        return memberRepository.findOne(memberId);
    }

}

어노테이션 기술 설명

@Service

@Transactional

  • 트랜잭션, 영속성 컨텍스트
    • readOnly=true : 데이터의 변경이 없는 읽기전용메서드, 영속성 컨텍스트를 플러시 하지 않아 약간의 성능이 향상 된다.
    • 데이터베이스 드라이버가 지원화면 DB에서 성능 향상@Autowired
  • 생성자 인젝션 많이 사용, 생성자가 하나면 생략가능

메서드 기능 설명

join()

findMembers()

findOne()

스프링 필드주입 대신 생성자주입 사용 권장

필드주입

public class MemberService {
 @Autowired
 MemberRepository memberRepository;
 ...
}

생성자 주입

public class MemberService {
 private final MemberRepository memberRepository;
 public MemberService(MemberRepository memberRepository) {
 this.memberRepository = memberRepository;
 }
 ...
}
  • 생성자 주입 방식 권장
  • 변경 불가능한 안전한 객체 생성 가능
  • final키워드 추가시 컴파일 시점에 memberRepository를 설정하지 않는 오류를 체크할 수 있다.





📌회원 기능 테스트

테스트 요구사항

  • 회원가입 성공
  • 회원가입시 중복이름 있을시 예외발생
package jpabook.jpashop.service;

import jpabook.jpashop.domain.Member;
import jpabook.jpashop.repository.MemberRepository;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;


@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class MemberServiceTest{
    @Autowired MemberRepository memberRepository;
    @Autowired MemberService memberService;


    @Test
    public void 회원가입테스트() throws Exception{
        //g
        Member m = new Member();
        m.setName("승빈");
        //w
        Long mId = memberService.join(m);

        //t
        Assert.assertEquals(m,memberRepository.findOne(mId));
    }

    @Test(expected = IllegalStateException.class)
    public void 회원중복테스트(){
        //g
        Member m = new Member();
        m.setName("홍길동");
        Member m1 = new Member();
        m1.setName("홍길동");
        //v
        Long member_ID = memberService.join(m);
        Long member1_ID = memberService.join(m1);

        //t
        Assert.fail("예외가 발생해야 한다.");

    }


}





📌어노테이션 정리

@RunWith(SpringRunner.class)

  • 실행 방벙을 확장할 때 사용하는 어노테이션
  • JUnit4.x 프레임워크가 내장된 Runner를 실행할 때 SpringRunner.class라는 확장된 클래스를 실행한다.
  • 따라서 테스트시 스프링 컨테이너를 활용할 수 있게된다.
  • SpringBoot2.1 버전부터 JUnit5.x로 변경되고 @SpringBootTest어노테이션에 포함되도록 변경되어 별도로 정의할 필요는 없어 졌다.

@SpringBootTest

  • 통합 테스트를 제공하는 스프링부트의 기본적인 어노테이션이다.
  • 여러 단위 테스트를 하나의 통합된 테스트로 수행할 때 사용한다.
  • JUnit4.x 는 @RunWith 어노테이션을 같이 사용해야 정상 작동한다.(JUnit의 SpringJUnit4ClassRunner 클래스를 상속 받아 사용 해야한다.)

@Transactional

REF