스프링 부트 백엔드 개발 강좌, 스프링 부트 3 코드 이해하기

안녕하세요! 이번 강좌에서는 스프링 부트 3의 코드를 이해하고, 백엔드 개발 방법론에 대해 자세히 알아보겠습니다. 스프링 부트는 자바 기반의 프레임워크로, 빠르고 쉽게 웹 애플리케이션을 구축할 수 있도록 도와줍니다. 이번 강좌를 통해 스프링 부트의 기본 개념부터 고급 기능까지 폭넓게 다루어보겠습니다.

1. 스프링 부트란?

스프링 부트는 스프링 프레임워크의 확장이며, 전통적인 스프링 애플리케이션을 더욱 쉽게 설정하고 배포할 수 있는 도구입니다. 일반적으로 스프링 애플리케이션을 설정할 때 매우 많은 설정 파일과 XML 구성이 필요하지만, 스프링 부트는 자동 설정(Auto Configuration)과 스타터 의존성(Starter Dependencies)을 통해 이 과정을 간소화합니다.

2. 스프링 부트 3의 주요 기능

  • 자동 구성 기능: 스프링 부트는 클래path를 기반으로 필요한 Bean을 자동으로 구성합니다.
  • 스타터 의존성: 여러 의존성을 통합해 관리할 수 있는 간편한 방법을 제공합니다.
  • 액츄에이터: 애플리케이션의 상태와 성능을 모니터링할 수 있는 도구를 제공합니다.
  • 테스트 지원: 스프링 부트는 테스트 유닛을 쉽게 작성할 수 있도록 돕습니다.
  • Spring WebFlux: 반응형 프로그래밍을 지원하여 비동기 애플리케이션을 구축할 수 있습니다.

3. 스프링 부트 3 환경 설정

스프링 부트를 사용하기 위해서는 먼저 개발 환경을 설정해야 합니다. 이 절에서는 스프링 부트 프로젝트를 생성하는 방법을 알아보겠습니다.

3.1. Spring Initializr 사용하기

스프링 부트 프로젝트를 시작하려면, Spring Initializr를 사용할 수 있습니다. 이 웹 기반 도구를 통해 필요한 모든 의존성을 설정할 수 있습니다.

https://start.spring.io

위의 링크에서 프로젝트의 메타데이터를 입력하고 필요한 의존성을 추가하면, 스프링 부트 프로젝트의 기본 골격을 다운로드할 수 있습니다.

3.2. IDE 설정

다운로드한 프로젝트를 IDE(통합 개발 환경, 예: IntelliJ IDEA 또는 Eclipse)에 로드합니다. 이 과정에서 Maven이나 Gradle을 통한 의존성 관리가 자동으로 설정됩니다.

4. 스프링 부트 애플리케이션 구조

스프링 부트 프로젝트는 다음과 같은 구조로 구성됩니다:


com.example.demo
├── DemoApplication.java
├── controller
│   ├── HelloController.java
├── service
│   ├── HelloService.java
└── repository
    ├── HelloRepository.java

각 폴더는 크게 다음과 같은 역할을 합니다:

  • controller: 클라이언트의 요청을 처리하는 컨트롤러들이 위치합니다.
  • service: 비즈니스 로직을 처리하는 서비스 클래스가 위치합니다.
  • repository: 데이터베이스와의 상호작용을 처리하는 레포지토리가 위치합니다.

5. 기본 웹 애플리케이션 만들기

이제 간단한 웹 애플리케이션을 만들어 보겠습니다. 이 애플리케이션은 “Hello, World!” 메시지를 반환하는 REST API를 생성합니다.

5.1. HelloController.java

다음과 같이 컨트롤러 클래스를 작성합니다:


package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, World!";
    }
}

5.2. DemoApplication.java

메인 애플리케이션 클래스는 다음과 같습니다:


package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

5.3. 애플리케이션 실행

이제 애플리케이션을 실행하고 웹 브라우저에서 http://localhost:8080/hello 를 입력하면 “Hello, World!” 메시지를 볼 수 있습니다.

6. 스프링 부트의 의존성 관리

스프링 부트는 Maven 또는 Gradle을 통해 의존성을 관리합니다. 기본적으로 Maven을 사용할 것입니다.

6.1. pom.xml 수정하기

프로젝트의 pom.xml 파일에는 필요한 의존성을 추가합니다. 아래는 RESTful 서비스를 위한 기본 의존성입니다:


<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <jdk.version>17</jdk.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

7. 데이터베이스와의 연동

스프링 부트를 사용하여 간단한 CRUD(Create, Read, Update, Delete) 기능을 구현할 수 있습니다. 이번 절에서는 H2 데이터베이스를 사용하여 데이터베이스와의 연동 방법을 설명하겠습니다.

7.1. H2 데이터베이스 의존성 추가

