Back-End ์ž‘์—…์‹ค/Spring Framework

[Spring Boot] Discord Bot(๋””์Šค์ฝ”๋“œ ๋ด‡) ๋งŒ๋“ค๊ธฐ - Spring Boot(์Šคํ”„๋ง ๋ถ€ํŠธ)๋ฅผ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ API ๋งŒ๋“ค๊ธฐ feat.mybatis(๋งˆ์ด๋ฐ”ํ‹ฐ์Šค)

์ฃผ๋‹ˆ์“ฐ๐Ÿง‘‍๐Ÿ’ป 2023. 3. 17. 22:14
728x90
๋ฐ˜์‘ํ˜•

 

 




 

 

์ „์ž์ •๋ถ€ ํ‘œ์ค€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์–‘๋Œ€ ํ•ต์‹ฌ ๊ธฐ์ˆ  ์„ธํŠธ : ์Šคํ”„๋ง + ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 

 

 

 




๐Ÿ—‚ ๋ชฉ์ฐจ

1. [Spring Boot] Discord Bot(๋””์Šค์ฝ”๋“œ ๋ด‡) ๋งŒ๋“ค๊ธฐ
2. [Spring Boot] Discord Bot(๋””์Šค์ฝ”๋“œ ๋ด‡) ๋งŒ๋“ค๊ธฐ - Spring Boot(์Šคํ”„๋ง ๋ถ€ํŠธ)๋ฅผ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ API ๋งŒ๋“ค๊ธฐ feat.Mybatis(๋งˆ์ด๋ฐ”ํ‹ฐ์Šค)

3. [Spring Boot] Discord Bot(๋””์Šค์ฝ”๋“œ ๋ด‡) ๋งŒ๋“ค๊ธฐ - JAVA๋ฅผ ์ด์šฉํ•œ API ํ˜ธ์ถœ

4. [Spring Boot] Discord Bot(๋””์Šค์ฝ”๋“œ ๋ด‡) ๋งŒ๋“ค๊ธฐ - ๋””์Šค์ฝ”๋“œ ๋ด‡์„ ์ด์šฉํ•˜์—ฌ API ํ˜ธ์ถœ

 

 

 

 

๐Ÿš€ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—

    ๐Ÿ”ฝ  ๊ฐœ์š”

์•ˆ๋…•ํ•˜์„ธ์š”? ์ฃผ๋‹ˆ์ž…๋‹ˆ๋‹ค.

์ง€๋‚œ ๋ฒˆ์— ๋งŒ๋“ค์—ˆ๋˜ ๋””์Šค์ฝ”๋“œ ๋ด‡์„ ์ข€ ๋” ๋ฐœ์ „ ์‹œ์ผœ ์ด๋ฒˆ์—๋Š” API๋ฅผ ํ†ตํ•ด Data Base(DB - ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค)์— ์ €์žฅ๋œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋ฐœ์ „ ์‹œ์ผœ๋ณด๋ ค๊ณ  ํ•ด์š”.

์ง€๋‚œ ๋ฒˆ์—๋„ ์–ธ๊ธ‰ํ–ˆ์—ˆ์ง€๋งŒ, ๊ธฐ๊น”๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค ์ง€์›์ž ์ •๋ณด๋ฅผ ๊ฐ ๊ฐ„๋ถ€๋“ค์ด ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๊ฒŒ ๋””์Šค์ฝ”๋“œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ๋ฐœ ์ค‘์ธ ๊ฒƒ์ด๋ผ ์‹ค์ œ ์ž‘์—…์„ ํ•˜๊ธฐ ์ „ ์—ฐ์Šตํ•œ ๊ฒƒ์„ ๋ธ”๋กœ๊ทธ์— ๋‚จ๊ฒจ ๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ JDA๋ฅผ ์ด์šฉํ•œ ๋””์Šค์ฝ”๋“œ ๋ด‡ ๋งŒ๋“ค๊ธฐ๋Š” ์ด ๊ณณ์— ๊ด€์‹ฌ์„ ์ฃผ์„ธ์š”.

