본문 바로가기
Spring

[Spring] spring boot 입문하기

by onejunu 2020. 7. 27.

spring 이라는 거대한 아이템에 접근하기 위해서 강의를 찾던중 인프런의 김영한님 강의를 듣게 되었다.

 

스프링부트 입문 강의는 모든 자료와 영상이 무료로 풀려있고 입문 영상으로는 최고라고 생각한다. 아직 안들었다면 꼭 들어보길 추천한다.

 

강의 들은 내용을 바탕으로 처음 부터 끝까지 혼자 직접 코딩하고 정리해보고 앞으로 어떤 부분을 깊게 공부해야할 지 정해야겠다. 개인적으로  jpa를 깊게 해볼까 생각중이다.

 

일단 뭘 알기 전에 프로젝트부터 생성해보고 시작하자.

 

1) 프로젝트 생성하고 살펴보기

 

start.spring.io

설정은 위와 같이 자바11버전과 spring boot 버전 2.3.2 와 빌드 방식은 Gradle Project로 설정한다.

 

템플릿 엔진은 여러개 있는데 강의에서 타임리프 썼기 때문에 본인도 타임리프를 선택한다.

 

Dependencies를 설정하면 해당되는 라이브러리와 관련된 모든 라이브러리를 자동으로 땡겨와 준다. 일단 그렇다고만 알자.

 

그런다음 generate를 누르고 적당할 폴더에 압출을 풀어준다.

 

인텔리제이를 열고 build.gradle 를 project로 열면 아래와 같은 화면이 나타난다.

 

초기 build.gradle

그래들이 무엇인가? 에 대해 찾아보면 의존성 관리를 위한 빌드 도구라고 나온다. 무슨 소리인지 모르지만 프로젝트를 관리하는 도구로서 라이브러리를 관리하고 전체 빌드에 관한 설정할 수 있는 정도로만 이해했다.

 

dependencies 를 보면 타임리프와 스타터 웹을 땡겨온 것을 확인할 수 있다. 하지만 테스트 관련된 것도 같이 들어와 있는데 이는 디폴트로 설정되어 있는 값이라고 한다.

 

전체 파일 구조를 보면 main 폴더와 test  폴더가 있다. 

 

main 폴더의 java 폴더에서 작성하고, test에서 테스트 코드를 작성한다.  resources 에는 static 과 templates 폴더가 있는데 정적콘텐츠를 제공하는 곳이라고 보면된다. django 에서는 static 관련된 설정을 직접해야되서 상당히 귀찮았던 기억이 있는데 spring boot에서는 애초에 static 폴더를 만들어 준다. 

 

일단 HelloApplication 을 run 하고 localhost:8080 에 접속하여 아래와 같은 페이지가 뜨면 성공한 것이다.

 

 

그냥 시작한 화면

그리고 강의에서는 build and run 과 run tests using 에 관한 설정을 인텔리제이가 하도록 설정했는데,

 

인텔리제이로 설정하면 본인 컴퓨터에서는 빌드가 안된다. 무료버전이라 그런지 모르겠는데 여튼 설정을 gradle로 그대로 두었다.

 

에러페이지가 싫으면 resources/static/index.html  을 생성하면된다.

 

hello spring

위와 같은 페이지를 웰컴페이지라고 하는데

 

https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/html/spring-boot-features.html#boot-features-spring-mvc-welcome-page

 

위를 참조하면 좋을거 같다.

 

또한 앞으로 공부를 위해서 링크 남겨두고 두고두고 봐야겠다.

 

타임리프 템플릿엔진 :

https://www.thymeleaf.org/

스프링 공식 튜토리얼: http:// https://spring.io/guides/gs/serving-web-content/

스프링 부트 메뉴얼 :  http:// https://docs.spring.io/spring-boot/docs/2.3.1.RELEASE/reference/ html/spring-boot-features.html#boot-features-spring-mvc-template-engines

 


2) Controller 

 

 

controller package 위치

만약에 controller 패키지를 HelloApplication이 있는 위치에 하지 않으면 controller 어노테이션을 달아도 인식하지 못한다.

 

