개발노트

3. [Spring Boot] JPA, findAll() 메소드로 전체 Data 가져오기 본문

서버 개발/Spring Boot

3. [Spring Boot] JPA, findAll() 메소드로 전체 Data 가져오기

mroh1226 2024. 4. 15. 14:36
반응형

JPA로 Data를 가져오기 위한 어노테이션 종류와 함께,
폴더구조(Model - Repository - Service - Controller)와 관계에 대해서 알아봅니다.

 

최종적으로 엔드포인트로 JSON 데이터를 가져오는 것을 예제로 만들어보겠습니다.

예제는 JPA의 findAll() 메소드를 통해 DB에 있는 Ingredient 테이블에서 모든 재료 데이터를 가져옵니다.


폴더 구조.

 

구조 설명.

  1. Model:
    • 역할: 데이터 모델이나 엔티티 클래스를 정의하는데 사용됩니다.
    • 특징:
      • 모델은 애플리케이션에서 사용되는 데이터의 구조를 정의합니다.
      • DB 테이블(@Table)의 엔터티(@Entity)를 표현하고, 클라이언트와 서버 간의 데이터 교환에 사용됩니다.
      • 주로 Java Beans 규칙을 따르며, 필드, 게터(@Getter) 및 세터(@Setter) 어노테이션을 포함합니다.
  2. Repository:
    • 역할: 데이터베이스와 상호 작용하는 인터페이스를 정의합니다.
    • 특징:
      • 리포지토리는 데이터의 영구 저장소인 데이터베이스와의 상호 작용을 추상화합니다.
      • 주로 Spring Data JPA와 함께 사용되며, JpaRepository 인터페이스를 확장하여 CRUD(Create, Read, Update, Delete) 작업을 정의합니다.
      • 각 메서드는 데이터베이스와 상호 작용하기 위한 쿼리를 정의하고, 데이터 조작을 수행합니다.
  3. Service:
    • 역할: 비즈니스 로직을 처리하는 클래스를 정의합니다.
    • 특징:
      • 서비스는 컨트롤러와 리포지토리 사이에서 중간 계층을 형성하며, 비즈니스 로직을 구현합니다.
      • 주로 트랜잭션 관리, 데이터 유효성 검사, 예외 처리 등을 수행합니다.
      • 여러 컨트롤러에서 재사용되는 코드를 서비스에 모듈화할 수 있습니다.
  4. Controller:
    • 역할: API 엔드포인트를 정의하고 클라이언트의 요청을 처리하는 클래스를 포함합니다.
    • 특징:
      • 컨트롤러는 HTTP 요청을 처리하고, 해당 요청에 대한 응답을 반환합니다.
      • 주로 Spring의 @RestController 어노테이션을 사용하여 정의됩니다.
      • 각 메서드는 특정 URL에 매핑되어 요청을 수신하고, 비즈니스 로직을 호출하여 결과를 반환합니다.

이러한 폴더 구조는 각각의 역할에 따라 코드를 분리하여 유지보수성을 향상시키고, 애플리케이션의 확장성을 높이는 데 도움이 됩니다.

 


Model

Model은 DB의 Table 을 Spring Boot의 Entity로 정의하고 어노테이션으로 Table,Column 명을 Mapping 합니다.

@Getter와 @Setter 어노테이션을 사용하여 Getter와 Setter를 자동생성 합니다.

ingredient 테이블(DB)

ingredient 테이블

Ingredient.java (Spring Boot)
package com.homebar.apiserver.model;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

@Entity
//어노테이션이 있으면 Getter,Setter 자동 생성
@Getter
@Setter
@Table(name = "Ingredient")
public class Ingredient {
    //@Id:Primary Key 설정
    @Id
    //@GeneratedValue: 자동으로 생성되는 것을 나타냄,IDENTITY는 자동 증가를 나타냄
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long ingredient_id;
    //@Column:  엔티티의 필드명과 데이터베이스 테이블의 컬럼명이 다를 때 또는 컬럼의 길이,
    //length 는 명시하지않으면 255를 기본값으로 갖음
    //NULL 허용 여부 등과 같은 속성을 지정해야 할 때 @Column 어노테이션을 사용
    @Column(name = "category_id")
    private Long category_id;

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