์—ฌ๋Ÿฌ IT ํšŒ์‚ฌ์—์„œ Java - Spring(์ž๋ฐ” - ์Šคํ”„๋ง)์„ ์ด์šฉํ•ด์„œ BackEnd (๋ฐฑ์—”๋“œ)๋ฅผ ๋งŒ๋“ค ๋•Œ, JPA์™€ QueryDSL (์ฟผ๋ฆฌ๋””์—์Šค์—˜) ์กฐํ•ฉ ํ˜น์€ JPA์™€ MyBatis(๋งˆ์ด๋ฐ”ํ‹ฐ์Šค) ํ˜น์€ MyBatis๋งŒ์„ ์ด์šฉํ•˜์—ฌ ๊ฐœ๋ฐœ ํ•˜๋Š” ๊ณณ์ด ์žˆ๋”๋ผ๊ตฌ์š”.

์ฃผ๋‹ˆ๊ฐ€ ๊ฒฝํ—˜ํ•œ ๋ฐ”๋กœ๋Š” ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋Š” Back Office(๋ฐฑ ์˜คํ”ผ์Šค)์—์„œ ์ฃผ๋กœ ๋งŽ์ด ์‚ฌ์šฉ๋˜๊ณ , ์ด์šฉ์ž (๋Œ€๊ตญ๋ฏผ) ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ JPA + QueryDSL ํ˜น์€ JPA + ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋ฅผ ์“ฐ๋Š” ๊ณณ์„ ๋งŽ์ด ๋ณด์•˜์–ด์š”.

๊ธฐ๊น”๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค์€ ์ด๋Ÿฐ ์ด์œ  ๋•Œ๋ฌธ์— ์ด์šฉ์ž ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ JPA์™€ QueryDSL ์กฐํ•ฉ์œผ๋กœ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ์กฐ์ž‘ํ•˜๊ณ , ๋ฐฑ ์˜คํ”ผ์Šค์˜ ๊ฒฝ์šฐ ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋ฅผ ์กฐ์ž‘ํ•˜๋ ค๊ณ  ํ•ด์š”.

๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฒˆ ๋””์Šค์ฝ”๋“œ ๋ด‡ ๋งŒ๋“ค๊ธฐ ๊ธ€์€ ๊ธฐ๊น”๋‚˜๋Š” ์‚ฌ๋žŒ๋“ค ๋ฐฑ ์˜คํ”ผ์Šค์—์„œ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ณ , ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋ฅผ ์ด์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

GitHub - junyharang-personal-project/juny-discord-bot-test: JDA๋ฅผ ์ด์šฉํ•œ Spring Boot Discord Bot ์—ฐ์Šต์ด์—์š”.

JDA๋ฅผ ์ด์šฉํ•œ Spring Boot Discord Bot ์—ฐ์Šต์ด์—์š”. Contribute to junyharang-personal-project/juny-discord-bot-test development by creating an account on GitHub.

github.com

 

 

 

 

 

    ๐Ÿ”ฝ  ์˜์กด์„ฑ ์ถ”๊ฐ€

build.gradle

 


์ด ์ „ ๊ธ€์—์„œ๋ณด๋‹ค ๋” ๋งŽ์€ ์˜์กด์„ฑ๋“ค์ด ์ถ”๊ฐ€ ๋˜์—ˆ์–ด์š”.

plugins {
    id 'java'
    id 'org.springframework.boot' version '2.7.9'
    id 'io.spring.dependency-management' version '1.0.15.RELEASE'
}

group = 'com.junyss'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    // Discord Bot ์‚ฌ์šฉ์„ ์œ„ํ•œ JDA ์˜์กด์„ฑ
    implementation 'net.dv8tion:JDA:5.0.0-beta.5'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.h2database:h2'
    // MyBatis Log๋ฅผ ์ฐ๊ธฐ ์œ„ํ•œ ์˜์กด์„ฑ ์ถ”๊ฐ€(https://mvnrepository.com/artifact/ch.qos.logback/logback-classic)
    testImplementation 'ch.qos.logback:logback-classic:1.4.5'
    // SQL query show
    implementation 'org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16'
    // GSON ์˜์กด์„ฑ
    // https://mvnrepository.com/artifact/com.google.code.gson/gson
    implementation 'com.google.code.gson:gson:2.10.1'
    // https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple
    implementation 'com.googlecode.json-simple:json-simple:1.1.1'
    //SpringDoc ์˜์กด์„ฑ ์ถ”๊ฐ€
    // https://mvnrepository.com/artifact/org.springdoc/springdoc-openapi-ui
    implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'
    // https://mvnrepository.com/artifact/org.json/json
    implementation 'org.json:json:20220924'
}

