jhhan의 블로그

자바와 스프링 그 사이(1) 본문

JAVA

자바와 스프링 그 사이(1)

jhhan000 2020. 12. 16. 21:27

이번 포스트는 이전에 다뤘던 SOLID원칙을 이용해서 진행할 것입니다.

특히 DIP와 OCP를 지켜볼려고 노력하면서 진행합니다.

 

자바를 사용해서 코드를 진행합니다.

하지만 프로젝트 설정은 스프링으로 시작합니다.

처음에는 자바로 코딩을 하다가 나중에 스프링으로 넘어가기 위해서입니다.

지금은 자바 쪽에 넣어놨지만, 나중에는 스프링으로 옮겨서 글을 이어서 쓸 것 입니다.

 

그래서 처음 설정은 스프링으로 시작합니다..

스프링을 설정을 하기 위해 다음의 사이트로 들어갑니다.

start.spring.io

여기로 들어가면 스프링 설정을 할 수 있습니다.

혹은 인텔리제이 얼티메이트 버전을 사용한다면 여기에 들어가지 않고 스프링 프로젝트를 바로 만드실 수 있습니다.

사이트에 들어가시면 왼쪽 위쪽에 이런 것들이 보입니다.

  • 프로젝트는 Gradle Project로 갑니다.
  • 언어는 당연히 JAVA입니다.
  • Spring Boot 버전은 SNAPSHOT이 적히지 않은 것 중 가장 최신 것으로 해주세요.
  • 정식 릴리즈가 되지 않으면 뒤에 SNAPSHOT 등 다양한 것들이 붙는다고 합니다.
  • Group은 hello, Artifact는 core라고 적었는데,, 이 부분은 본인이 원하는 이름으로 해주세요.

다음 밑으로 내려가시면 이런 것들이 보입니다.

  • Packaging은 Jar로 합니다.
  • Java 버전은 11로 합니다.

그리고 오른쪽 위에를 보시면 Dependency를 선택하는 부분이 있습니다.

Spring 설정을 한다면 당연히 여러가지를 추가해야 하지만,

지금은 Java로만 진행할 것이기 때문에 아무것도 추가하지 않습니다.

맨 밑에 다음의 버튼들이 있습니다.

Generate 버튼을 눌러주셔서 프로젝트 생성을 완료합니다.

그러면 zip 파일이 다운로드 됩니다.

이 파일을 풀어줍니다.

 

그리고 인텔리제이를 실행합니다.

아마 저 3가지 버튼이 보이실 겁니다.(Intellij 업데이트를 했더니 모양들이 바뀌었네요.. ㅎㅎ)

Open을 누르셔서 아까 다운받고 압축을 푼 파일 위치로 갑니다.

그리고 build.gradle 파일을 선택합니다.

그러면 다음의 알림창이 나오는데,

Open as Project를 눌러서 진행해주세요.

그리고 설정을 기다립니다...

 

그리고 build.gradle 파일에 한 번 가보실까요?

중간에 이런 설정이 있습니다.

아무것도 추가하지 않으면 저렇게

starter 와 test 만 추가됩니다. 깔-끔

 

그럼 이제 이 프로젝트를 한번 실행해보겠습니다.

런 버튼 눌러주시면 됩니다.

런을 하면 다음과 같이 실행이 될것입니다.

스프링에 아무런 설정을 하지 않았기 때문에 code 0으로 끝나는 것이 정상이에요!

톰캣이나 웹 설정을 하지 않았기 때문에 다른 것이 뜨면 그게 이상한 겁니다!

 

설정이 끝났으니 이제 개발을 진행해 볼까요>?

 

먼저 회원 도메인을 만들겠습니다.

회원은 등급이 존재하고, 등급은 VIP, BASIC 2개입니다.

회원의 경우 아이디, 이름, 등급 - 3가지만 가질겁니다.

 

프로젝트 구조는 다음과 같습니다.

제가 어느정도 진행해서 좀 다른 것들이 섞여있네요.

현재는 member package만 할것입니다.

hello.core 패키지 밑에 member라는 패키지를 하나 생성합니다.

 

먼저 Grade 부터 만들겠습니다.

Grade는 Enum class로 만들면 됩니다.

public enum Grade {
    BASIC,
    VIP
}

다음으로 Member Class를 만들겠습니다.

public class Member {

    private Long id;
    private String name;
    private Grade grade;

    public Member(Long id, String name, Grade grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }

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

    public Grade getGrade() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade = grade;
    }
}

변수는 id, name, grade 3개로 진행합니다.

그리고 생성자, getter, setter를 만들어줍니다.

(단축키 설정을 안하셨다면, Alt+Insert를 누르면 생성자, getter, setter를 더 쉽게 만들 수 있습니다.)

다음으로 MemberRepository 인터페이스를 만들겠습니다.
(Member를 저장할 공간이 필요하겠죠? MemberRepository가 그 역할을 할 것입니다.)

public interface MemberRepository {

    void save(Member member);

    Member findById(Long memberId);
}

간단하게 진행할 것이기 때문에 - 저장 & 조회만 만들겠습니다.

하지만 인터페이스만으로는 무언가를 하기 어렵습니다.

그래서 구현체를 만들겠습니다. MemoryMemberRepository입니다.

