01. [Springboot] Repository, Service, Model, Controller 세팅 및 사용하기

zero zoo·2024년 5월 5일
0
post-thumbnail

이전 게시물 : 01. [Springboot] 공공데이터포탈 API 사용한 Controller 만들기 (API 금융위원회_주식시세정보)
이전 게시물에서 Springboot 상에서 공공데이터포탈 API를 사용하였습니다. 하지만 이를 받아 프레임워크상에서 어떻게 사용하였는지에 대한 정보를 많이 생략하였는데, 이를 SpringBoot 세팅을 어떻게 하였는지에 대한 정보와 함께 설명하려 합니다.

구성

  1. Springboot API서버를 세팅했다면, 가장 상위에 기본적으로 만들어지는 Class가 있습니다. ChartKrxApplication.java
  2. 애플리케이션에서 가져다 쓰게될 Controller, APIController.java
  3. 공공데이터포탈 API에서 가져올 데이터 중 필요한 데이터 구조의 클래스 정의, Price.java
  4. 가져온 데이터를 통신이 끊기기 전까지 가지고 있을 Repository, MemoryPriceRepository.java 와 그 interface Repository, PriceRepository.java
    • 사실 한가지 종류의 Repository 밖에 없었으므로, interface가 굳이 필요하지는 않았습니다 (공부목적ㅎㅎ)
  5. Repository 내의 데이터를 관리/사용할 수 있도록 하는 함수들이 정의된 Service class, PriceService.java

Springboot Application main 소스

package chart.chart_KRX;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

main 소스는 간결합니다. 어노테이션과 run 함수를 이용하여 Springboot 프레임워크를 빌드하여 실행합니다.
여기서 중요한 건, @SpringBootApplication 어노테이션입니다.

@SpringBootApplication은 스프링 부트의 가장 기본적인 설정을 선언해 줍니다.
해당 어노테이션을 보면 @ComponentScan과 @EnableAutoConfiguration등의 어노테이션이 다시 선언되어 있습니다.
스크랩 - [Spring Boot] @SpringBootApplication 이란?


데이터의 기본적인 구조 설계, Model

package chart.chart_KRX.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
public class Price {
    private Long id;
    private String itemId;
    private String name;
    private String date;
    private Integer open;
    private Integer close;
    private Integer high;
    private Integer low;
}

Repository에 쌓게 될 데이터의 기본 구성입니다.
기본적으로 키(key) - 값(value) 형식으로 저장하고, getter와 setter로 지정 및 사용됩니다.
여기서 눈여겨 볼 것은, 위 정의에서 이를 편하게 해주는 lombok 라이브러리입니다.

lombok

Java의 라이브러리로 반복되는 메서드를 Anotation을 사용해 자동으로 작성해주는 아주 편리한 라이브러리입니다.
Java에서 보통 Model 클래스나 Entity같은 도메인 클래스 등에는 여러 속성이 존재하고 이들이 갖는 프로퍼티에 대해서 Getter, Setter, 생성자 등을 매번 작성해줘야하지만
Lombok을 이용한다면 어노테이션을 이용하는 것 만으로 자동으로 Getter, Setter, 생성자 등의 코드를 작성해줘 번거로운 과정을 제거해줍니다.

lombok 라이브러리 덕분에, 별도의 정의 없이 getter와 setter를 사용할 수 있습니다. (예시 : itemId -> getItemId , setItemId)

데이터 저장소, Repository

//@@@@@@@@@@@ interface PriceRepository

package chart.chart_KRX.repository;
import chart.chart_KRX.model.Price;
import java.util.List;

public interface PriceRepository {
    Price save(Price price);
    List<Price> findAll();
    void clearStore();
}
//@@@@@@@@@@@ repository MemoryPriceRepository

package chart.chart_KRX.repository;
import chart.chart_KRX.model.Price;
import org.springframework.stereotype.Repository;
import java.util.*;

@Repository
public class MemoryPriceRepository implements PriceRepository{
    private static Map<Long, Price> store = new HashMap<>();
    private static long sequence = 0L; // 0 1 2 순으로 키값 설정
	
    // Repository에 신규 데이터 추가 및 저장
    @Override
    public Price save(Price price){
        price.setId(++sequence);
        store.put(price.getId(), price);
        return price;
    }