tasks.named('test') {
    useJUnitPlatform()
}
๋ฐ˜์‘ํ˜•

 

 

 

    ๐Ÿ”ฝ  DTO์™€ VO

์ตœ์ดˆ API๋ฅผ ๋งŒ๋“ค๊ธฐ ์ „ DTO(Data Transfer Object)์™€ VO(Value Object)๋ฅผ ๋จผ์ € ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.


com/junyss/discordbottest/api/crew/model/dto/request/CrewSearchDTO.java 1 ~ 36๋ฒˆ์งธ ์ค„

 

 ์ตœ์ดˆ ๋””์Šค์ฝ”๋“œ ๋ด‡์„ ํ†ตํ•ด ๊ฒ€์ƒ‰์„ ํ•˜๋ ค๊ณ  ํ•  ๋•Œ, ๊ทธ ๊ฒ€์ƒ‰ ํƒ€์ž…๊ณผ ๊ฒ€์ƒ‰์–ด ๊ทธ๋ฆฌ๊ณ , ๋‚ ์งœ๋ฅผ ์ด์šฉํ•ด ๊ฒ€์ƒ‰์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

35๋ฒˆ์งธ ์ค„์— Method(๋ฉ”์„œ๋“œ)๋Š” Client(ํด๋ผ์ด์–ธํŠธ) ์ฆ‰, ์‚ฌ์šฉ์ž๊ฐ€ ๊ฒ€์ƒ‰์„ ์œ„ํ•ด ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅ ํ–ˆ์„ ๋•Œ, ๊ทธ ๊ฐ’์ด ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์—์„œ ๊บผ๋‚ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด์ค€ Getter(๊ฒŒํ„ฐ)์ธ๋ฐ, searchType ๋ณ€์ˆ˜๊ฐ€ Enum Type(์—ด๊ฑฐํ˜• ํƒ€์ž…)์ด๊ณ , ์ด๋ฅผ ๊ทธ๋Œ€๋กœ ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์—์„œ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•˜๊ฒŒ ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ String (๋ฌธ์ž์—ด)๋กœ ๋ฐ”๊ฟ”์„œ ๊ฐ€์ ธ๊ฐ€๊ฒŒ ํ•˜๋„๋ก ํ•˜๋ ค๊ณ  ๋งŒ๋“  ๊ฒŒํ„ฐ ๋ฉ”์„œ๋“œ์—์š”. 

com/junyss/discordbottest/api/crew/model/dto/request/CrewSearchDTO.java 41 ~ 67๋ฒˆ์งธ ์ค„


47๋ฒˆ์งธ setSearchType()์€ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ฒ€์ƒ‰์„ ์œ„ํ•ด ์ž…๋ ฅํ•œ ๊ฒ€์ƒ‰ ํƒ€์ž…์„ ๋ฐ›๊ณ , ์ด๋ฅผ switch(์Šค์œ„์น˜) ๋ฌธ์„ ํ†ตํ•ด ๋ถ„๊ธฐ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์—ฌ ํ•ด๋‹น ๋ฌธ์ž์—ด์„ ๋ถ„์„ํ•˜๊ณ , ๊ทธ์— ๋งž๋Š” ์—ด๊ฑฐํ˜• ํƒ€์ž…์˜ ๊ฐ’์„ searchType ๋ณ€์ˆ˜์— ๋„ฃ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ์ฃผ์—ˆ์–ด์š”.



์ด๋ฒˆ์—๋Š” Response(์‘๋‹ต) DTO๋ฅผ ์‚ดํŽด ๋ณผ๊ฒŒ์š”.

com/junyss/discordbottest/api/crew/model/dto/response/CrewListResponseDTO.java 1 ~ 29๋ฒˆ์งธ ์ค„


์œ„ DTO ๊ฐ์ฒด๋Š” ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค๋ฅผ ํ†ตํ•ด ์กฐํšŒ๋œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋“ค์„ Mapping(๋งคํ•‘)ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด์—์š”.

