[Spring] 스프링 입문 강의 요약 (1)

‍윤재성·2022년 6월 28일

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 : 테스트 코드 관련 소스들이 들어감

동작 확인

  • 기본 메인 메소드 실행

  • 메인 메소드를 실행하면 스프링부트 애플리케이션이 실행됨(자체적으로 tomcat이라는 웹서버를 내장하고 있고 tomcat 웹 서버를 자체적으로 띄우면서 스프링 부트가 같이 올라옴)

  • 스프링 부트 메인 실행 후 에러페이지로 간단하게 동작 확인( http://localhost:8080 )

웹 개발 3가지 방법

1. 정적 컨텐츠

  • 서버가 파일을 웹 브라우저에 정적 html 파일 그대로 반환해줌
  • resources/static 폴더에 html 파일이 들어간다.

동작 원리

  1. localhost:8080/hello-static.html을 치면 내장 톰켓 서버가 요청을 받고, 이 요청을 스프링 컨테이너에 던진다.
  2. 스프링 컨테이너는 먼저 컨트롤러 쪽에서 hello-static 컨트롤러가 있는지 찾아본다. (컨트롤러가 우선순위 가짐)
  3. 매핑된 컨트롤러가 없으면 resources 안에 있는 hello-static.html을 찾는다. 찾고 나면 웹 브라우저에 해당 html 파일을 반환한다.

2. MVC와 템플릿 엔진

MVC란?

MVC는 Model, View, Controller의 약자로, 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴이며, 스프링에서는 Model, View, Controller 구성요소를 사용해 다양한 HTTP Request를 처리하고 응답할 수 있도록 하는 프레임워크이다.

  • Model : 코드내의 데이터 집합을 전달해주는 역할을 수행

    • 모델은 애플리케이션의 정보(데이터)를 나타낸다.
  • Controller : 데이터와 내부 비즈니스 로직 사이의 상호동작을 관리한다.

    • 컨트롤러는 모델에 명령을 보냄으로써 모델의 상태를 변경할 수 있다. (예: 워드 프로세서에서 문서를 편집하는 것) 또, 컨트롤러가 관련된 뷰에 명령을 보냄으로써 모델의 표시 방법을 바꿀 수 있다. (문서를 스크롤하는 것)
  • View : 화면을 그리는 역할 수행

    • 뷰는 사용자가 볼 결과물을 생성하기 위해 모델로부터 정보를 얻어 온다.
    • 텍스트, 체크박스 항목 등과 같은 사용자 인터페이스 요소

동작 원리

  1. 브라우저에서 local:8080/hello-mvc로 요청한다.
  2. 톰캣 서버에서 요청을 받아 hello-mvc 라는게 왔다는 것을 스프링 컨테이너로 던져준다.
  3. 컨테이너는 우선적으로 hello-mvc라는 Controller를 찾고 hello-mvc에 맵핑된 @GetMapping()가 있는지 확인하고 매핑된 메소드를 호출한다.
  4. 스프링에게 리턴 값을 보내고, 동시에 Model에 키, 값의 데이터를 넣어 보낸다.
  5. 스프링이 화면(View) 관련된 연산을 처리해주는 해결자 viewResolver가 동작하여 해당 View(html 파일)를 찾아주고 템플릿 엔진에 연결시켜준다(넘긴다).
  6. 템플릿 엔진이 렌더링을 해서 변환한 html을 웹브라우저에 반환(반영)한다.

즉, MVC와 템플릿 엔진 방법은 HTML을 그대로 반환하는 것이 아니라 서버에서 HTML을 동적으로 바꿔서 클라이언트나 웹 브라우저에 HTML을 반환하는 동작을 한다.

3. API

  • 클라이언트(안드로이드, ios 등)와 개발을 진행하거나 서버끼리 데이터를 전달할 때 서버가 JSON이라는 데이터 구조 포맷으로 클라이언트 및 서버에게 데이터를 전달한다.
  • 서버끼리 통신할 때, html을 사용할 필요가 없이 데이터의 흐름이 중요하기 때문에 API 방식을 많이 사용한다.

동작 원리

  1. 웹브라우저에서 localhost:8080/hello-api를 요청
  2. 톰켓 서버에서 요청을 받아 hello-api가 왔다고 스프링한테 던짐.
  3. 스프링은 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 패턴으로 작성

테스트 메소드에서 중요한 것은 정상로직뿐만 아니라 예외적인 처리도 중요하다

0개의 댓글