[Spring Boot] 3. 스프링 부트3 구조 이해하기

김민경·2024년 7월 2일
post-thumbnail

'스프링 부트3 백엔드 개발자 되기' 책을 참고하며 작성 중 입니다.


스프링 부트 계층

  • 계층 : 각자의 역할과 책임이 있는 어떤 소프트웨어의 구성 요소
    • 각 계층은 서로 소통할 수는 있지만 다른 계층에 직접 간섭하거나 영향을 미치지 않는다.

프렌젠테이션 계층

HTTP 요청을 받고 이 요청을 비즈니스 계층으로 전송하는 역할
ex) Controller

비즈니스 계층

모든 비즈니스 로직 (서비스를 만들기 위한 로직) 을 처리
ex) Service

퍼시스턴스 계층

모든 데이터베이스 관련 로직 처리
데이터베이스에 접근하는 DAO 객체를 사용할 수도 있음

DAO : 데이터베이스 계층과 상호작용하기 위한 객체

ex) Repository

계층은 개념의 영역이며 Controller, Service, Repository는 실제 구현의 영역


스프링 부트 디렉토리

main

실제 코드를 작성하는 공간, 소스 코드 및 리소스 파일

templates

HTML과 같은 뷰 관련 파일

static

JS, CSS, 이미지와 같은 정적 파일

application.yml

스프링 부트 서버가 실행되면 자동으로 로딩되는 파일

test

프로젝트의 소스 코드를 테스트할 목적의 코드나 리소스 파일

build.gradle

빌드를 설정하는 파일, 의존성이나 플러그인 설정

setting.gradle

빌드할 프로젝트의 정보를 설정하는 파일


실제 적용

build.gradle

필요한 의존성 추가

  • Spring Data JPA

  • 인메모리 Database H2

  • lombok

    dependencies {
       implementation 'org.springframework.boot:spring-boot-starter-web'
       testImplementation 'org.springframework.boot:spring-boot-starter-test' 
     //원래 입력된 의존성들
    
     //새로 추가한 부분
       implementation 'org.springframework.boot:spring-boot-starter-data-jpa' 
       runtimeOnly 'com.h2database:h2'
       compileOnly 'org.projectlombok:lombok'
       annotationProcessor 'org.projectlombok:lombok'
    }
    

키워드

implementation

프로젝트 코드가 컴파일 시점과 런타임에 모두 해당 라이브러리를 필요로 할 때 사용

testImplementation

프로젝트의 테스트 코드를 컴파일하고 실행할 때만 필요한 의존성을 설정
테스트 코드에서만 사용, 메인 애플리케이션 코드에서는 사용하지 않음

runtimeOnly

런타임에만 필요한 의존성
컴파일 시에는 필요하지 않지만, 애플리케이션을 실행할 때 필요한 라이브러리 설정

compileOnly

컴파일 시에만 필요, 런타임에는 포함되지 않아야 하는 의존성 지정

annotationProcessor

컴파일 시에 애너테이션을 처리할 때 사용하는 도구의 의존성 지정


계층 만들기

Presentation

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class TestContoller {
  @Autowired
  TestService testService;

  @GetMapping("/test")
  public List<Member> getAllMembers(){
      List<Member> members = testService.getAllMembers();
      return members;
  }
}

Business

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class TestService {
  @Autowired
  MemberRepository memberRepository;

  public List<Member> getAllMembers(){
      return memberRepository.findAll();
  }
} 

DAO

member라는 이름의 테이블에 접근하는 데 사용할 객체

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
@Entity
public class Member {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column( name = "id", updatable = false)
  private Long id;

  @Column(name = "name", nullable = false)
  private String name;
}

Persistence

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MemberRepository extends JpaRepository<Member, Long> {

}

작동 확인

data.sql

현재 인메모리 데이터베이스 사용이기에 데이터가 휘발성
-> data.sql을 추가하여 실행할 때 원하는 데이터를 자동으로 넣는 작업

INSERT INTO member(id,name) VALUES (1,'name1')
INSERT INTO member(id,name) VALUES (2,'name2')
INSERT INTO member(id,name) VALUES (3,'name3')

application.yml

show-sql, format_sql

  • 데이터베이스에 쿼리할 일이 있으면 실행 구문을 모두 보여줌

defer-datasource-initialization

  • 실행할 때 테이블을 생성하고 data.sql 파일에 있는 쿼리 실행

    spring:
     jpa:
       #전송 쿼리 확인
       show-sql: true
       properties:
         hibernate:
           format_sql: true
       # 테이블 생성 후 data.sql 실행
       defer-datasource-initialization: true


요청-응답 과정

  1. Postman -> Tomcat 요청
  2. 디스패처 서블릿이 URL 분석 후 이 요청을 처리할 수 있는 Controller 찾기
  3. TestController에 있는 getAllMembers() 메소드가 비즈니스 계층, 퍼시스턴스 계층을 지나 필요한 데이터를 반환
  4. 뷰 리졸버템플릿 엔진을 사용해 HTML 문서를 만들거나 JSON, XML 등의 데이터를 생성
  5. 해당 데이터를 반환하여 Postman으로 확인

    요청

    http://localhost:8080/test

    반환

    [
      {
          "id": 1,
          "name": "name1"
      },
      {
          "id": 2,
          "name": "name2"
      },
      {
          "id": 3,
          "name": "name3"
      }
    ]
profile
뭐든 기록할 수 있도록

0개의 댓글