🏗️ 프로젝트 구조 web, core, infrastructure 모듈로 분리
This commit is contained in:
@@ -3,6 +3,7 @@ plugins {
|
||||
id("io.spring.dependency-management") version "1.0.13.RELEASE"
|
||||
kotlin("jvm") version "1.6.21"
|
||||
kotlin("plugin.spring") version "1.6.21"
|
||||
kotlin("plugin.jpa") version "1.6.21"
|
||||
kotlin("kapt") version "1.6.21"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package me.jiniworld.demohx.notice.domain
|
||||
package me.jiniworld.demohx.application.notice.domain
|
||||
|
||||
import me.jiniworld.demohx.notice.application.port.output.NoticeDetail
|
||||
import me.jiniworld.demohx.notice.application.port.output.NoticeSimple
|
||||
import me.jiniworld.demohx.util.DateTimeUtils
|
||||
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(
|
||||
@@ -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?
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.jiniworld.demohx.notice.application.port.output
|
||||
package me.jiniworld.demohx.application.notice.port.output
|
||||
|
||||
data class NoticeDetail(
|
||||
val id: Long,
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.jiniworld.demohx.notice.application.port.output
|
||||
package me.jiniworld.demohx.application.notice.port.output
|
||||
|
||||
data class NoticeSimple(
|
||||
val id: Long,
|
||||
@@ -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()
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package me.jiniworld.demohx.util
|
||||
package me.jiniworld.demohx.application.util
|
||||
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
@@ -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 {
|
||||
}
|
||||
7
infrastructure/datastore-mariadb/build.gradle.kts
Normal file
7
infrastructure/datastore-mariadb/build.gradle.kts
Normal file
@@ -0,0 +1,7 @@
|
||||
apply(plugin = "kotlin-jpa")
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
|
||||
runtimeOnly("org.mariadb.jdbc:mariadb-java-client")
|
||||
implementation(project(":core:demo-core"))
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package me.jiniworld.demohx.config
|
||||
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan
|
||||
import org.springframework.context.annotation.ComponentScan
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
|
||||
|
||||
@Configuration
|
||||
@ComponentScan("me.jiniworld.demohx.persistence")
|
||||
@EnableJpaRepositories(basePackages = ["me.jiniworld.demohx.persistence.notice.repository"])
|
||||
@EntityScan(basePackages = ["me.jiniworld.demohx.persistence.notice.entity"])
|
||||
class NoticeModule {
|
||||
// @Bean
|
||||
// fun noticePersistenceAdapter(noticeRepository: NoticeRepository): NoticePersistenceAdapter {
|
||||
// return NoticePersistenceAdapter(noticeRepository)
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package me.jiniworld.demohx.persistence.notice
|
||||
|
||||
import me.jiniworld.demohx.application.notice.port.output.LoadNoticePort
|
||||
import me.jiniworld.demohx.application.notice.domain.Notice
|
||||
import me.jiniworld.demohx.persistence.notice.repository.NoticeRepository
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
internal class NoticePersistenceAdapter(
|
||||
private val noticeRepository: NoticeRepository,
|
||||
) : LoadNoticePort {
|
||||
override fun loadNotices(pageable: Pageable): List<Notice>? {
|
||||
return noticeRepository.findAllBy(pageable).map { it.mapToNotice() }.toList()
|
||||
}
|
||||
|
||||
override fun loadNotice(id: Long): Notice? {
|
||||
return noticeRepository.findByIdOrNull(id)?.mapToNotice()
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package me.jiniworld.demohx.notice.adapter.output.persistence
|
||||
package me.jiniworld.demohx.persistence.notice.entity
|
||||
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import me.jiniworld.demohx.application.notice.domain.Notice
|
||||
import org.springframework.data.annotation.CreatedDate
|
||||
import org.springframework.data.annotation.LastModifiedDate
|
||||
import java.time.LocalDateTime
|
||||
@@ -1,5 +1,6 @@
|
||||
package me.jiniworld.demohx.notice.adapter.output.persistence
|
||||
package me.jiniworld.demohx.persistence.notice.repository
|
||||
|
||||
import me.jiniworld.demohx.persistence.notice.entity.NoticeEntity
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
spring:
|
||||
application:
|
||||
name: demo-datastore-mariadb
|
||||
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
|
||||
11
server/demo-app/build.gradle.kts
Normal file
11
server/demo-app/build.gradle.kts
Normal file
@@ -0,0 +1,11 @@
|
||||
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")
|
||||
|
||||
implementation(project(":core:demo-core"))
|
||||
implementation(project(":infrastructure:datastore-mariadb"))
|
||||
}
|
||||
@@ -4,10 +4,14 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.runApplication
|
||||
import java.util.*
|
||||
|
||||
@SpringBootApplication
|
||||
class DemoHxApplication
|
||||
@SpringBootApplication(scanBasePackages = [
|
||||
"me.jiniworld.demohx.config",
|
||||
"me.jiniworld.demohx.web",
|
||||
"me.jiniworld.demohx.application"
|
||||
])
|
||||
class DemoAppApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
Locale.setDefault(Locale.KOREA)
|
||||
runApplication<DemoHxApplication>(*args)
|
||||
runApplication<DemoAppApplication>(*args)
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package me.jiniworld.demohx.notice.adapter.input.web
|
||||
package me.jiniworld.demohx.web.notice
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation
|
||||
import io.swagger.v3.oas.annotations.tags.Tag
|
||||
import me.jiniworld.demohx.notice.application.service.GetNoticeService
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import me.jiniworld.demohx.application.notice.port.input.GetNoticeQuery
|
||||
import me.jiniworld.demohx.application.notice.domain.Notice
|
||||
import me.jiniworld.demohx.application.notice.port.output.NoticeSimple
|
||||
import org.springframework.data.domain.PageRequest
|
||||
import org.springframework.data.domain.Sort
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.RequestMapping
|
||||
import org.springframework.web.bind.annotation.RequestParam
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
@Component
|
||||
//@WebAdapter
|
||||
@@ -18,7 +16,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
@RestController
|
||||
@RequestMapping("/v1/notices")
|
||||
internal class GetNoticeController(
|
||||
private val getNoticeQuery: GetNoticeService,
|
||||
private val getNoticeQuery: GetNoticeQuery,
|
||||
) {
|
||||
|
||||
@Operation(summary = "공지사항 목록")
|
||||
@@ -26,9 +24,11 @@ internal class GetNoticeController(
|
||||
fun notices(
|
||||
@RequestParam(value = "page", required = false, defaultValue = "0") page: Int,
|
||||
@RequestParam(value = "size", required = false, defaultValue = "10") size: Int,
|
||||
): List<Notice> {
|
||||
println(">>>>>>>>> 1")
|
||||
return getNoticeQuery.getNoticeSimple(PageRequest.of(page, size, Sort.by(Sort.Order.desc("id"))))
|
||||
}
|
||||
) = getNoticeQuery.getNoticeSimple(PageRequest.of(page, size, Sort.by(Sort.Order.desc("id"))))
|
||||
|
||||
@Operation(summary = "공지사항 상세조회")
|
||||
@GetMapping("/{notice_id}")
|
||||
fun notice(@PathVariable("notice_id") noticeId: Long) =
|
||||
getNoticeQuery.getNoticeDetail(noticeId)
|
||||
|
||||
}
|
||||
78
server/demo-app/src/main/resources/application.yml
Normal file
78
server/demo-app/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
server/demo-app/src/main/resources/chaeking.yml
Normal file
7
server/demo-app/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
|
||||
@@ -1,3 +1,9 @@
|
||||
|
||||
rootProject.name = "demo-hexagonal"
|
||||
include("web")
|
||||
include("core:demo-core")
|
||||
findProject(":core:demo-core")?.name = "demo-core"
|
||||
include("infrastructure:datastore-mariadb")
|
||||
findProject(":infrastructure:datastore-mariadb")?.name = "datastore-mariadb"
|
||||
include("server")
|
||||
include("server:demo-app")
|
||||
findProject(":server:demo-app")?.name = "demo-app"
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package me.jiniworld.demohx.notice.adapter.output.persistence
|
||||
|
||||
import me.jiniworld.demohx.notice.application.port.output.LoadNoticePort
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import org.springframework.data.domain.Pageable
|
||||
import java.time.LocalDateTime
|
||||
|
||||
internal class NoticePersistenceAdapter(
|
||||
private val noticeRepository: NoticeRepository,
|
||||
) : LoadNoticePort {
|
||||
override fun loadNotices(pageable: Pageable): List<Notice> {
|
||||
|
||||
println(">>>>>>>>> 3")
|
||||
return noticeRepository.findAllBy(pageable).map { it.mapToNotice() }.toList()
|
||||
}
|
||||
|
||||
override fun loadNotice(id: Long): Notice? {
|
||||
return Notice(id = id, title = "zzz", content = "fff", createdAt = LocalDateTime.now())
|
||||
// return noticeRepository.findById(id)?.map(NoticeEntity::mapToNotice)
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package me.jiniworld.demohx.notice.adapter.output.persistence
|
||||
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories
|
||||
internal class NoticePersistenceAdapterConfiguration {
|
||||
|
||||
@Bean
|
||||
fun noticePersistenceAdapter(noticeRepository: NoticeRepository): NoticePersistenceAdapter {
|
||||
return NoticePersistenceAdapter(noticeRepository)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package me.jiniworld.demohx.notice.application.port.input
|
||||
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
interface GetNoticeQuery {
|
||||
fun getNoticeSimple(pageable: Pageable): List<Notice>
|
||||
fun getNoticeDetail(noticeId: Long): Notice?
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package me.jiniworld.demohx.notice.application.port.output
|
||||
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@Component
|
||||
interface LoadNoticePort {
|
||||
fun loadNotices(pageable: Pageable): List<Notice>
|
||||
fun loadNotice(id: Long): Notice?
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package me.jiniworld.demohx.notice.application.service
|
||||
|
||||
import me.jiniworld.demohx.notice.application.port.input.GetNoticeQuery
|
||||
import me.jiniworld.demohx.notice.application.port.output.LoadNoticePort
|
||||
import me.jiniworld.demohx.notice.domain.Notice
|
||||
import org.springframework.data.domain.Pageable
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.sql.DriverManager.println
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
@Component
|
||||
internal class GetNoticeService(
|
||||
private val loadNoticePort: LoadNoticePort,
|
||||
) : GetNoticeQuery {
|
||||
|
||||
override fun getNoticeSimple(pageable: Pageable): List<Notice> {
|
||||
println(">>>>>>>>> 2")
|
||||
return loadNoticePort.loadNotices(pageable)
|
||||
// return loadNoticePort.loadNotices(pageable).map { it.mapToNoticeSimple() }.toList()
|
||||
}
|
||||
|
||||
override fun getNoticeDetail(id: Long): Notice? {
|
||||
return loadNoticePort.loadNotice(id)
|
||||
// return loadNoticePort.loadNotice(id)?.mapToNoticeDetail()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user