    @Column(name = "detail",length = 255)
    private String detail;

    //precision: 정수의 전체 자릿수, scale: 소수점 이하의 자릿수
    @Column(name = "state",precision = 1)
    private String state;

    @Column(name = "created_at")
    @Temporal(TemporalType.DATE)
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date created_at;

}

 

  1. @Entity:
    • 클래스가 JPA 엔티티임을 나타냅니다. 즉, 이 클래스의 객체가 데이터베이스의 테이블과 매핑됩니다.
  2. @Id:
    • 해당 필드가 엔티티의 주요 식별자(primary key)임을 나타냅니다.
  3. @GeneratedValue:
    • 주요 키(Primary Key)의 값을 자동으로 생성하는 방법을 지정합니다.
    • strategy 속성은 생성 전략을 지정하며, 여기서는 **GenerationType.IDENTITY**를 사용하여 데이터베이스의 identity 컬럼을 사용하여 자동 증가하도록 설정했습니다.
  4. @Column:
    • 엔티티의 필드가 데이터베이스 테이블의 열(column)과 매핑됨을 나타냅니다.
    • name 속성은 엔티티 필드와 매핑될 데이터베이스 열의 이름을 지정합니다.
    • nullable 속성은 해당 열이 null 값을 허용하는지 여부를 지정합니다.
    • length 속성은 열의 길이를 지정합니다.
    • precisionscale 속성은 숫자 타입의 열에 대해 전체 자릿수와 소수점 이하 자릿수를 지정합니다.
  5. @Temporal:
    • 날짜 및 시간 필드의 유형을 지정합니다.
    • **TemporalType.DATE**는 날짜만 저장하고 시간 정보는 저장하지 않습니다.
  6. @DateTimeFormat:
    • 날짜 및 시간 필드의 서식을 지정합니다.
    • 여기서는 "yyyy-MM-dd" 형식으로 날짜를 지정하도록 했습니다.

이러한 어노테이션은 JPA(Java Persistence API)를 사용하여 엔티티를 매핑하고, 데이터베이스와의 상호 작용을 쉽게 할 수 있도록 도와줍니다.


Repository

Repository는 Spring 프레임워크에서 데이터베이스와 상호 작용하는 인터페이스를 정의하는데 사용되는 중요한 구성 요소입니다.

주로 데이터베이스와의 CRUD(Create, Read, Update, Delete) 작업을 수행하고 도메인 객체와의 상호 변환을 담당합니다.

일반적으로 Repository는 다음과 같은 역할을 수행합니다:

  1. 데이터 액세스 인터페이스 제공:
    • Repository는 데이터베이스와의 상호 작용을 위한 인터페이스를 제공합니다. 개발자는 Repository를 통해 데이터베이스와의 통신에 필요한 기능을 호출할 수 있습니다.
  2. CRUD 작업 지원:
    • 주로 데이터의 생성(Create), 읽기(Read), 갱신(Update), 삭제(Delete) 작업을 수행합니다. Spring Data JPA를 사용하는 경우, JpaRepository 인터페이스를 확장하여 CRUD 메서드를 자동으로 생성할 수 있습니다.
  3. Query 메서드 정의:
    • Repository는 사용자 정의 쿼리 메서드를 정의하여 데이터베이스로부터 데이터를 검색할 수 있습니다. 이를 통해 데이터베이스에 특정 조건을 적용하여 데이터를 필터링하거나, 연산할 수 있습니다.
  4. 도메인 객체 매핑:
    • Repository는 데이터베이스로부터 검색한 결과를 도메인 객체로 변환하거나, 도메인 객체를 데이터베이스에 저장하기 위해 필요한 매핑을 담당합니다. 이를 통해 데이터베이스의 레코드와 Java 객체 간의 변환을 자동화할 수 있습니다.
  5. 트랜잭션 관리:
    • Repository는 주로 서비스(Service)나 다른 레이어로부터 호출되며, 이때 트랜잭션 처리를 담당합니다. 일반적으로 Spring의 트랜잭션 관리 기능을 사용하여 데이터베이스 작업을 트랜잭션 단위로 처리합니다.