	// Repository 내 모든 데이터 return
    @Override
    public List<Price> findAll() {
        return new ArrayList<>(store.values());
    }

	// Repository 내 모든 데이터 초기화
    @Override
    public void clearStore() {
        store.clear();
    }
}

Interface를 정의하며 여러 클래스 및 repository를 관리하려 했으나,
한가지의 repository 외에 필요성이 떨어지게 되어 interface의 필요성이 조금 떨어지긴 했습니다.

여기서 중요한 점은, @Repository를 정의할 때, store는 id와 클래스의 Map 구조로 정의되어야 한다는 점입니다.
위 코드에서도 Map<Long, Price> 형식으로 정의되었습니다.

이후 데이터 추가용 save, 모든 데이터 호출용 findAll, 초기화용 clearStore를 선업했습니다.

데이터 조작 및 관리, Service

package chart.chart_KRX.service;

import chart.chart_KRX.model.Price;
import chart.chart_KRX.repository.PriceRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class PriceService {
    private final PriceRepository priceRepository;

    @Autowired
    public PriceService(PriceRepository priceRepository) {
        this.priceRepository = priceRepository;
    }
    
    public Long addDayPrice(Price price) {
        priceRepository.save(price);
        return price.getId();
    }

    public List<Price> listAll() {
        return priceRepository.findAll();
    }

    public void clearStore() {
        priceRepository.clearStore();
    }
}

Repository내 데이터들을 관리, 조작, 사용 등의 기능을 위한 함수들을 포함한 클래스입니다.
기본적으로 대표적인 데이터 처리 기능인 CRUD 를 포함하고 있지만, 여기서는 조회용도로만 사용하기 때문에 update, delete 등의 함수가 포함되어 있지 않습니다.

Repository에 정의되어 있는 함수를 사용하여 간단하게 풀어냅니다.
그리고 주로 이 Service에 있는 함수들을 기본적인 단위테스트에 사용합니다.

위코드에서는 @Autowired에 주목할 필요가 있습니다.

Spring IoC 컨테이너 / 빈 Bean
Bean 설정 소스에서 정의를 읽고, Bean을 구성하고 제공, 의존관계를 설정 → Spring IoC 컨테이너가 관리하는 자바 객체를 빈(Bean)이라고 부릅니다.

  • BeanFactory : 스프링 빈 컨테이너에 접근하기 위한 최상위 인터페이스
  • ApplicationContext : BeanFactory의 하위 인터페이스, Bean을 리스트처럼 보관하는 인터페이스

Autowired

이 어노테이션을 특정 필드에 부여하면 IoC컨테이너 안에 존재하는 특정 필드와 같은 타입의 Bean을 찾아 자동으로 주입해줍니다.

만약 @Autowired를 사용하지 않았다면, Service 클래스 정의를 위해 Repository도 따로 새로 정의를 해줘야 했을 것이고, Repository 클래스도 Pirce 클래스를 정의해주어야 했을 것입니다. 이 과정을 생략합니다.

즉, 생성자에 @Autowired 가 있으면 스프링이 연관된 객체를 스프링 컨테이너에서 찾아서 넣어줍니다. 그리고 이렇게 객체 의존관계를 외부에서 넣어주는 것을 DI (Dependency Injection), 의존성 주입이라 합니다

애플리케이션과 소통하는, Controller

이전 게시물 : 01. [Springboot] 공공데이터포탈 API 사용한 Controller 만들기 (API 금융위원회_주식시세정보)
코드와 설명은 위 링크에 모두 있습니다.


컨트롤러는 MVC 패턴중 하나(Model, View, Controller)로, 모델과 뷰를 분리하기 위한 패턴으로, 양쪽과 모두 소통하는 역할을 수행합니다.
1. 사용자들이 웹브라우저에서 URI/URL로 요청을 보내면, 그 요청을 컨트롤러가 받게됩니다.
2. 요청에 대한 응답을 View, 애플리케이션으로 반환합니다.


출처 :
https://bamdule.tistory.com/31
https://meojiktard.tistory.com/11
https://hstory0208.tistory.com/entry/Spring-Lombok롬복이란-설치부터-사용법까지
https://yangtaeyoung.github.io/docs/spring/autowired/

profile
한방향으로 지그재그

0개의 댓글