본문 바로가기

WINK-(Web & App)/Spring Boot 스터디

[2024-2 SpringBoot 스터디] 1주차 섹션 1~4

반응형

섹션 2

스프링부트 프로젝트 생성하기

https://start.spring.io/

여기 접속해서 위와 같이 설정을 해 주면 된다.

Project의 Maven 이나 Gradle 과 같은 것은 라이브러리 부터 빌드까지 모두 담당하는 것이다. 예전에는 Maven을 주로 썼으나, 요즘에는 Gradle을 쓴다고 한다.

Spring Boot에서의 Snapshot은 아직 만들고 있는 버전이며, M1 같은 것은 아직 완전히 완성된 것이 아니다.

Dependencies는 어떤 라이브러리를 땡겨쓸 것인지에 대한 것이다.

Spring Web과 Thymeleaf를 선택한다.

그 후에 Generate를 하고, IntelliJ에서 열어준다.

src : main과 test로 이루어져 있다. 요즘에는 main폴더와 test폴더가 나뉘어져 있다.

main : 주로 소스 파일이 들어있다.

test : 주로 테스트 파일이 들어있다. -> 테스트 코드가 중요하다!를 의미

resources : xml, html, 설정 파일 등 자바 파일을 제외한 것들이 들어간다.

build.gradle : 버전, 라이브러리 관련 설정들이 들어가 있다.  

thymeleaf : 템플릿 엔진

이런 라이브러리들을 mavenCentral()에서 다운받게 해 준다.

gitignore : git에 올라갈 때 필요하지 않은 것들을 적어둔다.

미리 class가 만들어져 있다. 바로 실행해 주자.

 

tomcat 8080 뭔가가 떴다.

이렇게 뜨면 성공이다(?)

@SpringBootApplication

 

이 annotation을 쓰면 실행버튼을 눌렀을 때 알아서 동작한다.

빠른 실행을 위해 설정 -> gradle에서 build and run using과 run tests using을 모두 IntelliJ IDEA로 바꿔준다. gradle로 되어 있을 시 gradle을 거쳐 실행하므로 실행이 느릴 수 있다고 한다. IntelliJ로 설정을 하면 실행 시 바로 IntelliJ로 실행한다.

라이브러리 살펴보기

External Libraries를 눌러보면 내가 땡긴 적이 없는 라이브러리까지 나온다. 

예를들어 spring-boot-starter-web을 검색해보면, 필요한 추가적인 라이브러리까지 모두 땡겨온다. 모두 의존관계를 갖고 있다고 보면 된다!

 

spring-boot-starter : 스프링부트 + 스프링코어 + 로깅

spring-boot-starter-tomcat : localhost:8080(웹 서버)을 띄우게 해 준다.

spring-webmvc : 스프링 웹 MVC

thymeleaf : 타임리프 템플릿 엔진

로깅 : 로그를 남겨야 나중에 오류를 모아볼 수 있다. 실무에서는 로깅을 써야 한다. spring-boot-starter-logging에는 logback과 slf4j가 있는데, 요즘은 logback을 많이 쓴다고 한다.

 

spring-boot-starter-test : 테스트 관련 라이브러리

junit : 자바에서 테스트 시 대부분 junit을 쓴다. 요즘에는 junit 5를 쓴다.

spring-test : 스프링과 통합해서 테스트를 해 주게 한다.

assertj : 테스트 코드 더 편하게 작성할 수 있게 도와줌.

View 환경설정

앞전에 localhost:8080 접속 시 에러 페이지만 떴었다. 이를 해결해보도록 하자.

src>main>resources>static 아래 index.html을 만들어 준다.

위와 같이 간단하게 작성해 준다.

재시작을 해보면 이제 우리가 만든 welcome page가 뜬다.

static/index.html을 작성하면 Welcome Page기능을 제공한다고 한다.

 

thymeleaf 템플릿 엔진?

https://www.thymeleaf.org/

 

Thymeleaf