Spring 프레임워크에서는 JpaRepository 인터페이스와 같은 여러 인터페이스를 제공하여 Repository를 간단하게 작성하고 사용할 수 있도록 도와줍니다. 이를 통해 개발자는 데이터베이스와의 상호 작용에 집중할 필요 없이 비즈니스 로직을 구현할 수 있습니다.

IngredientRepository.java
package com.homebar.apiserver.repository;

import com.homebar.apiserver.model.Ingredient;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface IngredientRepository extends JpaRepository<Ingredient,Long> {

}

 

  1. @Repository: 이 어노테이션은 해당 클래스가 데이터 액세스 계층의 구성 요소임을 나타냅니다. Spring에게 이 인터페이스를 빈으로 등록하여 데이터 액세스 작업에 필요한 리소스를 제공하고, 예외를 전파하는 역할을 합니다.
  2. JpaRepository<Ingredient, Long>: **JpaRepository**의 제네릭 타입 파라미터는 엔티티 클래스와 해당 엔티티의 식별자 타입입니다. 여기서 **Ingredient**는 엔티티 클래스이며, **Long**은 해당 엔티티의 식별자 타입입니다. JpaRepository는 이러한 정보를 기반으로 CRUD 작업을 수행합니다.
  3. IngredientRepository: 이 인터페이스는 데이터베이스에 액세스하는 데 필요한 모든 메서드를 상속받습니다. 이 메서드들은 자동으로 Spring Data JPA에 의해 구현됩니다. 따라서 개발자는 별도로 구현할 필요가 없습니다.

Service

Service는 주로 비즈니스 로직을 처리하고 제어하는 역할을 수행하는 컴포넌트입니다. 애플리케이션의 핵심 비즈니스 로직을 구현하고, 이를 트랜잭션 단위로 처리하며, 데이터의 가공, 유효성 검사, 외부 시스템과의 통합 등을 담당합니다. 주로 Controller와 Repository 사이에서 중간 계층 역할을 하며, 다양한 비즈니스 규칙을 구현하고 사용자 또는 클라이언트의 요청을 처리합니다.

Service의 주요 특징과 역할은 다음과 같습니다:

  1. 비즈니스 로직 처리: Service는 애플리케이션의 핵심 비즈니스 로직을 구현하고 처리합니다. 이는 사용자 요청에 따라 데이터 처리, 계산, 변환 등을 수행하는 작업을 포함합니다.
  2. 트랜잭션 관리: Service는 트랜잭션 단위로 데이터의 일관성을 유지하고 관리합니다. 여러 개의 Repository 메서드 호출이 하나의 트랜잭션으로 묶여야 할 때 Service에서 트랜잭션을 시작하고 종료합니다.
  3. Repository와의 상호작용: Service는 Repository를 사용하여 데이터베이스와의 상호 작용을 수행합니다. 비즈니스 로직에 따라 Repository를 호출하여 데이터를 조회, 수정, 삭제하거나 새로운 데이터를 저장합니다.
  4. 데이터 유효성 검사: Service는 입력된 데이터의 유효성을 검사하고 필요에 따라 예외를 처리합니다. 사용자가 올바르지 않은 데이터를 전송했을 때 이를 검증하고 적절한 에러 처리를 수행합니다.
  5. 애플리케이션의 응집성 유지: Service는 관련된 비즈니스 로직을 하나의 단위로 묶어 응집성을 유지합니다. 이를 통해 코드의 가독성을 높이고 유지 보수성을 향상시킵니다.

