🏗️ 프로젝트 구조 web, core, infrastructure 모듈로 분리
This commit is contained in:
8
core/demo-core/build.gradle.kts
Normal file
8
core/demo-core/build.gradle.kts
Normal file
@@ -0,0 +1,8 @@
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
implementation("org.springframework.boot:spring-boot-starter-validation")
|
||||
compileOnly("org.springframework.boot:spring-boot-configuration-processor")
|
||||
implementation("org.springdoc:springdoc-openapi-ui:1.6.13")
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package me.jiniworld.demohx.application.notice.domain
|
||||
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeDetail
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeSimple
|
||||
import me.jiniworld.demohx.application.util.DateTimeUtils
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class Notice(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
val content: String,
|
||||
val createdAt: LocalDateTime,
|
||||
) {
|
||||
fun mapToNoticeSimple() =
|
||||
NoticeSimple(id = id, title = title, createdOn = DateTimeUtils.toDateString(createdAt))
|
||||
|
||||
fun mapToNoticeDetail() =
|
||||
NoticeDetail(id = id, title = title, content = content, createdAt = DateTimeUtils.toString(createdAt))
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package me.jiniworld.demohx.application.notice.port.input
|
||||
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeDetail
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeSimple
|
||||
import org.springframework.data.domain.Pageable
|
||||
|
||||
interface GetNoticeQuery {
|
||||
fun getNoticeSimple(pageable: Pageable): List<NoticeSimple>?
|
||||
fun getNoticeDetail(noticeId: Long): NoticeDetail?
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.jiniworld.demohx.application.notice.port.output
|
||||
|
||||
import me.jiniworld.demohx.application.notice.domain.Notice
|
||||
import org.springframework.data.domain.Pageable
|
||||
|
||||
interface LoadNoticePort {
|
||||
fun loadNotices(pageable: Pageable): List<Notice>?
|
||||
fun loadNotice(id: Long): Notice?
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package me.jiniworld.demohx.application.notice.port.output
|
||||
|
||||
data class NoticeDetail(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
val content: String,
|
||||
val createdAt: String,
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.jiniworld.demohx.application.notice.port.output
|
||||
|
||||
data class NoticeSimple(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
val createdOn: String,
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
package me.jiniworld.demohx.application.notice.service
|
||||
|
||||
import me.jiniworld.demohx.application.notice.port.input.GetNoticeQuery
|
||||
import me.jiniworld.demohx.application.notice.port.output.LoadNoticePort
|
||||
import me.jiniworld.demohx.application.notice.domain.Notice
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeDetail
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeSimple
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Component
|
||||
internal class GetNoticeService(
|
||||
private val loadNoticePort: LoadNoticePort,
|
||||
) : GetNoticeQuery {
|
||||
|
||||
override fun getNoticeSimple(pageable: Pageable) =
|
||||
loadNoticePort.loadNotices(pageable)?.map { it.mapToNoticeSimple() }
|
||||
|
||||
override fun getNoticeDetail(id: Long): NoticeDetail? =
|
||||
loadNoticePort.loadNotice(id)?.mapToNoticeDetail()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package me.jiniworld.demohx.application.util
|
||||
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.temporal.ChronoField
|
||||
import java.time.temporal.TemporalAdjusters
|
||||
|
||||
object DateTimeUtils {
|
||||
|
||||
private const val SIMPLE_PATTERN_MONTH = "yyyyMM"
|
||||
private const val SIMPLE_PATTERN_DATE = "yyyyMMdd"
|
||||
private const val DEFAULT_PATTERN_DATE = "yyyy-MM-dd"
|
||||
private const val DEFAULT_PATTERN_DATETIME = "yyyy-MM-dd HH:mm:ss"
|
||||
private const val DEFAULT_PATTERN_TIME = "HH:mm:ss"
|
||||
|
||||
private val LOCALTIME_START = LocalTime.of(0, 0)
|
||||
private val LOCALTIME_END = LocalTime.of(23, 59, 59)
|
||||
|
||||
val FORMATTER_MONTH_SIMPLE: DateTimeFormatter = DateTimeFormatter.ofPattern(SIMPLE_PATTERN_MONTH)
|
||||
val FORMATTER_DATE_SIMPLE: DateTimeFormatter = DateTimeFormatter.ofPattern(SIMPLE_PATTERN_DATE)
|
||||
val FORMATTER_DATE: DateTimeFormatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN_DATE)
|
||||
val FORMATTER_DATETIME: DateTimeFormatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN_DATETIME)
|
||||
val FORMATTER_TIME: DateTimeFormatter = DateTimeFormatter.ofPattern(DEFAULT_PATTERN_TIME)
|
||||
|
||||
fun getFirstDate(month: String): LocalDate =
|
||||
LocalDate.of(Integer.parseInt(month.substring(0, 4)), Integer.parseInt(month.substring(4, 6)), 1)
|
||||
|
||||
fun getLastDate(month: String): LocalDate =
|
||||
getFirstDate(month).with(TemporalAdjusters.lastDayOfMonth())
|
||||
|
||||
fun getFirstDateTime(date: LocalDate): LocalDateTime =
|
||||
LocalDateTime.of(date, LOCALTIME_START)
|
||||
|
||||
fun getLastDateTime(date: LocalDate): LocalDateTime =
|
||||
LocalDateTime.of(date.with(TemporalAdjusters.lastDayOfMonth()), LOCALTIME_END)
|
||||
|
||||
fun getFirstDateTime(date: LocalDate, type: AnalysisType): LocalDateTime =
|
||||
when (type) {
|
||||
AnalysisType.weekly -> LocalDateTime.of(date.minusDays((date[ChronoField.DAY_OF_WEEK] - 1).toLong()).minusWeeks(6), LOCALTIME_START)
|
||||
AnalysisType.monthly -> date.minusDays((date[ChronoField.DAY_OF_MONTH] - 1).toLong()).minusMonths(6).atStartOfDay()
|
||||
else -> LocalDateTime.of(date.minusDays((date[ChronoField.DAY_OF_WEEK] - 1).toLong()), LOCALTIME_START)
|
||||
}
|
||||
|
||||
fun getLastDateTime(date: LocalDate, type: AnalysisType): LocalDateTime =
|
||||
when (type) {
|
||||
AnalysisType.monthly -> LocalDateTime.of(date.minusDays(date[ChronoField.DAY_OF_MONTH].toLong()).plusMonths(1), LOCALTIME_END)
|
||||
else -> LocalDateTime.of(date.plusDays((7 - date[ChronoField.DAY_OF_WEEK]).toLong()), LOCALTIME_END)
|
||||
}
|
||||
|
||||
fun toString(date: LocalDate) = date.format(FORMATTER_DATE)
|
||||
|
||||
fun toString(dateTime: LocalDateTime) = dateTime.format(FORMATTER_DATETIME)
|
||||
|
||||
fun toDateString(dateTime: LocalDateTime) = dateTime.format(FORMATTER_DATE)
|
||||
}
|
||||
|
||||
|
||||
enum class AnalysisType {
|
||||
daily, weekly, monthly
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.jiniworld.demohx.config
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("me.jiniworld.demohx.application.notice.port")
|
||||
class NoticeCoreModule {
|
||||
}
|
||||
78
core/demo-core/src/main/resources/application.yml
Normal file
78
core/demo-core/src/main/resources/application.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
spring:
|
||||
application:
|
||||
name: chaeking
|
||||
profiles:
|
||||
active: local
|
||||
config:
|
||||
import:
|
||||
- chaeking.yml
|
||||
# - vault://secret/chaeking-local
|
||||
datasource:
|
||||
url: jdbc:mariadb://localhost:3306/book
|
||||
driver-class-name: org.mariadb.jdbc.Driver
|
||||
username: test
|
||||
password: test
|
||||
hikari:
|
||||
auto-commit: false
|
||||
connection-test-query: SELECT 1
|
||||
minimum-idle: 10
|
||||
maximum-pool-size: 50
|
||||
# transaction-isolation: TRANSACTION_READ_UNCOMMITTED
|
||||
pool-name: pool-book
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.MariaDB103Dialect
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: false
|
||||
hbm2ddl.auto: update
|
||||
implicit_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
|
||||
physical_naming_strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
|
||||
default_batch_fetch_size: 500
|
||||
open-in-view: false
|
||||
show-sql: true
|
||||
|
||||
devtools:
|
||||
add-properties: false
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
tomcat:
|
||||
basedir: .
|
||||
# accesslog:
|
||||
# enabled: true
|
||||
# directory: logs
|
||||
# pattern: "%{yyyy-MM-dd HH:mm:ss}t %{X-Forwarded-For}i(%h) %l %u \"%r\" %s %b"
|
||||
remoteip:
|
||||
protocol-header: X-Forwarded-Proto
|
||||
remote-ip-header: X-Forwarded-For
|
||||
|
||||
springdoc:
|
||||
api-docs:
|
||||
path: /api-docs
|
||||
default-consumes-media-type: application/json
|
||||
default-produces-media-type: application/json
|
||||
swagger-ui:
|
||||
operations-sorter: alpha
|
||||
tags-sorter: alpha
|
||||
path: /
|
||||
disable-swagger-default-url: true
|
||||
doc-expansion: none
|
||||
syntax-highlight:
|
||||
theme: nord
|
||||
paths-to-match:
|
||||
- /v1/**
|
||||
- /temp/**
|
||||
- /data4library/**
|
||||
|
||||
logging:
|
||||
# file:
|
||||
# name: logs/check.log
|
||||
exception-conversion-word: '%wEx'
|
||||
pattern:
|
||||
console: '%d{yyyy-MM-dd HH:mm:ss.SSS} %clr(${LOG_LEVEL_PATTERN:%-5p}){green} %clr([%22thread]){magenta} %clr(%-40.40logger{39}){cyan} %clr(: %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}){faint}'
|
||||
level:
|
||||
web: debug
|
||||
org:
|
||||
springframework:
|
||||
web:
|
||||
servlet: debug
|
||||
7
core/demo-core/src/main/resources/chaeking.yml
Normal file
7
core/demo-core/src/main/resources/chaeking.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
chaeking:
|
||||
version: 1.0.1
|
||||
url: http://localhost:${server.port}
|
||||
|
||||
book-search:
|
||||
kakao:
|
||||
api-url: https://dapi.kakao.com
|
||||
Reference in New Issue
Block a user