Spring Initializer
Spring Initializer는 웹 기반 도구이며, 이를 통해 Spring boot Project를 쉽게 생성할 수 있다.
스프링 프로젝트 생성 예시
- 프로젝트 선택
- Project: Gradle Project
- Spring Boot: 2.7.1
- Language: Java
- Packaging: Jar
- Java: 17
- Project Metadata
- groupId: hello
- artifactId: hello-spring
- Dependencies: Spring Web, Thymeleaf
스프링 부트 프로젝트를 생성할 때 빌드 툴을 Maven과 Gradle 중에 선택할 수 있다.
과거에는 Maven을 많이 사용했었지만 요즘은 Gradle로 넘어오는 추세이다.
따라서 나는 Ant와 Maven의 장점들을 모아서 만들어진 Gradle로 프로젝트를 진행할 것이다.
프로젝트 src 폴더 구조
📦 src
├─ main
│ ├─ java
│ └─ resources
└─ test
└─ java
요즘은 main,test 폴더 구조로 거의 표준화되어 나누어짐
- main : java,resources
- java 밑에는 실제 패키지와 소스파일들이 있다.
- resource에는 실제 자바 소스를 제외한, xml이나,html, 설정 파일 등이 들어감 (자바 소스 파일 제외 나머지 모두)
- test : 테스트 코드 관련 소스들이 들어감
동작 확인
웹 개발 3가지 방법
1. 정적 컨텐츠
- 서버가 파일을 웹 브라우저에 정적 html 파일 그대로 반환해줌
- resources/static 폴더에 html 파일이 들어간다.

동작 원리
- localhost:8080/hello-static.html을 치면 내장 톰켓 서버가 요청을 받고, 이 요청을 스프링 컨테이너에 던진다.
- 스프링 컨테이너는 먼저 컨트롤러 쪽에서 hello-static 컨트롤러가 있는지 찾아본다. (컨트롤러가 우선순위 가짐)
- 매핑된 컨트롤러가 없으면 resources 안에 있는 hello-static.html을 찾는다. 찾고 나면 웹 브라우저에 해당 html 파일을 반환한다.
2. MVC와 템플릿 엔진
MVC란?
MVC는 Model, View, Controller의 약자로, 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이며, 스프링에서는 Model, View, Controller 구성요소를 사용해 다양한 HTTP Request를 처리하고 응답할 수 있도록 하는 프레임워크이다.

동작 원리
- 브라우저에서 local:8080/hello-mvc로 요청한다.
- 톰캣 서버에서 요청을 받아 hello-mvc 라는게 왔다는 것을 스프링 컨테이너로 던져준다.
- 컨테이너는 우선적으로 hello-mvc라는 Controller를 찾고 hello-mvc에 맵핑된 @GetMapping()가 있는지 확인하고 매핑된 메소드를 호출한다.
- 스프링에게 리턴 값을 보내고, 동시에 Model에 키, 값의 데이터를 넣어 보낸다.
- 스프링이 화면(View) 관련된 연산을 처리해주는 해결자 viewResolver가 동작하여 해당 View(html 파일)를 찾아주고 템플릿 엔진에 연결시켜준다(넘긴다).
- 템플릿 엔진이 렌더링을 해서 변환한 html을 웹브라우저에 반환(반영)한다.
즉, MVC와 템플릿 엔진 방법은 HTML을 그대로 반환하는 것이 아니라 서버에서 HTML을 동적으로 바꿔서 클라이언트나 웹 브라우저에 HTML을 반환하는 동작을 한다.
3. API
- 클라이언트(안드로이드, ios 등)와 개발을 진행하거나 서버끼리 데이터를 전달할 때 서버가 JSON이라는 데이터 구조 포맷으로 클라이언트 및 서버에게 데이터를 전달한다.
- 서버끼리 통신할 때, html을 사용할 필요가 없이 데이터의 흐름이 중요하기 때문에 API 방식을 많이 사용한다.

동작 원리
- 웹브라우저에서 localhost:8080/hello-api를 요청
- 톰켓 서버에서 요청을 받아 hello-api가 왔다고 스프링한테 던짐.
- 스프링은 hello-api라는 Controller를 찾고 @Responsebody 라는 annotation이 있다면 HttpMessageConverter가 동작하여 HTTP 응답에 그대로 데이터를 넘기는 동작을 한다.
@ResponseBody 가 없다면 viewResolver한테 던진다.
이 때, 리턴 값이 객체면 JsonConverter가, 문자면 StringConverter가 동작된다.
JsonConverter가 동작하는 경우에, 리턴 객체를 JSON 데이터 구조 포맷으로 바꾸고 그것을 HTTP Body에 실어서 요청을 했던 웹 브라우저(클라이언트, 다른 서버 등)에 반환함.
즉 API 방식은, 일반적으로 객체를 반환하는데, @ResponseBody를 통해 HttpMessageConverter가 동작하여 JSON 데이터 구조 포맷으로 변환한 다음, 그 데이터를 그대로 HTTP Response에 넣어 반환한다.
MVC 방식과의 차이로는, MVC 방식은 View를 통해 웹 브라우저에 html을 내리고, API 방식은 View가 없이 데이터를 그대로 내린다.
.
비즈니스 요구사항 정리
- 데이터: 회원ID, 이름
- 기능: 회원 등록, 조회
- 아직 데이터 저장소가 선정되지 않음(가상의 시나리오)
일반적인 웹 애플리케이션 계층 구조

-
컨트롤러: 웹 MVC의 컨트롤러 역할
-
서비스: 핵심 비즈니스 로직 구현
-
리포지토리: 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리
-
도메인: 비즈니스 도메인 객체, 예) 회원, 주문, 쿠폰 등등 주로 데이터베이스에 저장하고 관리됨
클래스 의존관계
- 아직 데이터 저장소가 선정되지 않아서, 우선 인터페이스로 구현 클래스를 변경할 수 있도록 설계
- 데이터 저장소는 RDB, NoSQL 등등 다양한 저장소를 고민중인 상황으로 가정
- 개발을 진행하기 위해서 초기 개발 단계에서는 구현체로 가벼운 메모리 기반의 데이터 저장소 사용
Optional은 findById,findByName 등으로 값을 가져올 때 값이 없으면 NULL을 반환하는데, Null을 그대로 반환하는 대신에 Optional이라는 것으로 감싸서 반환
optional에서 값을 꺼낼 떄는 get() 사용
assertions : actual, expected 값이 같은지 확인
테스트 케이스 작성
❗ 테스트 케이스 작성 시 주의 사항
- 모든 테스트 순서는 보장이 되지 않는다. 모든 테스트는 순서와 상관없이 메소드마다 따로 동작하게 설계해야한다.
- 따라서 하나의 테스트가 끝날 때마다 데이터를 클리어(리포지토리를 깔끔하게 지워주는 코드를 작성)를 해주어야한다
- 테스트는 서로 의존 관계, 순서에 관계없이 설계가 되어야한다.
다음 어노테이션과 함수를 통해 하나의 테스트가 끝날 때마다 데이터를 클리어하도록 한다.
@AfterEach : 어떤 메소드 실행이 끝날 때마다 어떤 동작을 하도록 함
store.clear(): 저장소를 비움
테스트 클래스 바로 만드는 법: 테스트하고자 하는 클래스 안에서 Ctrl + shift + T
테스트 메소드 작성할 때에는 given,when,then 패턴으로 작성
테스트 메소드에서 중요한 것은 정상로직뿐만 아니라 예외적인 처리도 중요하다