Integrations galore Eclipse, IntelliJ IDEA, Spring, Play, even the up-and-coming Model-View-Controller API for Java EE 8. Write Thymeleaf in your favourite tools, using your favourite web-development framework. Check out our Ecosystem to see more integrati

www.thymeleaf.org

이 외에도 freemarker, mustache 등 템플릿 엔진들을 제공한다.

 

Controller : 웹 애플리케이션에서 첫 진입점

controller라는 패키지 생성 > HelloController라는 클래스 생성

controller는 꼭 @Controller를 써 줘야 한다.

thymeleaf문법을 쓰는 html을 만들어 준다.

스프링부트에는 tomcat을 내장하고 있다.

http://localhost:8080/hello를 입력하면 @GetMapping("hello")가 있는 메소드를 실행한다.

return "hello" -> 동일한 이름을 가진 hello.html을 viewResolver가 찾아서 렌더링하라 라는 뜻이다.

(기본적으로 resources/templates 아래 있는 파일들을 찾는다.)

viewName매핑 -> resources:templates/ + {ViewName} + .html 으로 찾는다.

{data}는 모델에서 key값이다. {data}에 전달된 hello!!!을 spring!!!으로 바꾸면 표시되는 내용도 바뀐다.

빌드하고 실행하기

터미널 실행 > 프로젝트 파일 > ./gradlew build를 입력하면 빌드가 된다.

cd build > cd libs > ls -arlth를 입력해 완성된 jar파일을 찾고,

java -jar 파일이름.jar으로 실행해 준다.

*터미널에서 실행할 때는 IntelliJ에서 실행했던 걸 꺼주자! 8080은 동시에 실행할 수 없다.

 

./gradlew clean -> 빌드 폴더를 삭제함

./gradelw clean build -> 빌드가 잘 안될때 이걸 실행해 보자

섹션 3

정적 컨텐츠

MVC : model-view-controller를 의미. 서버에서 html으로 바꿔서 전달하는 방식

정적 컨텐츠 : 파일을 그대로 웹브라우저에 전다.

API : 안드로이드, IOS 개발 시 json이라는 포맷으로 클라이언트에게 전달하는 방식

*react.js, vue.js, 서버 간 통신 시에도 API 방식으로 데이터를 내려준다고 한다.

 

스프링부트 -> 정적 컨텐츠(static contents) 기능을 자동으로 제공한다!

위와 같이 static/hello-static.html이라는 파일을 만들어 작성해 준다.

실행 후, http://localhost:8080/hello-static.html (.html까지 써줘야 한다! 안그러면 에러가 뜬다.)으로 들어가 본다.

원하는 파일을 넣으면 그대로 내놓는다. 다만 프로그래밍은 불가능하다.

http://localhost:8080/hello-static.html 입력 >

controller에서 hello-static 관련 컨트롤러를 찾아봄 (controller가 우선순위가 높음) >

없다면 resources: static에서 hello-static을 찾아 띄워준다.

 

MVC와 템플릿 엔진

MVC : model-view-controller를 의미. 과거에는 컨트롤러와 뷰가 분리가 안되어 있고, 뷰에서 모든걸 다 했다!

요즘에는 MVC스타일로 많이 한다.

View는 화면을 그리는 데 집중하고, Controller나 Model관련 부분은 비즈니스 로직 혹은 내부적인 것들을 담당해야 한다.

HelloController.java 아래에 새롭게 하나를 추가해 준다. key가 "name"인 속성을 넘겨준다.

관련된 hello-template.html을 만들어 준다.

다시 실행하면 오류가 뜬다. RequestParam에 required라는 파라미터가 있다. Default 값이 true인데, 즉 아무것도 안 써주면 파라미터를 넘겨야 한다는 뜻이다.

이렇게 hello-mvc 뒤에 ?name=Spring공부중! 

과 같이 넣어줘야 한다.

helloController속에 있는 메소드 실행 

viewResolver가 관련 파일을 찾아 연결해 줌. 여기서는 hello-template.html을 찾아준다.