Spring 프레임워크에서는 Service를 구현할 때 @Service 어노테이션을 사용하여 해당 클래스를 서비스 빈으로 등록하고, 필요한 곳에서 주입하여 사용할 수 있도록 지원합니다. 이를 통해 개발자는 비즈니스 로직을 간편하게 구현하고 관리할 수 있습니다.

 

IngredientService.java
package com.homebar.apiserver.service;

import com.homebar.apiserver.model.Ingredient;
import com.homebar.apiserver.repository.IngredientRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class IngredientService {
    @Autowired
    private IngredientRepository ingredientRepository;
    public List<Ingredient> getAllIngredients(){
        return ingredientRepository.findAll();
    }
    //save(S entity) : 신규 데이터 인서트 혹은 기존 데이터 업데이트(Upsert 와 비슷)
    //findById(데이터형 id) : id로 조회
    //findAll() : Select * 전체 데이터 조회
    //deleteById() : 해당 id의 데이터를 Delete 함
    //deleteAll() : 테이블의 모든 데이터 삭제
}

 

Service의 코드는 **IngredientService**라는 서비스 클래스를 정의하고 있습니다. 이 클래스는 비즈니스 로직을 처리하고, 해당 비즈니스 로직에 필요한 데이터 액세스를 **IngredientRepository**를 통해 수행합니다.

여기서 사용된 어노테이션과 주요 요소에 대해 설명하겠습니다:

  1. @Service: 이 어노테이션은 해당 클래스가 서비스 계층의 구성 요소임을 나타냅니다. 이 클래스는 비즈니스 로직을 담당하고, 컨트롤러나 다른 서비스 클래스 등과의 인터페이스 역할을 합니다. Spring에게 이 클래스를 빈으로 등록하여 관리합니다.
  2. @Autowired: 이 어노테이션은 스프링에 해당 클래스의 빈(bean)을 주입(injection)하라는 것을 나타냅니다. 여기서 IngredientRepository 빈을 주입받아 데이터베이스와의 상호 작용을 수행할 수 있습니다.
  3. getAllIngredients(): 이 메서드는 데이터베이스에서 모든 Ingredient 엔티티를 조회하는 기능을 수행합니다. **IngredientRepository**의 findAll() 메서드를 호출하여 모든 엔티티를 가져옵니다.
  4. IngredientRepository: 이 서비스 클래스는 **IngredientRepository**를 사용하여 데이터베이스 액세스 작업을 수행합니다. 여기서는 findAll() 메서드를 호출하여 모든 재료(Ingredients)를 가져오고 있습니다.

이렇게 정의된 IngredientService 클래스는 컨트롤러(Controller)에서 호출되어 비즈니스 로직을 수행하고, 해당 비즈니스 로직에 필요한 데이터 액세스를 **IngredientRepository**를 통해 처리합니다.

 


Controller

컨트롤러(Controller)는 Spring 애플리케이션에서 클라이언트의 요청을 받고 응답을 반환하는 역할을 담당하는 주요 구성 요소 중 하나입니다. 주로 웹 애플리케이션에서 클라이언트와 상호 작용하는 인터페이스 역할을 합니다.

Spring Framework에서는 여러 가지 방식으로 컨트롤러를 정의할 수 있습니다. Spring MVC를 사용하는 경우, @Controller 또는 @RestController 어노테이션을 사용하여 클래스를 컨트롤러로 지정할 수 있습니다.