H2 데이터베이스는 메모리 기반의 데이터베이스로, 테스트 및 개발에 적합합니다. 아래의 의존성을 pom.xml에 추가합니다:


<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

7.2. 데이터베이스 설정

이제 application.properties 파일을 수정하여 데이터베이스 설정을 추가합니다:


spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

7.3. 엔티티 클래스 정의하기

다음으로, 단순한 사용자 정보를 저장할 수 있는 User 엔티티 클래스를 생성합니다:


package com.example.demo.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private String email;

    // getters and setters
}

7.4. 레포지토리 생성하기

이제 User 엔티티에 대한 CRUD 기능을 제공할 수 있는 UserRepository 인터페이스를 정의합니다:


package com.example.demo.repository;

import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository {
}

8. RESTful API 구현하기

마지막으로, User 엔티티에 대한 CRUD API를 구현해보겠습니다.

8.1. UserController.java

다음과 같이 RESTful API를 제공하는 컨트롤러를 작성합니다:


package com.example.demo.controller;

import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @GetMapping
    public List getAllUsers() {
        return userRepository.findAll();
    }

    @PostMapping
    public ResponseEntity createUser(@RequestBody User user) {
        return new ResponseEntity<>(userRepository.save(user), HttpStatus.CREATED);
    }

    @GetMapping("/{id}")
    public ResponseEntity getUserById(@PathVariable(value = "id") Long userId) {
        return userRepository.findById(userId)
                .map(user -> new ResponseEntity<>(user, HttpStatus.OK))
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @PutMapping("/{id}")
    public ResponseEntity updateUser(@PathVariable(value = "id") Long userId, @RequestBody User userDetails) {
        return userRepository.findById(userId)
                .map(user -> {
                    user.setName(userDetails.getName());
                    user.setEmail(userDetails.getEmail());
                    return new ResponseEntity<>(userRepository.save(user), HttpStatus.OK);
                })
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }

    @DeleteMapping("/{id}")
    public ResponseEntity deleteUser(@PathVariable(value = "id") Long userId) {
        return userRepository.findById(userId)
                .map(user -> {
                    userRepository.delete(user);
                    return new ResponseEntity(HttpStatus.NO_CONTENT);
                })
                .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }
}

9. 테스트 및 배포

스프링 부트에서는 JUnit을 사용하여 테스트를 수행할 수 있습니다. 효율적인 테스트 작성을 통해 애플리케이션의 품질을 높일 수 있습니다.

9.1. 테스트 코드 작성하기

간단한 테스트 코드를 작성해보겠습니다:


package com.example.demo;

import com.example.demo.controller.UserController;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import static org.mockito.Mockito.*;

public class UserControllerTest {

    @InjectMocks
    private UserController userController;

    @Mock
    private UserRepository userRepository;

    @BeforeEach
    void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    void getAllUsers() {
        userController.getAllUsers();
        verify(userRepository, times(1)).findAll();
    }

    @Test
    void createUser() {
        User user = new User();
        user.setName("Test User");
        when(userRepository.save(user)).thenReturn(user);

        userController.createUser(user);
        verify(userRepository, times(1)).save(user);
    }
}

9.2. 애플리케이션 배포

스프링 부트 애플리케이션은 패키징 후 독립 실행형 JAR 파일로 배포할 수 있습니다. Maven을 사용하여 빌드를 수행합니다:

mvn clean package

이후 target 디렉토리에서 생성된 JAR 파일을 실행하여 서버를 시작할 수 있습니다:

java -jar demo-0.0.1-SNAPSHOT.jar

10. 스프링 부트 마이크로서비스 아키텍처

스프링 부트는 마이크로서비스 아키텍처를 구축하는 데 매우 유용합니다. 여러 개의 독립적인 서비스를 구축하고 이들이 서로 통신하도록 구성할 수 있습니다.

10.1. 마이크로서비스의 장점

  • 독립적인 배포: 각 서비스는 독립적으로 배포할 수 있습니다.
  • 확장성: 서비스의 필요에 따라 확장이 가능합니다.
  • 유연성: 기술 스택에 대한 유연성이 있습니다.

11. FAQ

11.1. 스프링 부트를 학습하는 데 필요한 기본 지식은 무엇인가요?

자바 프로그래밍 언어에 대한 기본적인 지식과 스프링 프레임워크에 대한 이해가 필요합니다.

11.2. 스프링 부트를 배우는 추천 자료는 무엇인가요?

스프링 공식 문서 및 온라인 강좌, 관련 서적을 추천합니다.

12. 결론

이번 강좌에서는 스프링 부트 3의 기본 구조와 기능에 대해 알아보았습니다. 스프링 부트는 매우 강력한 프레임워크로, 다양한 애플리케이션을 빠르게 개발할 수 있는 장점을 제공합니다. 앞으로도 계속해서 깊이 있는 학습을 통해 더 많은 기능을 익혀보시길 바랍니다!