정적 컨텐츠에서는 변환 없이 바로 웹 브라우저에 넘겼지만, 템플릿 엔진에서는 변환 과정을 거쳐 넘겨준다.

정적 컨텐츠에서는 작성한 html 코드가 그대로 들어갔지만, 템플릿 엔진에서는 입력값으로 변환해서 내보낸다.

 

API

ResponseBody : html의 Body부분에 내용을 직접 넣겠다~

예) 

return "hello " + name;

name이 KIM이라면, hello KIM으로 변환

 

위와 같은 방식을 API방식이라고 한다. 기본적으로 json으로 반환한다.

getter, setter를 쓰는 방식을 프로퍼티 방식이라고도 한다.

@ResponseBody 감지 시,

- 문자라면 문자값을 http응답에 전달한다.

- 객체라면 기본 디폴트 값은 json방식으로 만들어서 html에 반환하는 것 이다.

HttpMessageConverter가 동작한다.

- 문자라면 StringConverter가 동작

- 객체라면 JsonConverter가 동작

Converter 동작 결과를 웹브라우저에 전달한다

 

@ResponseBody가 없을 때는

- viewResolver에게 전달한다.

 

HTTP Accept헤더에서 온 요청 (json, xml등) 에 따라 변환하는 포맷이 달라진다.

제일 중요한 건 요즘엔 json만 쓴다

 

 

섹션 4

비즈니스 요구사항 정리

데이터 : 회원 ID, 이름

기능 : 회원 등록 및 조회

아직 데이터 저장소가 선정되지 않았음을 가정 (어떤 형태의 데이터베이스로 개발할 지 정해지지 않았다는 뜻)

 

일반적인 웹 애플리케이션의 구조 

 

초기에는 가벼운 메모리 기반의 저장소 사용 (데이터 저장소가 선정되지 않았기 때문.)

 

회원 도메인과 리포지토리 만들기

domain 패키지 생성, 데이터인 회원 id 와 이름을 추가

repository 패키지 생성

save : 저장 기능

 

option + enter시 interface를 불러올 수 있음

 

sequence : 키값 0,1,2 등을 생성해줌

위와 같이 저장과 검색을 위한 메소드를 만들어 준다.

 

회원 리포지토리 테스트 케이스 작성

JUnit이라는 프레임워크를 이용해서 테스트를 수행한다 - 이는 간단하고 시간이 적게 드는 방법이다.

test/java/이름/repository에 MemoryMemberRepository + Test 를 붙여 class를 만들어 준다.

위와 같이 들어온 내용을 잘 저장하는지에 대한 코드를 작성하는데, 

1번 처럼 

System.out.println("result = "+ (result==member));

을 이용해 출력할 수도 있고,

 

2번 처럼

Assertions.assertEquals(result, member);

assertion을 이용할 수도 있고,

 

강의 내용과 실제 적용했을 때의 코드는 약간 달랐지만,

강의 내용 실제 적용 시

같은 assertion을 제공하는 다른 라이브러리를 사용해도 된다. static import를 통해 더 쉽게 쓸 수 있다.

static import을 할 경우, 

assertThat(member).isEqualTo(result);

 

이렇게만 쓰면 된다.

이번에는 이름으로 찾는 findbyname메소드를 써준다. member1과 2는 각각 다른 name값을 가지고 있으며, member2에 들어있는 값과 member1에 들어있는 값은 다르기에 테스트 수행 시 오류를 출력한다.

*Shift + F6 (혹은 맥 기준 fn+Shift+F6)을 누르면, 동일한 내용을 복사해도 객체 이름을 바꿀 수 있다. 아랫줄의 해당 객체의 이름 또한 바뀌는 건 덤.

총 데이터의 개수를 출력하는 findAll을 작성해준다.

그 뒤, 모든 테스트를 실행해 주면 에러가 뜬다.

왤까??

모든 테스트는 순서와 상관없이 따로 실행되어야 한다.

findAll()에서 이미 객체를 저장했기 때문에, findByName에서 오류가 뜨는 것이다.