주요 역할은 다음과 같습니다:

  1. 요청 매핑(Request Mapping):
    • 컨트롤러는 클라이언트로부터 오는 HTTP 요청을 특정 메서드와 매핑합니다. 이를 통해 요청을 처리할 수 있습니다. @RequestMapping, @GetMapping, @PostMapping 등의 어노테이션을 사용하여 요청 경로와 HTTP 메서드에 대한 매핑을 지정할 수 있습니다.
  2. 비즈니스 로직 연결:
    • 컨트롤러는 클라이언트의 요청을 받아서 비즈니스 로직을 실행하기 위해 서비스(Service)나 다른 관련된 컴포넌트를 호출합니다. 이를 통해 요청에 대한 처리를 완료하고 응답을 생성합니다.
  3. 모델과의 상호 작용:
    • 클라이언트로부터 받은 데이터를 처리하거나, 클라이언트에게 전달할 데이터를 모델과 상호 작용하여 준비합니다. 이를 통해 요청에 따라 데이터를 검색하거나 업데이트할 수 있습니다.
  4. 응답 생성:
    • 컨트롤러는 비즈니스 로직의 결과를 바탕으로 클라이언트에게 응답을 생성합니다. 주로 JSON, XML, HTML 등의 형식으로 응답을 생성하여 클라이언트에게 반환합니다.
  5. 에러 처리:
    • 예외 처리와 에러 페이지를 컨트롤러에서 처리할 수 있습니다. 이를 통해 예상되는 예외 상황에 대해 적절한 처리를 수행하고 사용자에게 적절한 오류 메시지를 제공할 수 있습니다.

컨트롤러는 Spring 애플리케이션에서 매우 중요한 부분을 차지하며, 클라이언트와의 상호 작용을 담당하여 애플리케이션의 기능을 완성하는 데 필수적인 역할을 합니다.

package com.homebar.apiserver.controller;

import com.homebar.apiserver.model.Ingredient;
import com.homebar.apiserver.service.IngredientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
@RestController
@RequestMapping("/ing")
public class IngredientController {
    @Autowired
    private IngredientService ingredientService;

    @GetMapping
    public List<Ingredient> getAllIngredients(){
        var ing = ingredientService.getAllIngredients();
        ing.forEach(System.out::println);
        return ing;
    }
}

 

위의 코드는 Spring Boot 애플리케이션에서 API 엔드포인트를 처리하는 컨트롤러 클래스를 정의합니다.

이 컨트롤러는 /ing 경로에 매핑되어 있습니다.(http://localhost:8080/ing)

여기서 사용된 어노테이션과 컨트롤러의 역할에 대해 설명해보겠습니다:

  1. @RestController:
    • 이 어노테이션은 해당 클래스가 RESTful 웹 서비스의 컨트롤러임을 나타냅니다. Spring Boot는 이 어노테이션이 지정된 클래스를 스캔하여 REST API를 처리하는 데 사용합니다.
  2. @RequestMapping:
    • 클래스 또는 메서드에 대한 요청 매핑을 지정합니다. 여기서는 /ing 경로에 대한 요청을 이 클래스의 메서드에 매핑합니다.
  3. @Autowired:
    • 스프링이 해당 필드에 해당하는 Bean을 자동으로 주입합니다. 여기서는 **IngredientService**의 구현체가 필요하며, 이를 자동으로 주입받습니다.
  4. @GetMapping:
    • HTTP GET 요청을 처리하는 핸들러 메서드를 지정합니다. 여기서는 /ing 경로에 대한 GET 요청을 처리하는 getAllIngredients() 메서드를 지정합니다.
  5. getAllIngredients() 메서드:
    • 이 메서드는 모든 재료(Ingredient)를 반환하는 엔드포인트를 정의합니다. **ingredientService.getAllIngredients()**를 호출하여 모든 재료를 가져온 후, 이를 출력하고 반환합니다.

Model - Repository - Service - Controller 관계도

관계도


예제 빌드.

Application 빌드 후 엔드포인트를 확인합니다.

 

모든 Ingredient(재료) 가져오기 확인완료.

 

 

findAll() 이외에도  다양한 메소드로 조회, 수정, 삭제가 가능합니다.

  •    save(S entity) : 신규 데이터 인서트 혹은 기존 데이터 업데이트(Upsert 와 비슷)
  •     findById(데이터형 id) : id로 조회
  •     findAll() : Select * 전체 데이터 조회
  •     deleteById() : 해당 id의 데이터를 Delete 함
  •     deleteAll() : 테이블의 모든 데이터 삭제

 

다음시간에는 다른 JPA의 메소드 사용법을 알아보고 엔드포인트를 찍어보겠습니다.

반응형
Comments