Skip to content

Commit 1d66bf5

Browse files
authored
✨ [Feat] 가격 변동 알림 구현 (1/2)
2 parents 9e98013 + 4411d34 commit 1d66bf5

15 files changed

Lines changed: 467 additions & 19 deletions

File tree

build.gradle

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ dependencies {
4242
// MySQL
4343
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
4444

45-
4645
// Test
4746
testImplementation 'org.springframework.boot:spring-boot-starter-test'
4847
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
@@ -65,7 +64,7 @@ dependencies {
6564

6665
// Firebase
6766
implementation 'com.google.firebase:firebase-admin:9.7.0'
68-
67+
6968
// Spring Security
7069
implementation 'org.springframework.boot:spring-boot-starter-security'
7170

@@ -74,6 +73,15 @@ dependencies {
7473

7574
// Dotenv (환경변수)
7675
implementation 'me.paulschwarz:spring-dotenv:4.0.0'
76+
77+
// WebSocket
78+
implementation 'org.springframework.boot:spring-boot-starter-websocket'
79+
implementation 'org.webjars:stomp-websocket:2.3.3'
80+
implementation 'org.webjars:webjars-locator-core'
81+
implementation 'org.webjars:sockjs-client:1.0.2'
82+
83+
// Retry
84+
implementation 'org.springframework.retry:spring-retry'
7785
}
7886

7987
tasks.named('test') {

src/main/java/com/example/scoi/ScoiApplication.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55
import org.springframework.cloud.openfeign.EnableFeignClients;
66
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
7+
import org.springframework.retry.annotation.EnableRetry;
78

89
@SpringBootApplication
910
@EnableJpaAuditing
1011
@EnableFeignClients
12+
@EnableRetry
1113
public class ScoiApplication {
1214

1315
public static void main(String[] args) {

src/main/java/com/example/scoi/domain/member/entity/MemberFcm.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@ public class MemberFcm {
3131
@ManyToOne(fetch = FetchType.LAZY)
3232
@JoinColumn(name = "member_id")
3333
private Member member;
34+
35+
// 업데이트
36+
public void updateFcmToken(String fcmToken){
37+
this.fcmToken = fcmToken;
38+
}
3439
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.example.scoi.domain.websocket;
2+
3+
import com.example.scoi.domain.websocket.handler.UpbitTickerHandler;
4+
import lombok.RequiredArgsConstructor;
5+
import lombok.extern.slf4j.Slf4j;
6+
import org.springframework.boot.context.event.ApplicationReadyEvent;
7+
import org.springframework.context.event.EventListener;
8+
import org.springframework.stereotype.Service;
9+
import org.springframework.web.socket.client.WebSocketClient;
10+
11+
@Service
12+
@RequiredArgsConstructor
13+
@Slf4j
14+
public class WebsocketConnect {
15+
16+
private final WebSocketClient webSocketClient;
17+
private final UpbitTickerHandler upbitTickerHandler;
18+
19+
private static final String PUBLIC_URL = "wss://api.upbit.com/websocket/v1";
20+
21+
// 실시간 가격 변동 체크
22+
@EventListener(ApplicationReadyEvent.class)
23+
public void connect(){
24+
log.info("[ Websocket ]: 디페깅 알고리즘 구동 시작...");
25+
webSocketClient.execute(upbitTickerHandler, PUBLIC_URL);
26+
}
27+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.example.scoi.domain.websocket.converter;
2+
3+
import com.example.scoi.domain.websocket.dto.UpbitReqDTO;
4+
import com.example.scoi.domain.websocket.dto.WebSocketReqDTO;
5+
import com.fasterxml.jackson.core.JsonProcessingException;
6+
import com.fasterxml.jackson.databind.ObjectMapper;
7+
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.web.socket.TextMessage;
10+
11+
import java.util.List;
12+
import java.util.UUID;
13+
14+
@RequiredArgsConstructor
15+
public class WebSocketConverter {
16+
17+
private static final ObjectMapper objectMapper = new ObjectMapper()
18+
.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
19+
20+
// 코인 가격 조회: 업비트
21+
public static TextMessage toGetCoinPrice(
22+
List<String> codes
23+
) throws JsonProcessingException {
24+
List<Object> payload = List.of(toTicket(), toTicker(codes) ,toFormat());
25+
return new TextMessage(objectMapper.writeValueAsString(payload));
26+
}
27+
28+
private static WebSocketReqDTO.Ticket toTicket(){
29+
return WebSocketReqDTO.Ticket.builder()
30+
.ticket(UUID.randomUUID().toString())
31+
.build();
32+
}
33+
34+
private static WebSocketReqDTO.Format toFormat(){
35+
return WebSocketReqDTO.Format.builder()
36+
.format("SIMPLE_LIST")
37+
.build();
38+
}
39+
40+
private static UpbitReqDTO.Ticker toTicker(
41+
List<String> codes
42+
){
43+
return UpbitReqDTO.Ticker.builder()
44+
.type("ticker")
45+
.codes(codes)
46+
.build();
47+
}
48+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.scoi.domain.websocket.dto;
2+
3+
public class BithumbReqDTO {
4+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.example.scoi.domain.websocket.dto;
2+
3+
import lombok.Builder;
4+
5+
import java.util.List;
6+
7+
public class UpbitReqDTO {
8+
9+
// 가격 실시간 조회
10+
@Builder
11+
public record Ticker(
12+
String type,
13+
List<String> codes
14+
){}
15+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.example.scoi.domain.websocket.dto;
2+
3+
import java.util.Date;
4+
5+
public class UpbitResDTO {
6+
7+
// 현제 코인 가격
8+
public record Ticker(
9+
String ty,
10+
String cd,
11+
Double op,
12+
Double hp,
13+
Double lp,
14+
Double tp,
15+
Double pcp,
16+
String c,
17+
Double cp,
18+
Double scp,
19+
Double cr,
20+
Double scr,
21+
Double tv,
22+
Double atv,
23+
Double atv24h,
24+
Double atp,
25+
Double atp24h,
26+
String tdt,
27+
String ttm,
28+
Long ttms,
29+
String ab,
30+
Double aav,
31+
Double abv,
32+
Double h52wp,
33+
String h52wdt,
34+
Double l52wp,
35+
String l52wdt,
36+
String ms,
37+
Date dd,
38+
Long tms,
39+
String st,
40+
41+
// Deprecated
42+
Boolean its,
43+
String mw
44+
){}
45+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.example.scoi.domain.websocket.dto;
2+
3+
import lombok.Builder;
4+
5+
public class WebSocketReqDTO {
6+
7+
@Builder
8+
public record Ticket(
9+
String ticket
10+
){}
11+
12+
@Builder
13+
public record Format(
14+
String format
15+
){}
16+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.example.scoi.domain.websocket.enums;
2+
3+
import lombok.RequiredArgsConstructor;
4+
5+
@RequiredArgsConstructor
6+
public enum RiseOrFall {
7+
RISE("올랐어요."),
8+
FALL("떨어졌어요.")
9+
;
10+
11+
private final String message;
12+
}

0 commit comments

Comments
 (0)