public class MemoryMemberRepository implements MemberRepository {
    private static Map<Long, Member> store = new HashMap<>();

    @Override
    public void save(Member member) {
        store.put(member.getId(), member);
    }

    @Override
    public Member findById(Long memberId) {
        return store.get(memberId);
    }
}

MemberRepository를 구현한 MemoryMemberRepository입니다.

앞으로 store에 저장이 될 것입니다.

물론 실전에서는 저런식으로 하시면 안됩니다. 지금은 예제니깐 간편하게 개발하기 위해서 Map으로 진행할 겁니다. ㅎ

 

MemberRepository는 DB와 관련된 부분이고 실제 회원가입과 조회가 가능하도록 하는 부분도 필요합니다.

이제 MemberService 인터페이스를 만들겠습니다.

public interface MemberService {
    void join(Member member);

    Member findMember(Long memberId);
}

그리고 인터페이스를 구현할 구현체도 만들겠습니다. MemberServiceImpl입니다.

public class MemberServiceImpl implements MemberService{
    private final MemberRepository memberRepository = new MemoryMemberRepository();

    @Override
    public void join(Member member) {
        memberRepository.save(member);
    }

    @Override
    public Member findMember(Long memberId) {
        return memberRepository.findById(memberId);
    }
}

 

이제 이렇게 만들어 봤으니깐, 이제 테스트를 해보겠습니다.

MemberApp 클래스를 만들겠습니다.

public class MemberApp {

    public static void main(String[] args) {
        MemberService memberService = new MemberServiceImpl();
        Member member = new Member(1L, "MemberA", Grade.VIP);
        memberService.join(member);

        Member findMember = memberService.findMember(1L);
        System.out.println("new Member = " + member.getName());
        System.out.println("find Member = " + findMember.getName());
    }
}

자바로 진행하기 때문에 자바 형식의 테스트를 만들어 봤습니다. ㅎ

(인텔리제이에서는 psvm을 입력하면 public static void main()을 바로 만들어줍니다. ㅎㅎ)

이제 실행해 보겠습니다.

이렇게 잘 나옵니다. - 작성한 코드에 문제점이 없다고 볼 수 있겠네요

 

스프링 설정을 하긴 했지만, 지금까지의 코드를 보면 완벽한 자바 코드입니다.

하지만, 아무리 순수 자바로만 한다고 해도, 테스트 하기에는 좀 불편합니다.

그래서 jUnit을 이용해서 테스트를 좀 더 편하게 해보겠습니다. ㅎㅎ

test라는 폴더 밑에 hello.core 밑에 - member라는 패키지를 만들고, MemberServiceTest라는 클래스를 만듭니다.

public class MemberServiceTest {

}

그러면 이렇게 빈 클래스가 생성됩니다.

이제 여기다 Test code를 입력해보겠습니다.

public class MemberServiceTest {
    MemberService memberService = new MemberServiceImpl();

    @Test
    void join() {
        // given
        Member member = new Member(1L, "memberA", Grade.VIP);

        // when
        memberService.join(member);
        Member findMember = memberService.findMember(1L);

        // then
        Assertions.assertThat(member).isEqualTo(findMember);
    }
}

회원가입을 해보는 테스트를 만들었습니다.

  • 주석은 보기 싫으시면 제거하셔도 됩니다.
  • Assertions의 경우 org.assertj.core.api.Assertions 에 있는 녀석을 사용하시기 바랍니다.

실행을 해보시면, 녹색깔이 보이면서 테스트가 성공했다는 것을 볼 수 있을 겁니다.

그럼 한번 실패하는 경우도 알아봐야 겠죠?

코드에서 찾고자 하는 id를 1L이 아닌 다른 것을 넣어보시길 바랍니다.

그러면 빨간색깔이 보이면서 실패했다는 것을 알 수 있습니다.

 

이렇게 테스트를 하는 것이 앞에서 순수 자바 코드로 테스트 하는 것보다는 더 나아보입니다. ㅎㅎ

앞으로 테스트 할 때는 이렇게 하는 것이 좀 더 편하지 않을 까요? 

 

 

 

 

일단은 여기서 마무리를 하겠습니다.

근데 이 코드는 약간 문제가 있습니다.

DIP가 제대로 이루어지지 않았습니다...!

private final MemberRepository memberRepository = new MemoryMemberRepository();

중간에 이런 코드가 있다는 것을 아마 아실 겁니다.

인터페이스에 의존하고 있는 동시에 구현체에도 의존하고 있습니다.

이렇게 되면 나중에 확장(추가)를 하는데 변경을 해야하는 어려움이 있습니다.

다음 포스트에서 당장 이 문제점을 해결하지는 않을 것 같습니다.

하지만 어찌됐든 DIP가 지켜져야 하기 때문에 이 문제점을 해결할 것입니다..

 

이렇게 이번 포스트를 마무리 하겠습니다.

 

출처: 인프런 - 스프링 핵심원리(기본편) by 김영한

'JAVA' 카테고리의 다른 글

자바와 스프링 그 사이(3)  (0) 2020.12.29
자바와 스프링 그 사이(2)  (0) 2020.12.26
BufferedReader & BufferedWriter  (0) 2020.06.18
Java의 정석을 시작하자(7)(2/11)  (0) 2020.02.14
Java의 정석을 시작하자(6)(2/10)  (0) 2020.02.14