공공 데이터 포털이란?

공공데이터포털은 공공기관이 생성 또는 취득하여 관리하고 있는 공공데이터를 한 곳에서 제공하는 통합 창구이다.

공공데이터포털에서는 국민이 쉽고편리하게 공공데이터를 이용할 수 있도록 파일데이터, 오픈API, 시각화 등 다양한 방식으로 제공하고 있으며, 누구라도 쉽고 편리한 검색을통해 원하는 공공데이터를 빠르고 정확하게 찾을 수 있다. 

https://www.data.go.kr/index.do

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

사용하기 위한 필요 과정

정말 간단하다. 사이트에 회원 가입 후 사용하길 희망하는 오픈 API에 활용신청 하여 API 키를 발급받으면 된다. 
주의할 점이 있다면 대부분 API는 상시 허가로 되어 있어 신청하자마자 바로 사용할 수 있지만 몇몇 API와 데이터 같은 경우에는 신청 후 승인까지의 대기시간이 있을 수 있다는 점이다.

 

사용하기 전 미리보기 기능

마이페이지 -> API 신청 -> 신청한 API -> 미리보기 버튼을 활용하여 Rest API 방식으로 요청을 보내는 파라미터들을 임의로 조작하여 미리 어떤 결과가 나오는지 확인이 가능하다.

만약 공공데이터 사용이 처음이라면 미리보기 기능을 통해 어디까지 활용이 가능하고 어떻게 활용해야 겠다 계획을 세우고 하는 것을 추천한다.

<미리 보기 한 결과>

 

데이터 포털에서 제공해주는 Java 1.8 샘플 코드

import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.io.BufferedReader;
import java.io.IOException;