toDTO()๋Š” ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์—์„œ ์กฐํšŒ๋œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ VO ๊ฐ์ฒดํ˜•์œผ๋กœ ๋‚˜์˜ค๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋ฅผ DTO ํ˜•ํƒœ๋กœ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ์—์š”.

์ด๋ ‡๊ฒŒ ํ•˜์ง€ ์•Š๊ณ , ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ฃผ๋‹ˆ๋Š” ์ด๋ ‡๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”. 

์‚ฌ์‹ค VO์™€ ์‘๋‹ต DTO์˜ ๊ฐ’์ด ๋˜‘๊ฐ™๊ธฐ ๋•Œ๋ฌธ์— ๋ฐ”๋กœ VO๋ฅผ ๋ฐ˜ํ™˜ํ•ด ์ค˜๋„ ๋˜์ง€๋งŒ, Service(์„œ๋น„์Šค)๊ฐ€ ์ปค์ง€๋ฉด ์ปค์งˆ์ˆ˜๋ก ๋˜ํ•œ, ๋ชฉ๋ก ์กฐํšŒ๋Š” ์ด๋ ‡๊ฒŒ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋”ฐ๋กœ ์‘๋‹ต DTO๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ์— ์ค‘์ ์„ ๋‘๊ณ , ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

com/junyss/discordbottest/api/crew/model/vo/CrewVO.java 1 ~ 18๋ฒˆ์งธ ์ค„


VO
์— ๊ฒฝ์šฐ ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

10๋ฒˆ์งธ ์ค„์— ์–ด๋…ธํ…Œ์ด์…˜์€ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž์˜ ์ ‘๊ทผ ์ œ์–ด๋ฅผ PROTECTED(๋‹ค๋ฅธ Package์— ์†Œ์†๋œ Class (์ƒ์† ์ œ์™ธ)๋Š” ์ ‘๊ทผ ๋ถˆ๊ฐ€)๋กœ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด ๋ช…์‹œํ•œ ๊ฒƒ์ธ๋ฐ, ์ด๋Š” ๋ฌด๋ถ„๋ณ„ํ•œ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋ง‰๊ธฐ ์œ„ํ•จ์ด์—์š”.

๋งŒ์•ฝ ์œ„์—์„œ ๋ช…์‹œํ•œ ๋ชจ๋“  ๋ณ€์ˆ˜๋ฅผ ๋‹ค ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—์„œ๋งŒ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์‚ฌ์šฉ๋˜๋„๋ก ํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ new ์—ฐ์‚ฐ์ž ๋“ฑ์„ ์ด์šฉํ•ด VO ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•  ๋•Œ, ํ•ด๋‹น VO ๊ฐ์ฒด๋Š” ์™„์ „ํ•˜์ง€ ์•Š์€ ๊ฐ์ฒด๊ฐ€ ๋  ๊ฑฐ์—์š”.

์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด Null ๊ฐ’์„ ๊ฐ€์ง„ ๋ณ€์ˆ˜๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ๊ฐ์ฒด๋ผ๋Š” ์ด์•ผ๊ธฐ์—์š”.

์ด๋Ÿฐ ์ƒํ™ฉ์„ ๋ง‰๊ธฐ ์œ„ํ•ด ์ด๋Ÿด ๋•Œ๋Š” Builder(๋นŒ๋”) ๋‚˜, ๋‹ค๋ฅธ ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด์„œ ์ ‘๊ทผํ•˜๊ฒŒ ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€๋ฐ, ์ฃผ๋‹ˆ๋Š” ์—ฐ์Šต์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ๋‹ค ์‚ฌ์šฉํ•˜๋„๋ก ๋งŒ๋“ค์–ด ์ค„๊ฑฐ์—์š”.





    ๐Ÿ”ฝ  Controller (์ปจํŠธ๋กค๋Ÿฌ)

์ด๋ฒˆ์—๋Š” ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์— ์ตœ์ „์„ ์„ ๋งก๊ณ  ์žˆ๋Š” ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋งŒ๋“ค์–ด ๋ณผ๊ฒŒ์š”.

com/junyss/discordbottest/api/crew/controller/CrewController.java


