1. 이전 포스팅
https://growingsaja.tistory.com/991
2. 목표
실시간 환율 정보 및 가상자산 정보를 수집해 저장하고, 데이터를 가공해 제공하는 api가 구현된 백엔드 서버 개발
- 개발하는 백엔드 시스템 기본 정보 저장용 DB로 H2 사용
- 서비스 데이터는 모두 MongoDB에 저장 및 관리
ㄴ 본 포스팅에서는 MongoDB 내용을 다루지 않지만, 이후 포스팅에서 개발되는 기능들에서는 MongoDB를 활용합니다.
3. 프로젝트 새로 만들기 in IntelliJ
Name : Kotlin
Language : Gradle - Kotlin
Name : kopring00
Group : com.dev
Developer Tools -> Sptring Boot DevTools
Web -> Spring Web
SQL -> Spring Data JPA
SQL -> H2 Database
NoSQL -> Spring Data MongoDB
4. 프로젝트 구조 세팅 - 폴더
- base : 추후 계속 사용하거나, 기본적인 api 기능 관련 구현
controllers
entities
repositories
services
- external : 구현할 새로운 기능들 중 하나로, 필자는 외부 api에 call해서 정보 수집 및 가공하는 기능을 모으는 용도로 사용 예정
ㄴ fiat : 법정 화폐 정보 수집 및 가공 기능 구현 예정
ㄴ fiat 말고 다른 패키지를 만들며 추가 기능 탑재 예정 (현재는 없음)
5. swagger 적용
https://growingsaja.tistory.com/962
// vim build.gradle.kts
// ...
dependencies {
// ...
// swagger
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0")
}
// ...
http://localhost:8080/swagger-ui/index.html#/
6. api 공통 response 형태 사전 설계
// vim StatusOfResponse.kt
package com.dev.kopring00.base.entities
import java.time.LocalDateTime
data class StatusOfResponse(
var code: String,
var message: String,
val timestamp: LocalDateTime = LocalDateTime.now()
)
- 참조
https://growingsaja.tistory.com/984
7. H2 적용
backend 정보 관리를 위한 H2 Database 설정
https://growingsaja.tistory.com/964
# vim /main/resources/application.properties
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:default-setting
http://localhost/h2-console
- 기본 데이터셋
// vim entities/ApiServer.kt
package com.dev.kopring00.base.entities
import jakarta.persistence.Entity
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import java.time.LocalDateTime
@Entity
data class ApiServer(
// @Id 어노테이션은 이 필드가 엔터티의 기본 키(primary key)임을 나타냅니다.
@Id
// @GeneratedValue 어노테이션은 기본 키의 생성 전략을 나타내며, IDENTITY 전략은 데이터베이스가 자동으로 기본 키 값을 생성하도록 지시합니다.
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int,
/* ===== 앱 업데이트 안내 ===== */
val recentVersion: String, // 가장 최근 배포된 버전 이상 >>> 조치 없음
// recentVersion 미만 & stableVersion 이상 >>> 앱 업데이트 권고
val stableVersion: String, // 최소 버전 = 해당 버전 미만 >>> 앱 업데이트 강제
/* ===== 앱 실행 차단 (ex. 긴급 점검) ===== */
val isServiceOutage: Boolean, // 장애 상황인 경우 true로 바꿔, 모든 앱 실행자의 진입을 차단
val text_serviceOutage: String, // 장애 상황인 경우 노출되는 안내 문구
// api server 최근 재가동 일시
val lastRestartAt: LocalDateTime = LocalDateTime.now()
)
// vim ApiServerInitialData.kt
package com.dev.kopring00.base.entities
import com.dev.kopring00.base.repositories.ApiServerRepository
import jakarta.annotation.PostConstruct
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import java.time.LocalDateTime
@Component
class ApiServerInitialData @Autowired constructor(private val apiServerRepository: ApiServerRepository) {
@PostConstruct
fun loadData() {
// 최신 정보로 1개 데이터만 List로 기재
val initialApiServerData = listOf(
ApiServer(
1,
"0.0.1",
"0.0.1",
false,
"서비스 점검 중입니다."
),
)
apiServerRepository.saveAll(initialApiServerData)
}
}
8. H2 데이터 활용 기능 구현
// vim ApiServerResponse.kt
package com.dev.kopring00.base.entities
data class ApiServerResponse(
var status: StatusOfResponse,
var result: ApiServer?
)
// vim ApiServerRepository.kt
package com.dev.kopring00.base.repositories
import com.dev.kopring00.base.entities.ApiServer
import org.springframework.data.jpa.repository.JpaRepository
interface ApiServerRepository: JpaRepository<ApiServer, Int> {}
// vim ApiServerService.kt
package com.dev.kopring00.base.services
import com.dev.kopring00.base.entities.ApiServer
import com.dev.kopring00.base.entities.ApiServerResponse
import com.dev.kopring00.base.entities.StatusOfResponse
import com.dev.kopring00.base.repositories.ApiServerRepository
import org.springframework.stereotype.Service
@Service
class ApiServerService(private val apiServerRepository: ApiServerRepository) {
fun getRecentSystemInfo(): ApiServerResponse {
val recentSystemInfoAll = apiServerRepository.findAll()
return if (recentSystemInfoAll.isNotEmpty()) {
ApiServerResponse(
StatusOfResponse("100", "success"),
recentSystemInfoAll.first()
)
} else {
ApiServerResponse(
StatusOfResponse("204", "no data"),
null
)
}
}
}
- 데이터가 없으면 result에 null 데이터가 들어간채로 return합니다.
// vim ApiServerController.kt
package com.dev.kopring00.base.controllers
import com.dev.kopring00.base.entities.ApiServerResponse
import com.dev.kopring00.base.services.ApiServerService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/v1/system/info")
class ApiServerController(private val apiServerService: ApiServerService) {
@GetMapping("/recent")
fun getRecentSystemInfo(): ApiServerResponse {
return apiServerService.getRecentSystemInfo()
}
}
9. MongoDB 적용하는데에 도움이 필요하다면 복습하러 가기
- repository JpaRepository와 DB 2개 동시에 연동하는 부분 필요시 참조
https://growingsaja.tistory.com/972