public class ApiExplorer {
    public static void main(String[] args) throws IOException {
        StringBuilder urlBuilder = new StringBuilder("http://apis.data.go.kr/1471000/DrbEasyDrugInfoService/getDrbEasyDrugList"); /*URL*/
        urlBuilder.append("?" + URLEncoder.encode("serviceKey","UTF-8") + "=서비스키"); /*Service Key*/
        urlBuilder.append("&" + URLEncoder.encode("pageNo","UTF-8") + "=" + URLEncoder.encode("1", "UTF-8")); /*페이지번호*/
        urlBuilder.append("&" + URLEncoder.encode("numOfRows","UTF-8") + "=" + URLEncoder.encode("3", "UTF-8")); /*한 페이지 결과 수*/
        urlBuilder.append("&" + URLEncoder.encode("entpName","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*업체명*/
        urlBuilder.append("&" + URLEncoder.encode("itemName","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*제품명*/
        urlBuilder.append("&" + URLEncoder.encode("itemSeq","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*품목기준코드*/
        urlBuilder.append("&" + URLEncoder.encode("efcyQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약의 효능은 무엇입니까?*/
        urlBuilder.append("&" + URLEncoder.encode("useMethodQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약은 어떻게 사용합니까?*/
        urlBuilder.append("&" + URLEncoder.encode("atpnWarnQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약을 사용하기 전에 반드시 알아야 할 내용은 무엇입니까?*/
        urlBuilder.append("&" + URLEncoder.encode("atpnQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약의 사용상 주의사항은 무엇입니까?*/
        urlBuilder.append("&" + URLEncoder.encode("intrcQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약을 사용하는 동안 주의해야 할 약 또는 음식은 무엇입니까?*/
        urlBuilder.append("&" + URLEncoder.encode("seQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약은 어떤 이상반응이 나타날 수 있습니까?*/
        urlBuilder.append("&" + URLEncoder.encode("depositMethodQesitm","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*이 약은 어떻게 보관해야 합니까?*/
        urlBuilder.append("&" + URLEncoder.encode("openDe","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*공개일자*/
        urlBuilder.append("&" + URLEncoder.encode("updateDe","UTF-8") + "=" + URLEncoder.encode("", "UTF-8")); /*수정일자*/
        urlBuilder.append("&" + URLEncoder.encode("type","UTF-8") + "=" + URLEncoder.encode("xml", "UTF-8")); /*응답데이터 형식(xml/json) Default:xml*/
        URL url = new URL(urlBuilder.toString());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Content-type", "application/json");
        System.out.println("Response code: " + conn.getResponseCode());
        BufferedReader rd;
        if(conn.getResponseCode() >= 200 && conn.getResponseCode() <= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();
        System.out.println(sb.toString());
    }
}

해당 코드를 그대로 가져와서 수정하여 사용하여도 되지만 가급적 최신 자바 코드 라이브러리와 스프링 부트의 라이브러리를 활용하는 방법으로 코드를 수정하고자 한다.

 

최신 자바 라이브러리(HttpClient) 사용 버전

@RestController
public class DrugOpenAPIController {
    @GetMapping("/publicData")
    public String getDrugInfo() throws Exception {
        HttpClient client = HttpClient.newHttpClient();
        String url = "http://apis.data.go.kr/1471000/DrbEasyDrugInfoService/getDrbEasyDrugList";
        String charset = StandardCharsets.UTF_8.name();
        String query = String.format("serviceKey=%s&pageNo=%s&numOfRows=%s&entpName=%s&itemName=%s&itemSeq=%s&efcyQesitm=%s&useMethodQesitm=%s&atpnWarnQesitm=%s&atpnQesitm=%s&intrcQesitm=%s&seQesitm=%s&depositMethodQesitm=%s&openDe=%s&updateDe=%s&type=%s",
                URLEncoder.encode("Decoding 인증키", charset),
                URLEncoder.encode("1", charset),
                URLEncoder.encode("1", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("", charset),
                URLEncoder.encode("json", charset));

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url + "?" + query))
                .GET()
                .header("Content-Type", "application/json")
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println("Response code: " + response.statusCode());
        HttpHeaders headers = response.headers();
        headers.map().forEach((k, v) -> System.out.println(k + ":" + v));

        String responseBody = response.body();

        // Jackson 객체 생성
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        // JSON 문자열을 Map 객체로 변환
        Map<String, Object> map = mapper.readValue(responseBody, Map.class);

        // 'body' key에 해당하는 부분을 추출
        Map<String, Object> bodyMap = (Map<String, Object>) map.get("body");

        // 'items' key에 해당하는 부분을 추출
        List<Map<String, Object>> items = (List<Map<String, Object>>) bodyMap.get("items");

        // items를 JSON 문자열로 변환
        String prettyItemsJson = mapper.writeValueAsString(items);

        System.out.println(prettyItemsJson); // 수정된 JSON 출력

        return prettyItemsJson;
    }
}

해당 코드에서는 Jackson 객체를 사용하여 응답 body 부분의 item 항목의 데이터를 파싱 하는 것 까지 추가해보았다.

 

스프링 부트에서 권장하는 라이브러리(WebClient) 사용 버전

<필요한 의존성> https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux/3.1.0

implementation 'org.springframework.boot:spring-boot-starter-webflux:3.1.0'

<블록킹 방식>

@RestController
public class DrugOpenAPIController {
    private final static String BASE_URL = "http://apis.data.go.kr/1471000/DrbEasyDrugInfoService/getDrbEasyDrugList";
    private final String API_KEY = "encoding API키";

    @GetMapping(value = "/publicData", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> getDrugInfo() {
        DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL);
        factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);

        WebClient webClient = WebClient.builder()
                .uriBuilderFactory(factory)
                .baseUrl(BASE_URL)
                .build();

        ResponseEntity<String> response = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .queryParam("serviceKey", API_KEY)
                        .queryParam("pageNo", "1")
                        .queryParam("numOfRows", "1")
                        .queryParam("entpName", "")
                        .queryParam("itemName", "")
                        .queryParam("itemSeq", "")
                        .queryParam("efcyQesitm", "")
                        .queryParam("useMethodQesitm", "")
                        .queryParam("atpnWarnQesitm", "")
                        .queryParam("atpnQesitm", "")
                        .queryParam("intrcQesitm", "")
                        .queryParam("seQesitm", "")
                        .queryParam("depositMethodQesitm", "")
                        .queryParam("openDe", "")
                        .queryParam("updateDe", "")
                        .queryParam("type", "json")
                        .build())
                .retrieve()
                .toEntity(String.class).block();

        return response;
    }
}

<논 블록킹 방식>

@RestController
public class DrugOpenAPIController {
    private final static String BASE_URL = "http://apis.data.go.kr/1471000/DrbEasyDrugInfoService/getDrbEasyDrugList";
    private final String API_KEY = "encoding API키";

    @GetMapping(value = "/publicData", produces = MediaType.APPLICATION_JSON_VALUE)
    public Mono<String> getDrugInfo() {
        DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(BASE_URL);
        factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.VALUES_ONLY);

        WebClient webClient = WebClient.builder()
                .uriBuilderFactory(factory)
                .baseUrl(BASE_URL)
                .build();

        Mono<String> response = webClient.get()
                .uri(uriBuilder -> uriBuilder
                        .queryParam("serviceKey", API_KEY)
                        .queryParam("pageNo", "1")
                        .queryParam("numOfRows", "1")
                        .queryParam("entpName", "")
                        .queryParam("itemName", "")
                        .queryParam("itemSeq", "")
                        .queryParam("efcyQesitm", "")
                        .queryParam("useMethodQesitm", "")
                        .queryParam("atpnWarnQesitm", "")
                        .queryParam("atpnQesitm", "")
                        .queryParam("intrcQesitm", "")
                        .queryParam("seQesitm", "")
                        .queryParam("depositMethodQesitm", "")
                        .queryParam("openDe", "")
                        .queryParam("updateDe", "")
                        .queryParam("type", "json")
                        .build())
                .retrieve()
                .bodyToMono(String.class);

        return response;
    }
}
첫 번째 방식(ResponseEntity<String>반환)에서
.toEntity(String.class).block(); 구문을 사용하고 있는데, 이는 호출한 스레드가 데이터를 수신할 때까지 대기하게 하며, 데이터가 도착하면 작업을 계속 진행합니다.
이 방식은 쉽고 직관적인 프로그래밍을 가능하게 하지만, I/O 작업이 많거나 네트워크 지연이 발생할 경우 대기 시간이 길어지고, 이로 인해 전체적인 시스템 성능이 저하될 수 있습니다.
두 번째 방식(Mono<String>반환)은
논블로킹 방식으로, 호출한 스레드가 결과를 기다리지 않고 바로 반환합니다.
이 방식은 리액티브 프로그래밍 패러다임을 따르며, 데이터가 준비될 때까지 다른 작업을 계속 수행할 수 있습니다.
이로 인해 리소스를 효율적으로 사용하고, 시스템 성능을 개선할 수 있습니다.
단, 이 방식은 프로그래밍이 복잡해질 수 있으며, 비동기 프로그래밍에 익숙하지 않은 개발자들에게는 이해하기 어려울 수 있습니다.

 

결론: 블로킹 방식은 쉽고 직관적이지만, 대기 시간이 길어질 수 있으며, 논블로킹 방식은 복잡하지만, 성능 향상과 리소스 효율성을 얻을 수 있다.

주의 사항 (Content-Type 체크)

스프링 프레임워크는 기본적으로 application/json 타입으로 받는 것을 기대하기 때문에

아래와 같이 Content-Type이 application/json 이면 상관 없으나 

해당 사진 처럼 간혹 공공포털 api 에서 text/json으로 반환 해주는 경우가 있어 

해당 경우에는 추가적으로 다음 로직을 추가하여야 한다.

	ExchangeStrategies strategies = ExchangeStrategies
                .builder()
                .codecs(configurer -> configurer.defaultCodecs().jackson2JsonDecoder(new Jackson2JsonDecoder(new ObjectMapper(), MediaType.valueOf("text/json"))))
                .build();

        WebClient webClient = WebClient.builder()
                .baseUrl(BASE_URL)
                .exchangeStrategies(strategies)
                .build();

 

JSON Viwer 확장 플러그인을 사용하여 깔끔하게 표시되는 결과

WebClient란?

WebClient는 Spring 5에서 도입된 비동기적인 방식의 HTTP 프로토콜을 통해 요청을 보낼 때 사용하는 클래스로 기존에 사용되었던 동기적 방식의 RestTemplate를 대체하여 사용되며 블로킹, 논블로킹 I/O 작업을 지원한다. 

(위에 코드에서는 block(); 메소드를 통해 블로킹 I/O 작업을 사용하였다.)

 

<정리가 잘 되어있는 링크>

https://velog.io/@dnrwhddk1/Spring-Web-Client-%EA%B0%9C%EB%85%90-%EB%B0%8F-%EC%82%AC%EC%9A%A9

1. Spring-Boot JAR 파일로 내보내기

자세한 설명은 해당 링크 참조: https://suhanlim.tistory.com/192

만약 GitHub에 있는 코드 그대로 사용시 해당 오류가 발생할 수 있는데 프로그램의 단위테스트 자체가 실패했다는 의미이므로 DB 설정 부분을 지우거나 기존 실습 했던 값으로 바꿔야 한다.

드디어 대망의 jar 파일 생성완료

2. EC2 인바운드 규칙 추가

3. FileZilla를 사용하여 jar 파일을 EC2 내부로 이동

FileZilla 대신 git을 사용하여 작업하여도 된다.

https://filezilla-project.org/download.php?platform=win64

도움을 받은 글: https://app-developer.tistory.com/93

더블 클릭으로 파일 전송

4. EC2에 Java 설치 및 jar 파일 실행

파일 전송 확인

sudo yum install java-17-amazon-corretto-devel

java17 설치 확인 후 chmod +x 파일명.jar 로 실행 권한 부여

java -jar 파일명.jar --spring.datasource.url=jdbc:mysql://엔드포인트:3306/데이터베이스 이름 --spring.datasource.username=유저명 --spring.datasource.password=비밀번호

프로젝트 실행 완료

5. 테스트

http://EC2 IP:8080/medications

6. 안드로이드 프로그램 url 주소 수정

배포 성공!

1. EC2 실행

(인스턴스 실행)

2. Puttygen, Putty 다운로드 후 Puttygen 실행

https://www.puttygen.com/download-putty

https://www.puttygen.com/

EC2 생성시 만들었던 .pem 파일 선택

Save private key 클릭 후 파일명 설정시 파일명.ppk 파일 생성

3. Putty 실행

Browse 버튼을 통해 아까 생성한 .ppk 파일 선택

EC2 IP주소 입력 후 Open

Accept 클릭

ec2-user 입력시 접속이 되면 성공

3. EC2에 MySQL 설치

https://dev.classmethod.jp/articles/ec2-mysql-install-confilicting-requests-error-kr/
sudo dnf install https://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm
sudo dnf install mysql-community-server

해당 명령어 입력시 MySQL 설치 중간 중간 Y/N 을 물을 때 Y입력 

mysql —version 으로 설치가 잘 됬는지 확인

4. EC2를 통해 RDS 접속 후 사용할 DB생성

mysql -u {마스터 사용자 이름} -p -h {RDS 인스턴스 엔드포인트}
// 이후 패스워드 입력

4-2. RDS 데이터베이스 생성, 조회 SQL

CREATE database Medications default character set utf8mb4 collate utf8mb4_unicode_ci;

USE Medications;

CREATE TABLE Medications (
ID INT PRIMARY KEY,
medicationId VARCHAR(255),
NAME VARCHAR(255)
);
insert into Medications (ID,medicationId,NAME)
values  (3, 'e12','감기약');
insert into Medications (ID,medicationId,NAME)
values  (2, 'z12','타이레놀');
insert into Medications (ID,medicationId,NAME)
values  (1, 's12','수면제');
SELECT * FROM Medications;

exit명령어로 mysql 빠져 나오기

선행 요소: AWS 회원가입

1. AWS EC2 시작

주의!: 과금 요소가 생길 수 있으니 최대한 프리티어로 생성해야 한다.

키 페어 생성시 RestAPI.pem 파일이 다운로드 되는데 이는 해당 EC2를 실행하는데 꼭 필요한 보안 파일 이기 때문에 삭제하지 말고 중요한 곳에 모셔두어야 한다.

그 외 설정은 추가적으로 건드는 것 없이 인스턴스 시작

2. 탄력적 IP 할당

지금 실행 시킨 EC2는 새로 연결시 url이 바뀌기 때문에 이를 방지하기 위해서는 탄력적 IP를 할당하여 사용할 필요가 있다.

3. RDS 생성

가장 중요!!!: 반드시 RDS는 프리 티어로 만들어야 한다. 프로덕션, 개발/테스트 용도로 만들 경우 세팅도 프리티어와 다를 뿐 아니라 아무런 이용이 없다 해도 한 달 고정 비용이 많이 발생하기 때문

해당 비밀번호를 반드시 기억해야 한다.

이후 따로 설정을 건들지 않고 데이터 베이스 생성 버튼을 클릭한다.

4. EC2, 데이터베이스 연결

1. application.properties.yml 내용 추가

spring.datasource.url=jdbc:mysql://localhost:3306/Medications
spring.datasource.username=testuser
spring.datasource.password="스키마 생성시 설정한 비밀번호"
spring.jpa.hibernate.ddl-auto=update

2. DB에 삽입할 테스트 sql 문 data.sql

insert into medications.medications (ID,medication_Id,NAME)
values  (2, 'e12','감기약');
insert into medications.medications (ID,medication_Id,NAME)
values  (3, 'z12','타이레놀');
insert into medications.medications (ID,medication_Id,NAME)
values  (4, 's12','수면제');

3. DB 연결

아이디, 비밀번호, DB명 입력

Insert 작업이 완료 되었나 select 문을 통해 MySQL Workbench에서 확인

USE Medications;
SELECT * FROM Medications;

4. 추가 테스트

http://localhost:8080/medications

https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh?hl=ko

JSON Viewer를 쓴 모습

API Tester 확장 플러그인을 사용하여 Create 작업이 잘 되는지 확인 다른 API 테스트 툴이 있다면 그걸 사용해도 무방하다.

https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm?hl=ko

 

1. 프로젝트 생성

https://start.spring.io/

2. 생성된 zip 파일 위치 설정 및 실행

로컬 디스크(c)로 이동 후 압축 해제

IntelliJ로 실행

3. controller, domain, repository로 분할 클래스,인터페이스 작성

MedicationsController.java

package _PF026.DrDrug.controller;

import _PF026.DrDrug.domain.Medications;
import _PF026.DrDrug.repository.MedicationsRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
public class MedicationsController {
    @Autowired
    private MedicationsRepository repository;

    @GetMapping("/medications")
    public List<Medications> getAllMedications(){
        return repository.findAll();
    }

    @GetMapping("/medications/{id}")
    public Medications getMedicationsDetail(@PathVariable long id){
        Optional<Medications> medications = repository.findById(id);
        if(medications.isEmpty()){
            throw new RuntimeException("Course not found with id "+id);
        }
        return medications.get();
    }
    @PostMapping("/medications")
    public void createMedications(@RequestBody Medications medications){
        repository.save(medications);
    }

    // 객체가 존재하면 업데이트 없다면 삽입
    @PutMapping("/medications")
    public void updateMedications(@RequestBody Medications medications){
        repository.save(medications);
    }

    // 객체가 존재하면 업데이트 없다면 삽입
    @DeleteMapping("/medications/{id}")
    public void deleteMedications(@PathVariable long id){
        repository.deleteById(id);
    }

}

Medications.java

package _PF026.DrDrug.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter @Setter
public class Medications {
    @Id @GeneratedValue
    private Long id;
    private String medicationId;
    private String name;
}

MedicationsRepository.java

package _PF026.DrDrug.repository;

import _PF026.DrDrug.domain.Medications;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface MedicationsRepository extends JpaRepository<Medications,Long> {

}

<Repository>를 만들때는 EntityManager와 JpaRepository 두 가지 다른 방법이 존재하는데 여기서는 간단한 CRUD연산만 필요 하므로 JpaRepository를 사용하였다.

  1. EntityManager를 사용: EntityManager는 JPA의 핵심 컴포넌트로, 엔티티를 관리하며 데이터베이스와의 모든 상호작용을 처리합니다. EntityManager를 사용하면 직접적으로 데이터베이스 작업을 제어할 수 있습니다. 복잡하고 세밀한 작업이 필요한 상황에서는 EntityManager를 사용하는 것이 좋을 수 있습니다. 하지만 EntityManager를 사용하면 코드가 복잡해질 수 있고, JPA를 깊이 이해해야 할 수 있습니다.
  2. JpaRepository를 상속: JpaRepository를 상속받는 Repository를 사용하면 CRUD 연산을 매우 쉽게 처리할 수 있습니다. JpaRepository는 기본적인 CRUD 메서드를 제공하며, 이를 상속받는 클래스는 이 메서드를 직접 사용할 수 있습니다. 또한, 메서드 이름으로 쿼리를 생성하는 기능을 제공하여 데이터베이스 작업을 매우 쉽게 만들어줍니다. JpaRepository를 사용하면 보일러플레이트 코드를 크게 줄일 수 있지만, 복잡한 쿼리나 특정 데이터베이스 작업을 처리하기 어려울 수 있습니다.

 

Spring Boot에서 Controller, Service, Repository를 분리하는 이유는 소프트웨어 설계 원칙 중 하나인 '단일 책임 원칙'을 따르기 위함이며, 이 원칙에 따르면, 각 컴포넌트는 하나의 책임만을 가져야 하며, 이는 시스템의 각 부분이 잘 정의된 역할을 가지고 있어야 함을 의미한다.

  • Controller: 컨트롤러는 HTTP 요청을 처리하는 역할을 담당한다. 이는 요청을 받아들이고, 요청에 대한 적절한 서비스 메소드를 호출하며, 그 결과를 클라이언트에게 반환하는 역할을 한다. (프레젠테이션 계층)
  • Service: 서비스 계층은 비즈니스 로직을 담당한다. 이는 여러 레포지토리를 조합하여 작업을 수행하거나, 트랜잭션을 관리하거나, 특정 작업을 수행하기 위한 로직을 구현하는 역할을 한다. 데이터의 흐름과 비즈니스 로직을 캡슐화하여 Controller DAO 사이에서 역할을 수행한다. (비즈니스 로직을 수행하는 계층)
  • Repository: 레포지토리는 도메인 모델에 집중하고 특정 데이터베이스 기술의 의존성을 최소화 하는 것을 목적으로 가진다. 기능으로는 데이터베이스와의 상호작용을 담당한다. CRUD(Create, Read, Update, Delete) 작업을 데이터베이스에 대해 수행한다. (데이터 접근 계층)

<Repository>

EntityManager와 JpaRepository는 두 가지 다른 방법으로 데이터베이스 작업을 수행할 수 있게 한다. 어떤 방법을 선택할 것인지는 프로젝트의 요구사항과 개발 팀의 선호에 따라 달라지게된다.

  1. EntityManager를 사용: EntityManager는 JPA의 핵심 컴포넌트로, 엔티티를 관리하며 데이터베이스와의 모든 상호작용을 처리한다. EntityManager를 사용하면 직접적으로 데이터베이스 작업을 제어할 수 있어, 복잡하고 세밀한 작업이 필요한 상황에서는 EntityManager를 사용하는 것이 유리하다. 하지만 EntityManager를 사용하면 코드가 복잡해질 수 있고, JPA를 깊이 이해하는 것이 필요하다.
  2. JpaRepository를 상속: JpaRepository를 상속받는 Repository를 사용하면 CRUD 연산을 매우 쉽게 처리할 수 있다. JpaRepository는 기본적인 CRUD 메서드를 제공하며, 이를 상속받는 클래스는 이 메서드를 직접 사용할 수 있다. 또한, 메서드 이름으로 쿼리를 생성하는 기능을 제공하여 데이터베이스 작업을 매우 쉽게 만들어준다. JpaRepository를 사용하면 보일러플레이트 코드를 크게 줄일 수 있지만, 복잡한 쿼리나 특정 데이터베이스 작업을 처리하기 어려울 수 있다.

Spring Boot Actuator

Spring Boot 애플리케이션의 프로덕션 준비 기능을 제공하는 Spring Boot 프로젝트의 일부입니다. 이것은 애플리케이션의 상태를 모니터링하고 관리하는데 필요한 다양한 엔드포인트를 추가합니다.

의존성 정보 링크: https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator/3.1.0

 

1. Spring boot gradle 기준으로 해당 의존성 추가

dependencies {
	// 기존 의존성들 
	implementation 'org.springframework.boot:spring-boot-starter-actuator:3.1.0'
	
}

2. 프로젝트 경로 src/main/resources/application.properties 파일에 내용 추가

management.endpoints.web.exposure.include=*

 

3. 서버 실행 후 http://localhost:8080/actuator url 입력

 

<Json viewer 확장 플러그인 사용 화면>

https://chrome.google.com/webstore/detail/json-viewer/gbmdgpbipfallnflgajpaliibnhdgobh/related?hl=ko 

4. "http://localhost:8080/actuator/metrics/http.server.requests" 입력

COUNT가 지금까지의 접속 횟수를 나타낸다.

+ Recent posts