์ปจํŠธ๋กค๋Ÿฌ๋Š” ์œ„์™€ ๊ฐ™์ด ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋Š”๋ฐ, 25 ~ 32๋ฒˆ์งธ ์ค„๊นŒ์ง€ ๋‚ด์šฉ์€ springdoc-openapi์„ ์ด์šฉํ•œ Swagger ๋ฌธ์„œ ์ž‘์„ฑ์„ ํ•ด ์ค€ ๊ฑฐ์—์š”.

 


์œ„์™€ ๊ฐ™์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด ์ค€๊ฑฐ์—์š”.

 

์ฐธ๊ณ ๋กœ ์ฃผ๋‹ˆ๋Š” @ModelAttribute๋ฅผ ํ†ตํ•ด ๊ฒ€์ƒ‰ ์กฐ๊ฑด์„ ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ๋ฐ›์•„์ฃผ๋„๋ก ํ•˜์˜€์–ด์š”.

 

 

๐Ÿ’ก ์ฐธ๊ณ  ์‚ฌํ•ญ
RequestParam๊ณผ ModelAttribute ์ฐจ์ด

1. @RequestParam ์ด๋ž€?
Client ์š”์ฒญ์— ์ „๋‹ฌ๊ฐ’์„ Handler(Controller)์˜ ๋งค๊ฐœ ๋ณ€์ˆ˜(Parameter)๋กœ 1:1 Mapping(๋งคํ•‘) ํ•  ๋•Œ ์‚ฌ์šฉ

@Slf4j
@Controller
public class JunyssTestController {
    @GetMapping("/")
    public String getTestPage(@RequestParam("name") String name) {
        log.info("์ด๋ฆ„ : " + name);
        return "test";
    }
}


์œ„์™€ ๊ฐ™์€ Controller๊ฐ€ ์žˆ์„ ๋•Œ, Client๊ฐ€ URL์„ ํ†ตํ•ด /?name=test ๋ผ๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด name ๋ณ€์ˆ˜์—๋Š” test ๋ผ๋Š” ๋ฌธ์ž์—ด์ด ๋“ค์–ด๊ฐ.

1. @ModelAttribute ๋ž€?
ํ•ด๋‹น ์–ด๋…ธํ…Œ์ด์…˜์€ Method(๋ฉ”์„œ๋“œ) Level(๋ ˆ๋ฒจ)๊ณผ ๋งค๊ฐœ ๋ณ€์ˆ˜ ๋‘ ๊ณณ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.

@Getter 
@Setter 
public class JunyssTestDTO { 
	private String name; private int age; 
} 

@Slf4j 
@RestController 
public class JunyssTestController { 
@GetMapping("/") 
    public String getTestPage(@ModelAttribute JunyssTestDTO junyssTestDTO) { 
    log.info("์ด๋ฆ„ : " + junyssTestDTO.getName()); 
    log.info("๋‚˜์ด : " + junyssTestDTO.getAge()); return "test"; 
	} 
}โ€‹
728x90

 

์œ„์™€ ๊ฐ™์ด DTO์™€ Controller๊ฐ€ ์žˆ์„ ๋•Œ, name๊ณผ age๋ฅผ ์ธ์Šคํ„ด์Šค Member ๋ณ€์ˆ˜๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” DTO๋ฅผ ํ†ตํ•ด Controller์—์„œ ํ•ด๋‹น ๋งค๊ฐœ ๋ณ€์ˆ˜์— ๋งž๋Š” ๊ฐ’๋“ค์„ ๋ฐ›๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋•Œ, ์ด์šฉ์ž๊ฐ€ URL์„ ํ†ตํ•ด /?name=Juny&age=99 ๋ผ๊ณ  ๊ฐ’์„ ๋ณด๋‚ด๊ฒŒ ๋˜๋ฉด Controller์˜ DTO ๊ฐ์ฒด๋กœ Binding์ด ๋˜๊ฒŒ ๋œ๋‹ค.
๋‹จ, ํ•ด๋‹น ๋งค๊ฐœ ๋ณ€์ˆ˜ ๊ฐ์ฒด๋Š” ๋ฐ˜๋“œ์‹œ Setter๊ฐ€ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

 






    ๐Ÿ”ฝ  Service (์„œ๋น„์Šค)

์ด๋ฒˆ์—๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ๋ฅผ ๋‹ด๋‹นํ•˜๋Š” ์„œ๋น„์Šค ๊ฐ์ฒด๋ฅผ ๋งŒ๋‚˜๋ณผ๊ฒŒ์š”.

