스프링 부트 백엔드 개발 강좌, 스프링 데이터 JPA에서 제공하는 메서드 사용해보기

안녕하세요! 이번 강좌에서는 스프링 부트와 스프링 데이터 JPA를 이용한 백엔드 개발을 다뤄보겠습니다.
스프링 데이터 JPA는 객체 관계 매핑(ORM)을 위한 강력하고 유연한 프레임워크로, 데이터베이스와의 상호작용을
간편하게 만들어 줍니다. 특히, 스프링 데이터 JPA는 다양한 메서드를 제공하여 개발자가 보다
쉽게 CRUD(생성, 읽기, 업데이트, 삭제) 작업을 수행할 수 있도록 도와줍니다.

1. 스프링 데이터 JPA란?

스프링 데이터 JPA는 스프링 프레임워크와 JPA(Java Persistence API)를 기반으로 한 데이터의
영속성을 관리하는 라이브러리입니다. JPA는 자바 객체를 데이터베이스의 테이블과 매핑하여
데이터베이스의 데이터를 Java 객체로 관리할 수 있게 해줍니다. 이를 통해 데이터베이스와의
상호작용이 더 직관적이고 간단해집니다.

2. 스프링 부트 프로젝트 설정

스프링 부트를 이용한 프로젝트를 설정하는 과정은 매우 간단합니다. start.spring.io를 통해
필요한 종속성을 선택한 후, ZIP 파일을 다운로드하여 프로젝트를 생성할 수 있습니다.
이번 예제에서는 Spring Web, Spring Data JPA, H2 Database를 추가합니다.

2.1 Gradle 또는 Maven 설정

다운로드한 프로젝트의 build.gradle 또는 pom.xml 파일에
다음 의존성을 추가해줍니다.

dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
        implementation 'org.springframework.boot:spring-boot-starter-web'
        runtimeOnly 'com.h2database:h2'
    }

3. Entity 클래스 만들기

스프링 데이터 JPA를 사용하기 위해서는 먼저 데이터베이스의 테이블과 매핑될 Entity 클래스를 정의해야 합니다.
예를 들어, 간단한 사용자 정보를 저장하는 `User` 클래스를 만들어 보겠습니다.

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

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String username;
    private String email;

    // Getters and Setters
}

4. Repository 인터페이스 구현하기

스프링 데이터 JPA는 Repository라는 개념을 도입하여 데이터베이스 접근을 간편하게 만들어 줍니다.
Repository 인터페이스를 생성하여 필요한 메서드를 정의합니다.

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

public interface UserRepository extends JpaRepository {
    User findByUsername(String username);
}

5. 서비스 클래스 만들기

서비스 클래스에서는 실제 비즈니스 로직을 구현하게 되며, Repository를 주입받아 CRUD 작업을 수행합니다.
예를 들어, `UserService` 클래스를 만들어 보겠습니다.

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

import java.util.List;

@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User save(User user) {
        return userRepository.save(user);
    }

    public List findAll() {
        return userRepository.findAll();
    }

    public User findById(Long id) {
        return userRepository.findById(id).orElse(null);
    }

    public void delete(Long id) {
        userRepository.deleteById(id);
    }
}

6. Controller 클래스 만들기

컨트롤러 클래스는 HTTP 요청을 처리하고 클라이언트와의 상호작용을 담당합니다. RESTful API를 구현하기 위해
`UserController` 클래스를 작성하겠습니다.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/users")
public class UserController {
    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @PostMapping
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }

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

    @GetMapping("/{id}")
    public ResponseEntity getUserById(@PathVariable Long id) {
        User user = userService.findById(id);
        return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
    }

    @DeleteMapping("/{id}")
    public ResponseEntity deleteUser(@PathVariable Long id) {
        userService.delete(id);
        return ResponseEntity.noContent().build();
    }
}

7. 스프링 데이터 JPA에서 제공하는 메서드 사용

스프링 데이터 JPA는 기본 제공 메서드를 통해 많은 작업을 간단하게 처리할 수 있도록 도와줍니다.
여기서는 몇 가지 주요 메서드에 대해 살펴보겠습니다.

7.1 findAll

findAll() 메서드는 데이터베이스 내 모든 레코드를 조회하는 데 사용됩니다.
이 메서드는 List 형태로 모든 엔티티를 반환합니다.

7.2 findById

findById(Long id) 메서드는 특정 ID에 해당하는 엔티티를 조회합니다.
반환값은 Optional 타입으로, 결과가 없는 경우 Optional.empty()를 반환합니다.

7.3 save

save(User user) 메서드는 새 엔티티를 저장하거나 기존 엔티티를 업데이트합니다.
이 메서드는 비즈니스 로직을 간단하게 구현하도록 도와줍니다.

7.4 deleteById

deleteById(Long id) 메서드는 주어진 ID에 해당하는 엔티티를 삭제합니다.
해당 엔티티가 데이터베이스에서 삭제됩니다.

7.5 Query Methods

스프링 데이터 JPA는 쿼리 메서드를 사용하여 복잡한 쿼리를 정의할 수 있습니다. 예를 들어,
findByUsername(String username) 메서드는 입력된 사용자 이름과 일치하는
사용자 정보를 조회합니다. Query Method는 메서드 이름을 통해 자동으로 쿼리가 생성됩니다.

8. JPA 쿼리 사용하기

스프링 데이터 JPA는 JPQL(Java Persistence Query Language)과 Native Query를 지원합니다.
경우에 따라 복잡한 쿼리가 필요할 수 있으며, 이런 경우에는 다음과 같은 방법으로 쿼리를 작성할 수 있습니다.

8.1 JPQL 사용

@Query("SELECT u FROM User u WHERE u.username = ?1")
    User findByUsername(String username);

8.2 Native Query 사용

@Query(value = "SELECT * FROM users WHERE username = ?1", nativeQuery = true)
    User findByUsernameNative(String username);

9. 데이터 검증 및 예외 처리

유효성 검사를 통해 데이터의 정합성을 유지할 수 있습니다. 이를 위해 Bean Validation을 사용할 수 있습니다.
스프링에서는 @Valid 어노테이션을 활용하여 요청 본문 데이터의 검증을 간편하게 처리할 수 있습니다.

import javax.validation.Valid;

@PostMapping
public User createUser(@Valid @RequestBody User user) {
    return userService.save(user);
}

10. 테스트 코드 작성하기

모든 애플리케이션은 유닛 테스트와 통합 테스트를 통해 검증되어야 합니다.
스프링 부트에서는 쉽게 테스트 코드를 작성할 수 있습니다.

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest(UserController.class)
public class UserControllerTest {
    @Autowired
    private MockMvc mockMvc;

    @Test
    public void createUser_ShouldReturnUser() throws Exception {
        String newUserJson = "{\"username\":\"testuser\",\"email\":\"test@example.com\"}";

        mockMvc.perform(post("/api/users")
                .contentType(MediaType.APPLICATION_JSON)
                .content(newUserJson))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.username").value("testuser"));
    }
}

결론

이번 강좌에서는 스프링 부트를 사용한 백엔드 개발과 스프링 데이터 JPA에서 제공하는 메서드들에 대해
알아보았습니다. 스프링 데이터 JPA는 데이터베이스와의 상호작용을 더욱 간편하게 만들어주는 강력한 도구입니다.
다양한 메서드와 쿼리 기능을 통해 신속하고 효율적인 백엔드 개발이 가능하다는 것을 알 수 있었습니다.
앞으로도 다양한 기능과 사례를 통해 스프링 부트를 활용한 개발을 이어가시길 바랍니다.