따라서 필자는 controller를 처음에 myFristSpring에 만들어서 왜 안될까 고민했다...

 

그리고 controller 라는 이름을 쓰지 않아도 된다. 단지 @Controller 만 잘 달아주면 된다. 

 

HelloController

위와 같이 작성하고 templates/hello.html 을 작성해주면 된다.  html 작성은 생략하지만 타임리프 문법은 아래와 같다. 

templates/hello.html

 

model은 html 로 전송할때 key 와 value를 추가하여 보내주면 html에 ${data} 부분에 알아서 렌더링 해서 화면을 보여준다.

아래 사진은 helloController 에서 주석처리한 부분 그대로 저장하여 돌리면 나오는 결과물이다. 참고로 p태그 안에 "안녕하세요" 는 무시된다.

 

model attribute 생략하면

그렇다면 이렇게 화면을 보여주는 원리는 어떻게 될까?? 대략적인 큰 로직은 아래와 같다.

 

1) 웹브라우저에서 localhost:8080/hello 로 GET 요청을 보낸다.

2) 스프링부트의 내장 톰캣서버를 통해 해당 url을 가진 controller를 찾는다. 이러한 컨트롤러는 아까 했지만 @Controller로 스프링부트에 알려준다. 

3) controller를 찾았고 메소드가 GET이라면 로직을 처리한 후 String을 반환한다.

4) viewResolver 에서 templates/{ 반환된String}.html 에다가 전달된 model 값을 렌더링하여 사용자 화면에 뿌려준다.

 

 

 

GET request 에 어떤 파라미터가 있다면 어떨까?

 

예를 들면  " localhost:8080/hello?id=100&name=jun "  로 요청을 보냈다면 어떻게 처리할까?

 

GET 요청에서 parameter 처리는 @RequestParam을 이용하면 된다.

helloController
hello.html
name과 id 순서 바뀌어도 상관없음

3) @ResponseBody

 

 

responseBody

위와 같이 작성하고 

 

날것 그대로 보내진다. 어떠한 html 코드도 없음

4) API

 

api 란 데이터 객체를 주고 받는 것을 의미하는데 3) 에서 처럼 String 이 날것 그대로 responseBody에 실려서 왔다면 객체는 어떻게 될까?? 만약 객체를 보낸다면?

 

.

 

객체를 보내면 json으로 설정된다.

 

Spring 에서는 xml 이 아니라 json 으로 객체를 default로 표현하고 있다. 

또한 viewResolver가 처리하는 것이 아니라 ResponseBody가 붙으면 HttpMessageConverter가 동작한다.

 

 String 처리라면

StringHttpMessageConverter

 

객체처리라면

MappingJackson2HttpMessageConverter

 

만약에 클라이언트 http 메시지에 Accept에 정보가 있다면 이를 참고하여 컨버터를 선택한다.

 

 

5) 실제 배포할려면 어떻게 빌드하고 실행하나?

 

작업중인 폴더로 이동 -> ./gradlew build -> cd build/libs -> java -jar {파일이름}.jar 

 

 

6) 초간단 웹어플리 케이션 개발

 

 

6-1) 도메인과 레포지토리

강의에서는 비즈니스 요구사항을 정의하고 이에 맞춰서 하나씩 구현해 나간다.

나도 똑같이 비즈니스 요구사항을 정의하고 한번더 해보기로 한다.

 

요구사항 : 회원의 등록과 조회

회원은 이름만 있으면됨.

데이터베이스는 뭘로 할지 정하지 않은 사항.

 

데이터베이스는 정하지 않았기 때문에 인터페이스로 구현하여 이후 조립만 하면 되도록 한다. 다형성의 매력이 여기서 등장한다.

 

 

웹어플리케이션의 동작은 크게 4가지가 있는데 아래와 같다.

 

1) 컨트롤러

2) 서비스

3) 레포지토리

4) 도메인

큰 구조

 

컨트롤러는 이때까지 본것처럼 url 관련된 요청을 처리한다. 서비스는 컨트롤러에서 일을 시키면 핵심 비즈니스 로직을 수행한다.