์ฃผ๋‹ˆ๋Š” SOLID ์›์น™ ์ค‘ OCP๋ฅผ ์ง€ํ‚ค๊ธฐ ์œ„ํ•ด Interface์™€ ๊ตฌํ˜„์ฒด๋ฅผ ๋ถ„๋ฆฌํ•ด์„œ ๋งŒ๋“ค์–ด ๋ณด์•˜์–ด์š”.
๋ฌผ๋ก  ๋‹ค๋ฅธ ๋‚ด์šฉ์œผ๋กœ ๋Œ€์ฒดํ•  ๊ฒƒ์ด ์—†๊ธด ํ•˜์ง€๋งŒ, ์ผ๋‹จ ๋ถ„๋ฆฌํ•ด ๋ณด์•˜์–ด์š”.

com/junyss/discordbottest/api/crew/service/CrewService.java 1 ~ 12๋ฒˆ์งธ ์ค„

 

 

com/junyss/discordbottest/api/crew/service/Impl/CrewServiceImpl.java 1 ~ 35๋ฒˆ์งธ ์ค„

 


Interface๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด์—์„œ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋œ CrewSearchDTO๋ฅผ ๋ฐ›์•„ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

30 ~ 31๋ฒˆ์งธ ์ค„์—์„œ crewSearchDTO๋ฅผ ์ด์šฉํ•ด์„œ DAO (Data Access Object)์˜ findByCrewList()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์กฐํšŒ๋œ ๊ฐ’์„ ๊บผ๋‚ด์˜ค๊ฒŒ ํ•˜์˜€๊ณ , ์กฐํšŒ๋œ ๊ฐ’์ด Null safetyํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด .filter(Objects::nonNull)์„ ๋ช…์‹œํ•˜๊ณ , ์กฐํšŒ๋œ ๊ฐ’์„ forEach ๋ฌธ์„ ํ†ตํ•ด ๋ฐ˜๋ณตํ•˜๋ฉด์„œ ์ƒˆ๋กญ๊ฒŒ ๋งŒ๋“  resultArray List์— ๋‹ด์•„์ฃผ๋Š”๋ฐ, ์ด ๋•Œ, ์œ„์—์„œ ์ด์•ผ๊ธฐ ํ–ˆ์—ˆ๋˜ VO๋ฅผ DTO๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” toDTO()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ DTO ๊ฐ์ฒด๋กœ ๋ฐ”๊ฟ” ์ค€ ๋’ค์— resultArray์— ๋‹ด์•„ ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋Ÿฐ ๋’ค ํ•ด๋‹น ๋ฐฐ์—ด์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•ด ์ฃผ๋„๋ก ํ•˜์˜€์–ด์š”.







    ๐Ÿ”ฝ Data Access Object (DAO - ๋‹ค์˜ค)

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ Data Base์— ์ ์  ๊ฐ€๊นŒ์›Œ์ง€๊ณ  ์žˆ์–ด์š”!

com/junyss/discordbottest/api/crew/dao/CrewDAO.java 1 ~ 21๋ฒˆ์งธ ์ค„

 

 

com/junyss/discordbottest/api/crew/dao/Impl/CrewDAOImpl.java 1 ~ 36๋ฒˆ์งธ ์ค„


์ด๋ฒˆ์—๋Š” DAO์— ๋Œ€ํ•ด ์‚ดํŽด ๋ณผ๊ฒŒ์š”.

์ตœ์ดˆ 31๋ฒˆ์งธ ์ค„์— ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด findByCrewList()๋Š” ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์—์„œ ์ฝ๊ธฐ ์ž‘์—…๋งŒ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜์—ฌ ์ฃผ์—ˆ์–ด์š”. ๋งŒ์•ฝ ์“ฐ๊ธฐ ์ž‘์—…์„ ํ•ด์•ผ ํ•œ๋‹ค๋ฉด (reaOnly = true)๋งŒ ์‚ดํฌ์‹œ ์—†์• ์ฃผ๋ฉด ๋˜์š”.

๊ทธ๋Ÿฐ ๋’ค Mapper ๊ฐ์ฒด์˜ findByCrewList()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์—ญ์‹œ DTO๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ์—ˆ์–ด์š”.









 

    ๐Ÿ”ฝ MyBatis Mapper (๋งคํผ)