그러기 위해서는 테스트가 끝날 때 마다 데이터를 clear해줘야 한다.

 

@AfterEach를 써 주면 테스트가 끝날때마다 수행하는 콜백함수를 만들어준다.

MemoryMemberRepository.java MemoryMemberRepositoryTest.java

각각 테스트가 끝날 때마다 데이터를 날려주는 코드를 작성해준다. 

그러면 테스트 순서에 관계 없이 잘 수행이 된다.

*테스트를 먼저 만들고, 구현 후에 테스트를 수행하는 것 = 테스트 주도 개발 (TDD)

회원 서비스 개발

*

memberRepository.findByName(member.getName());

입력 후, option + command + v를 눌러보자. 

Optional<Member> result = memberRepository.findByName(member.getName());

 

이렇게 바꿔준다. 야호

result.ifPresen()를 통해 이미 존재하는지 여부를 보고, ()안에 람다함수를 넣어 이미 존재함을 알리는 IllegalStateException()을 호출한다.

 

*참고로 null의 가능성이 있기에, Optional로 감싸줘야 한다. 감싸주면 ifPresent(), orElseGet()등을 쓸 수 있다.

 

하지만 위와 같이 result로 빼는 것을 추천하진 않는다고 하신다.

이미 윗 사진의 첫줄까지 썼다면 ifPresent()를 바로 쓸 수 있기 때문에 아래에 바로 써준다.

 

강의내용 실제 적용 시

이런건 메소드로 뽑는게 좋은데, control + T를 누르면 리팩토링과 관련된 메소드가 나온다.

Extract Method (command + option + M)을 눌러 바꾼다. (강의내용과 버전이 다른지 몰라도 다르게 뜹니따!)

 

그외 전체적인 멤버조회 등을 작성해준다.

주석과 같이 서비스 이름은 비즈니스 관련된 용어로 작성해야 다른 팀원들이 이해하기 쉽다고 하신다!

 

 

회원 서비스 테스트

이제 회원 서비스를 테스트 해보고자 한다.

앞전 테스트 제작 강의에서는 일일이 만들었지만,

클래스 이름에 커서를 두고, command + shift + T를 누르면, 위와 같이 뜨는데, create Test를 누른다.

이렇게 테스트를 만드는 창이 뜨는데, 해당하는 것들을 모두 체크해준다.

그럼 이렇게 테스트를 만들기 위한 껍데기를 만들어준다!

경로 또한 test 경로 안에 만들어준다. (세상 친절)

*테스트 파일의 메소드명은 한글로 적어도 된다고 한다! 실제로 테스트코드는 빌드시에 포함되지 않는다고...

 

<Given - When - Then>

테스트를 작성 시, 위 구조로 작성하는 것을 추천하신다. 어디서 어떻게 테스트가 이뤄지는지 쉽게 알 수 있다고 하신다.

회원가입 테스트 작성 완료 ~

하지만 중복회원이 있는지에 대한 메소드를 테스트해봐야 한다.

테스트 성공 시 테스트 실패 시

위처럼 try ~ catch() 문을 써서 예외처리를 할 수 있다.

그러나 더 좋은 방법이 있는데, assertThrows를 쓰는 방법이다.

이 테스트 또한 clear를 해줘야 하는데 MemberService밖에 없다!

위와 같이 MemoryMemberRepository를 생성해 준 뒤에, clear를 수행한다.

*control + R 누르면 이전에 실행했던거 그대로 실행해준다.

 

여기서, memberService의 MemoryMemberRepository와, test case의 MemoryMemberRepository는 다른 repository(instance)이다. 나중에 문제가 생길 수 있으므로, 같은 instance를 쓰게 해야 한다.

command + n을 눌러 constructor를 생성한다.

BeforeEach를 사용한다. 이는 테스트 수행 전에 실행할 코드를 넣어두는 곳임.

 

MemberService 입장에서 직접 이용하지 않고, MemberRepository를 외부에서 넣어줌 -> Dependency Injection

반응형