레포지토리는 서비스에서 필요한 데이터를 데이터베이스에 관련되어 일을 처리한다. 따라서 레포지토리는 좀 단순한 명령을 수행한다고 볼 수 있지만 결코 만만하지 않다. 마지막으로 도메인은 비즈니스상에서 도메인 객체에 해당한다. 주로 데이터베이스에 저장된다.

 

 

먼저 도메인 부터 정의할 것이다. 

이름 밖에 없으므로 이름과 데이터베이스에서 사용할 primary key로서 id를 선언해준다.

코드는 아래와 같다.

 

member domain

그다음으로 데이터베이스를 뭘로 해야될지 모르니까 MemberRepository를 interface로 구현한다.

 

MemberRepository 인터페이스

여기 인터페이스를 구현하여 강의에서는 다양한 repository를 구현했지만 필자는 디비를 쓰지않는 메모리 레포지토리와 h2데이터베이스를 사용하는 jpa레포지토리를 만들어 볼 것이다.

 

정리할 것도 없지만 그래도 지금까지 한것을 정리하면 아래와 같다. 

도메인과 인터페이스

 

레포지토리는 데이터베이스를 사용하지 않기 때문에 멤버레포지토리를 implements 하고 자체 저장소를 지녀야한다.

이름은 MemoryMemberRepository로 정했다.

 

멤버를 저장하기 위한 자료구조는 가장 단순한 HashMap을 쓴다. 실무는 ConcurrentHashMap을 쓴다고 한다. 

 

자료구조 설정

이제 메소드 각각을 구현해본다.

MemoryMemberRepository 메소드

스트림과 람다가 정말 코드를 보기 편하게 만들어 주는거 같다.

다음에 스트림과 람다사용에 대해 JAVA 카테고리에 정리해야겠다.

 

6-2) 레포지토리 테스트코드 작성

 

다음은 메소드가 실제로 잘 동작하는 지 테스트를 해야한다.

테스트의 하위 폴더에 MemoryMemberRepositoryTest 라는 클래스를 만들어서 테스트를 한다.

 

메모리에 저장되어있는 Hashmap가지고 테스트를 하는 것이기 때문에 어렵지 않다. 

하지만 중요한 개념 몇개만 기억해두고 넘어간다.

 

1. 모든 테스트는 독립되어야 한다. 즉 다른 테스트 메소드에게 영향을 미쳐서는 안된다. 데이터베이스의 경우 남은 데이터를 비워야 할 것이며 메모리에 테스트한다면 그 역시 다 비워야할 것이다. 

@AfterEach  는  반복적인 @Test 후에 실행되는 메소드이며 비우는 작업을 할때 선언하면 된다.

 

2. 테스트 코드 작성은 모든 경우의 수를 작성해보는 것이 좋다.  정상적으로 되는 경우가 아니라 비정상적인 경우 모두 체크해 봐야한다는 것이다. 

 

3. 테스트를 시작하기 전에 @BeforeEach 를 통해 레포지토리또는 서비스 혹은 둘다 새로 생성해야한다.

 

4.org.assertj.core.api.AssertionsassertThatisEqualTo 를 사용하여 정상 로직을 테스트하자.

 

5. assertThrows 를 통해 비정상 로직을 테스트 하자. 

 

 

** 이후 서비스와 컨트롤러는 간단하게만 언급하고 다음 spring 공부에서 배운것을 바탕으로 

스스로 비즈니스 요구사항을 만든뒤에 간단하게 만들어 볼 것이다. h2데이터베이스를 사용할 것이다.

6-3) 멤버 서비스 작성

 

실제로 데이터베이스와 연결은 하지 않았지만 레포지토리와 관련된 간단한 메소드들을 작성하였다.

 

이제는 이러한 메소드를 가지고 실제 핵심 로직을 구현하는 서비스를 작성해보도록 한다.

 

6-4)스프링 컨테이너에 등록후 컨트롤러를 통해 웹서비스

 

서비스를 작성한후 컨트롤러를 통해 실제 url로 서비스가 되도록 만들어본다.

 

 

 

댓글