com/junyss/discordbottest/api/crew/mapper/CrewManagementMapper.java 1 ~ 24๋ฒˆ์งธ ์ค„

 

์ด ๊ณณ์—์„œ ์‹ค์ œ๋กœ ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์— SQL ๋ฌธ์„ ์ž‘์„ฑํ•˜๋Š” XML์„ ๋งคํ•‘ํ•ด ์ค„ ์ˆ˜ ์žˆ์–ด์š”.

@Param์€ ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค์˜ SQL ๋ฌธ์žฅ์— ์—ฌ๋Ÿฌ ๋งค๊ฐœ ๋ณ€์ˆ˜๊ฐ’์„ ์ „๋‹ฌํ•  ๋•Œ, ๋ถ™ํ˜€์ค˜์•ผ ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜์ธ๋ฐ, ์ด๋ ‡๊ฒŒํ•ด์•ผ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ๋ฐ›์„ ๋•Œ, ๋ช…ํ™•ํ•˜๊ฒŒ ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค SQL ๋ฌธ์žฅ์— ๋งค๊ฐœ ๋ณ€์ˆ˜๋ฅผ ์ „๋‹ฌํ•ด ์ค„ ์ˆ˜ ์žˆ์–ด์š”.

mapper/CrewManagementMapper.xml 1 ~ 41๋ฒˆ์งธ ์ค„



์ฃผ๋‹ˆ๊ฐ€ ์ž‘์„ฑํ•œ 
๋งˆ์ด๋ฐ”ํ‹ฐ์Šค ๋งคํผ XML์ด์—์š”.

์œ„์—์„œ ์ด์•ผ๊ธฐํ•œ๋Œ€๋กœ @Param์„ ํ†ตํ•ด ๋งค๊ฐœ ๋ณ€์ˆ˜๋กœ ์ „๋‹ฌ๋œ DTO ๊ฐ’์˜ Getter๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ•ด๋‹น ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์˜ฌ ์ˆ˜ ์žˆ๋Š”๋ฐ, 10๋ฒˆ์งธ ์ค„์— ๊ฒ€์ƒ‰ ํƒ€์ž…์ด Null์ด๊ฑฐ๋‚˜, ๊ณต๋ฐฑ์ด๋ผ๋ฉด 11 ~ 31๋ฒˆ์งธ ์ค„์„ ํƒ€์ง€ ์•Š๊ฒŒ ํ•ด ์ฃผ์—ˆ์–ด์š”.

๋งŒ์•ฝ ๊ฒ€์ƒ‰ ํƒ€์ž…์ด ์žˆ๋‹ค๋ฉด ๊ทธ ๊ฐ’์— ์–ด๋–ค ๋ฌธ์ž์—ด์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ํ•ด๋‹น ๋ฌธ์ž์—ด์— ๋งž๋Š” ์ปฌ๋Ÿผ์— searchWord ์ฆ‰, ๊ฒ€์ƒ‰์–ด๊ฐ€ ์žˆ๋Š”์ง€ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ์–ด์š”.

๊ทธ๋Ÿฐ ๋’ค 27๋ฒˆ์งธ ์ค„์— ๋‚ ์งœ ๋ฒ”์œ„ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ startDate์™€ endDate๊ฐ€ Null์ด ์•„๋‹Œ์ง€ ํ™•์ธํ•˜๊ณ , and ์ ˆ์„ ํ†ตํ•ด Null์ด ์•„๋‹ˆ๋ฉด BETWEEN A And B ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‚ ์งœ ๋ฒ”์œ„๋ฅผ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.

33๋ฒˆ์งธ ์ค„์—๋Š” 10๋ฒˆ์งธ ์ค„์ด Null์ด๊ฑฐ๋‚˜, ๊ณต๋ฐฑ ์ฆ‰, ๊ฒ€์ƒ‰ ํƒ€์ž…์— ๊ฐ’์ด ์—†์–ด ๊ฒ€์ƒ‰์–ด๋ฅผ ์ด์šฉํ•œ ๊ฒ€์ƒ‰์ด ์ด๋ค„์ง€์ง€ ์•Š์„ ๋•Œ, ๋‚ ์งœ ๋ฒ”์œ„ ๊ฒ€์ƒ‰๋งŒ์„ ์›ํ•ด ํ•ด๋‹น ๊ฐ’์ด Null์ด ์•„๋‹ˆ๋ฉด ๋‚ ์งœ ๋ฒ”์œ„ ๊ฒ€์ƒ‰์ด ๋˜๋„๋ก ์ฒ˜๋ฆฌํ•ด ์ฃผ์—ˆ์–ด์š”.






    ๐Ÿ”ฝ Data Base Initialization (๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค ์ดˆ๊ธฐํ™”)

