Skip to content

Commit 311ec8a

Browse files
authored
feat: 알람 기능 구현
# 변경점 👍 알람 기능을 구현했습니다. `firebase`를 통한 알람 기능을 구현했습니다. (먼저 킬링파트 좋아요에만 알람 리스너 추가해놨습니다. 먼저 알람 정상 확인하고 추후 확장예정) 알람을 보내기 위해서는 클라이언트에서 발급한 디바이스 토큰을 `POST /api/fcm/tokens` 엔드포인트를 호출해서 저장해야합니다. `Alarm` 엔티티는 단순히 DB에 저장하기 위한 용도입니다. 알람 구현에는 `ApplicationEventPublisher`와 `TransactionalEventListener`를 사용해봤습니다. 특정 클래스를 `ApplicationEventPublisher`로 이벤트를 publish하면 `TransactionalEventListener`가 동작합니다.
1 parent ad4a83c commit 311ec8a

31 files changed

Lines changed: 743 additions & 7 deletions

.github/workflows/deploy.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ jobs:
3434
- name: 테스트 환경변수 주입
3535
run: echo "${{ secrets.APPLICATION_TEST_PROPERTIES }}" > ./src/test/resources/application.properties
3636

37+
- name: firebase 디렉토리 생성
38+
run: mkdir -p ./src/main/resources/firebase
39+
40+
- name: fcm.json 파일 주입
41+
id: create-json
42+
uses: jsdaniell/create-json@v1.2.2
43+
with:
44+
name: "killing-part-32870-firebase-adminsdk-fbsvc-f5c0d13f5b.json"
45+
json: ${{ secrets.FIREBASE_KEY }}
46+
dir: 'src/main/resources/firebase/'
47+
48+
3749
- name: 테스트 및 빌드하기
3850
run: ./gradlew clean build
3951

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,3 +40,4 @@ out/
4040
.env
4141
src/main/resources/application-prod.properties
4242
src/test/resources/application-prod.properties
43+
src/main/resources/firebase/

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ dependencies {
7272
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
7373

7474
implementation 'org.springframework.ai:spring-ai-starter-model-openai:1.1.0'
75+
76+
// firebase
77+
implementation 'com.google.firebase:firebase-admin:9.2.0'
7578
}
7679

7780

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package apptive.team5.alarm.controller;
2+
3+
import apptive.team5.alarm.dto.AlarmResponse;
4+
import apptive.team5.alarm.service.AlarmService;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.data.domain.Page;
7+
import org.springframework.data.domain.PageRequest;
8+
import org.springframework.data.domain.Pageable;
9+
import org.springframework.data.domain.Sort;
10+
import org.springframework.http.HttpStatus;
11+
import org.springframework.http.MediaType;
12+
import org.springframework.http.ResponseEntity;
13+
import org.springframework.security.core.annotation.AuthenticationPrincipal;
14+
import org.springframework.web.bind.annotation.GetMapping;
15+
import org.springframework.web.bind.annotation.RequestMapping;
16+
import org.springframework.web.bind.annotation.RequestParam;
17+
import org.springframework.web.bind.annotation.RestController;
18+
19+
@RestController
20+
@RequestMapping("/api/alarms")
21+
@RequiredArgsConstructor
22+
public class AlarmController {
23+
24+
private final AlarmService alarmService;
25+
26+
@GetMapping
27+
public ResponseEntity<Page<AlarmResponse>> getAlarms(
28+
@RequestParam(name = "page", defaultValue = "0") int page,
29+
@RequestParam(name = "size", defaultValue = "5") int size,
30+
@AuthenticationPrincipal Long userId
31+
) {
32+
Pageable pageable = PageRequest.of(
33+
page,
34+
size,
35+
Sort.by(
36+
Sort.Order.desc("createDateTime"),
37+
Sort.Order.desc("id")
38+
)
39+
);
40+
Page<AlarmResponse> alarms = alarmService.getAlarms(userId, pageable);
41+
42+
return ResponseEntity.status(HttpStatus.OK).body(alarms);
43+
}
44+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package apptive.team5.alarm.dto;
2+
3+
4+
import apptive.team5.alarm.entity.Alarm;
5+
6+
public record AlarmResponse(
7+
Long alarmId,
8+
String title,
9+
String content,
10+
String deepLink
11+
) {
12+
13+
public AlarmResponse(Alarm alarm) {
14+
this(
15+
alarm.getId(),
16+
alarm.getTitle(),
17+
alarm.getContent(),
18+
alarm.getDeepLink()
19+
);
20+
}
21+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package apptive.team5.alarm.dto;
2+
3+
import apptive.team5.user.domain.UserEntity;
4+
5+
public record AlarmSendRequest(
6+
Long diaryId,
7+
Long actorId
8+
) {
9+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package apptive.team5.alarm.entity;
2+
3+
4+
import apptive.team5.global.entity.BaseTimeEntity;
5+
import apptive.team5.user.domain.UserEntity;
6+
import jakarta.persistence.*;
7+
import lombok.AccessLevel;
8+
import lombok.AllArgsConstructor;
9+
import lombok.Getter;
10+
import lombok.NoArgsConstructor;
11+
12+
@Entity
13+
@Getter
14+
@AllArgsConstructor
15+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
16+
public class Alarm extends BaseTimeEntity {
17+
18+
@Id
19+
@GeneratedValue(strategy = GenerationType.IDENTITY)
20+
private Long id;
21+
22+
@Column(nullable = false, length = 1000)
23+
private String title;
24+
25+
@Column(nullable = false, length = 1000)
26+
private String content;
27+
28+
@Column(nullable = false, length = 1000)
29+
private String deepLink;
30+
31+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
32+
@JoinColumn(
33+
name = "user_id",
34+
nullable = false
35+
)
36+
private UserEntity user;
37+
38+
public Alarm(String title, String content, String deepLink, UserEntity user) {
39+
this.title = title;
40+
this.content = content;
41+
this.deepLink = deepLink;
42+
this.user = user;
43+
}
44+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package apptive.team5.alarm.entity;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public enum AlarmMessage {
7+
8+
LIKE_ALARM("킬링파트에 좋아요가 도착했어요");
9+
10+
private final String message;
11+
12+
13+
AlarmMessage(String message) {
14+
this.message = message;
15+
}
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package apptive.team5.alarm.event;
2+
3+
public record AlarmCreatedEvent(
4+
Long receiverId,
5+
String title,
6+
String content,
7+
String deepLink
8+
) {
9+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package apptive.team5.alarm.event;
2+
3+
import apptive.team5.fcm.service.FcmService;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.stereotype.Component;
6+
import org.springframework.transaction.event.TransactionPhase;
7+
import org.springframework.transaction.event.TransactionalEventListener;
8+
9+
@Component
10+
@RequiredArgsConstructor
11+
public class AlarmEventListener {
12+
13+
private final FcmService fcmService;
14+
15+
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
16+
public void handleAlarmCreated(AlarmCreatedEvent event) {
17+
fcmService.sendAlarm(event.receiverId(), event.title(), event.content(), event.deepLink());
18+
}
19+
}

0 commit comments

Comments
 (0)