init/database/schema.sql 1 ~ 10๋ฒˆ์งธ ์ค„

 


์ฃผ๋‹ˆ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ด๋ ‡๊ฒŒ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค์— ๋ฏธ๋ฆฌ ํ…Œ์ด๋ธ”์ด ๋งŒ๋“ค์–ด ์ง€๋„๋ก ํ•˜์˜€์–ด์š”.


init/database/data.sql 1 ~ 8๋ฒˆ์งธ ์ค„

 


๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ํ…Œ์ŠคํŠธ์šฉ DATA (๋ฐ์ดํ„ฐ)๊ฐ€ ์Œ“์ผ ์ˆ˜ ์žˆ๋„๋ก ํ•ด ์ฃผ์—ˆ์–ด์š”.

application.yml 5 ~ 29๋ฒˆ์งธ ์ค„

 


์ฃผ๋‹ˆ๋Š” ์œ„์™€ ๊ฐ™์ด H2 Embeded (์ž„๋ฒ ๋””๋“œ)๋กœ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๊ฐ€ ์‚ฌ์šฉ๋˜๋„๋ก ํ•ด ์ฃผ์—ˆ๋Š”๋ฐ, 20 ~ 24๋ฒˆ์งธ ์ค„ ์„ค์ •์„ ํ•ด์ฃผ๋ฉด ์œ„์™€ schema.sql๊ณผ data.sql์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

discord:
  bot:
    token: <Discord Bot Token Value>
spring:
  h2:
    console:
      enabled: true
      path: /h2-console
      settings:
        web-allow-others: true

  datasource:
    url: jdbc:log4jdbc:h2:~/giggal-discord-bot?serverTimezone=UTC&characterEncoding=UTF-8;MODE=MySQL;
    username: sa
    password:
    driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy

  sql:
    init:
      mode: always
      schema-locations: classpath:init/database/schema.sql
      data-locations: classpath:init/database/data.sql

mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    map-underscore-to-camel-case: true

springdoc:
  api-docs:
    groups:
      enabled: true
  swagger-ui:
    operations-sorter: alpha
    tags-sorter: alpha
    path: /swagger.html
    disable-swagger-default-url: true
    display-query-params-without-oauth2: true
    doc-expansion: none
    version: v1
    display-request-duration: true

  cache:
    disabled: true

  paths-to-match:
    - /api/**

 

 

 

 

GitHub - junyharang-personal-project/juny-discord-bot-test: JDA๋ฅผ ์ด์šฉํ•œ Spring Boot Discord Bot ์—ฐ์Šต์ด์—์š”.

JDA๋ฅผ ์ด์šฉํ•œ Spring Boot Discord Bot ์—ฐ์Šต์ด์—์š”. Contribute to junyharang-personal-project/juny-discord-bot-test development by creating an account on GitHub.

github.com

 

์ฃผ๋‹ˆ๊ฐ€ ๋งŒ๋“  Source Code(์†Œ์Šค ์ฝ”๋“œ)๊ฐ€ ๊ถ๊ธˆํ•˜์‹  ๋ถ„๋“ค์€ ์œ„์— Git Hub ๋งํฌ์—์„œ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ค€๋น„ํ•ด ๋‘์—ˆ์–ด์š”.




 

 

 

์ „์ž์ •๋ถ€ ํ‘œ์ค€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์–‘๋Œ€ ํ•ต์‹ฌ ๊ธฐ์ˆ  ์„ธํŠธ : ์Šคํ”„๋ง + ๋งˆ์ด๋ฐ”ํ‹ฐ์Šค

COUPANG

www.coupang.com

"์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ, ์ด์— ๋”ฐ๋ฅธ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค."

 



 

 

 

 

728x90
๋ฐ˜์‘ํ˜•