-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
28 changed files
with
630 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
36 changes: 36 additions & 0 deletions
36
src/main/java/com/kkokkomu/short_news/alarm/controller/AlarmController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package com.kkokkomu.short_news.alarm.controller; | ||
|
||
import com.kkokkomu.short_news.alarm.dto.request.FcmSendDto; | ||
import com.kkokkomu.short_news.alarm.dto.request.PushAlarmDto; | ||
import com.kkokkomu.short_news.alarm.service.FCMSendService; | ||
import com.kkokkomu.short_news.core.annotation.UserId; | ||
import com.kkokkomu.short_news.core.dto.ResponseDto; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.Parameter; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import java.io.IOException; | ||
|
||
@Tag(name = "알람") | ||
@RestController | ||
@Slf4j | ||
@RequiredArgsConstructor | ||
@RequestMapping("/alarm") | ||
public class AlarmController { | ||
private FCMSendService fcmSendService; | ||
|
||
@Operation(summary = "알람 테스트") | ||
@GetMapping("/test") | ||
public ResponseDto<String> test( | ||
@Parameter(hidden = true) @UserId Long userId, | ||
@RequestBody PushAlarmDto pushAlarmDto | ||
) throws IOException { | ||
return ResponseDto.ok(fcmSendService.test(pushAlarmDto, userId)); | ||
} | ||
} |
38 changes: 0 additions & 38 deletions
38
src/main/java/com/kkokkomu/short_news/alarm/domain/AlarmSetting.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
src/main/java/com/kkokkomu/short_news/alarm/dto/request/CreateTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.kkokkomu.short_news.alarm.dto.request; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
|
||
public record CreateTokenDto ( | ||
@NotNull | ||
String fcmToken, | ||
|
||
@NotNull | ||
String deviceId | ||
) { | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/kkokkomu/short_news/alarm/dto/request/FcmMessageDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.kkokkomu.short_news.alarm.dto.request; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
@Builder | ||
public class FcmMessageDto { | ||
private boolean validateOnly; | ||
private FcmMessageDto.Message message; | ||
|
||
@Builder | ||
@AllArgsConstructor | ||
@Getter | ||
public static class Message { | ||
private FcmMessageDto.Notification notification; | ||
private String token; | ||
} | ||
|
||
@Builder | ||
@AllArgsConstructor | ||
@Getter | ||
public static class Notification { | ||
private String title; | ||
private String body; | ||
private String image; | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
src/main/java/com/kkokkomu/short_news/alarm/dto/request/FcmSendDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.kkokkomu.short_news.alarm.dto.request; | ||
|
||
import lombok.*; | ||
|
||
@Getter | ||
@ToString | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class FcmSendDto { | ||
private String token; | ||
|
||
private String title; | ||
|
||
private String body; | ||
|
||
@Builder(toBuilder = true) | ||
public FcmSendDto(String token, String title, String body) { | ||
this.token = token; | ||
this.title = title; | ||
this.body = body; | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
src/main/java/com/kkokkomu/short_news/alarm/dto/request/PushAlarmDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.kkokkomu.short_news.alarm.dto.request; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
|
||
public record PushAlarmDto( | ||
@NotNull String deviceId, | ||
@NotNull String title, | ||
@NotNull String body | ||
) { | ||
} |
23 changes: 23 additions & 0 deletions
23
src/main/java/com/kkokkomu/short_news/alarm/dto/response/FCMTokenDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package com.kkokkomu.short_news.alarm.dto.response; | ||
|
||
import com.kkokkomu.short_news.alarm.domain.FCMToken; | ||
import lombok.Builder; | ||
|
||
@Builder | ||
public record FCMTokenDto( | ||
Long id, | ||
String token, | ||
String deviceId, | ||
String editedAt, | ||
String expiredAt | ||
) { | ||
public static FCMTokenDto of(FCMToken fcmToken) { | ||
return FCMTokenDto.builder() | ||
.id(fcmToken.getId()) | ||
.token(fcmToken.getToken()) | ||
.deviceId(fcmToken.getDeviceId()) | ||
.editedAt(fcmToken.getEditedAt().toString()) | ||
.expiredAt(fcmToken.getExpiredAt().toString()) | ||
.build(); | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
src/main/java/com/kkokkomu/short_news/alarm/repository/FCMTokenRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.kkokkomu.short_news.alarm.repository; | ||
|
||
import com.kkokkomu.short_news.alarm.domain.FCMToken; | ||
import com.kkokkomu.short_news.user.domain.User; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.data.jpa.repository.Query; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import java.time.LocalDateTime; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@Repository | ||
public interface FCMTokenRepository extends JpaRepository<FCMToken, Long> { | ||
|
||
// 만기된 토큰들 조회 | ||
@Query("SELECT token FROM FCMToken token WHERE token.expiredAt <= :now") | ||
List<FCMToken> findExpiredTokenList(LocalDateTime now); | ||
|
||
List<FCMToken> findAllByDeviceId(String deviceId); | ||
|
||
FCMToken findByToken(String token); | ||
|
||
Optional<FCMToken> findByDeviceIdAndToken(String deviceId, String token); | ||
|
||
FCMToken findByDeviceIdAndUserId(String deviceId, Long userId); | ||
|
||
void deleteByDeviceIdAndUser(String deviceId, User user); | ||
} |
121 changes: 121 additions & 0 deletions
121
src/main/java/com/kkokkomu/short_news/alarm/service/FCMSendService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package com.kkokkomu.short_news.alarm.service; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.google.auth.oauth2.GoogleCredentials; | ||
import com.kkokkomu.short_news.alarm.domain.FCMToken; | ||
import com.kkokkomu.short_news.alarm.dto.request.FcmMessageDto; | ||
import com.kkokkomu.short_news.alarm.dto.request.FcmSendDto; | ||
import com.kkokkomu.short_news.alarm.dto.request.PushAlarmDto; | ||
import com.kkokkomu.short_news.alarm.repository.FCMTokenRepository; | ||
import com.kkokkomu.short_news.user.domain.User; | ||
import com.kkokkomu.short_news.user.service.UserLookupService; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.core.io.ClassPathResource; | ||
import org.springframework.http.*; | ||
import org.springframework.http.converter.StringHttpMessageConverter; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.web.client.RestTemplate; | ||
|
||
import java.io.IOException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Slf4j | ||
public class FCMSendService { | ||
@Value("${fcm.firebase-key}") | ||
private String firebaseConfigPath; | ||
|
||
private final FCMTokenRepository fcmTokenRepository; | ||
|
||
private final UserLookupService userLookupService; | ||
|
||
public String test(PushAlarmDto pushAlarmDto, Long userId) { | ||
FCMToken fcmToken = fcmTokenRepository.findByDeviceIdAndUserId(pushAlarmDto.deviceId(), userId); | ||
|
||
sendMessageTo( | ||
FcmSendDto.builder() | ||
.token(fcmToken.getToken()) | ||
.title(pushAlarmDto.title()) | ||
.body(pushAlarmDto.body()) | ||
.build() | ||
); | ||
|
||
return "success"; | ||
} | ||
|
||
/** | ||
* 푸시 메시지 처리를 수행하는 비즈니스 로직 | ||
* | ||
* @param fcmSendDto 모바일에서 전달받은 Object | ||
* @return 성공(1), 실패(0) | ||
*/ | ||
public int sendMessageTo(FcmSendDto fcmSendDto) { | ||
try { | ||
String message = makeMessage(fcmSendDto); | ||
RestTemplate restTemplate = new RestTemplate(); | ||
/** | ||
* 추가된 사항 : RestTemplate 이용중 클라이언트의 한글 깨짐 증상에 대한 수정 | ||
* @refernece : https://stackoverflow.com/questions/29392422/how-can-i-tell-resttemplate-to-post-with-utf-8-encoding | ||
*/ | ||
restTemplate.getMessageConverters() | ||
.add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8)); | ||
|
||
HttpHeaders headers = new HttpHeaders(); | ||
headers.setContentType(MediaType.APPLICATION_JSON); | ||
headers.set("Authorization", "Bearer " + getAccessToken()); | ||
|
||
HttpEntity entity = new HttpEntity<>(message, headers); | ||
|
||
String API_URL = "<https://fcm.googleapis.com/v1/projects/adjh54-a0189/messages:send>"; | ||
ResponseEntity response = restTemplate.exchange(API_URL, HttpMethod.POST, entity, String.class); | ||
|
||
log.info(String.valueOf(response.getStatusCode())); | ||
|
||
return response.getStatusCode() == HttpStatus.OK ? 1 : 0; | ||
} catch (IOException e) { | ||
e.printStackTrace(); | ||
return 0; | ||
} | ||
} | ||
|
||
/** | ||
* Firebase Admin SDK의 비공개 키를 참조하여 Bearer 토큰을 발급 받습니다. | ||
* | ||
* @return Bearer token | ||
*/ | ||
private String getAccessToken() throws IOException { | ||
GoogleCredentials googleCredentials = GoogleCredentials | ||
.fromStream(new ClassPathResource(firebaseConfigPath).getInputStream()) | ||
.createScoped(List.of("<https://www.googleapis.com/auth/cloud-platform>")); | ||
|
||
googleCredentials.refreshIfExpired(); | ||
return googleCredentials.getAccessToken().getTokenValue(); | ||
} | ||
|
||
/** | ||
* FCM 전송 정보를 기반으로 메시지를 구성합니다. (Object -> String) | ||
* | ||
* @param fcmSendDto FcmSendDto | ||
* @return String | ||
*/ | ||
private String makeMessage(FcmSendDto fcmSendDto) throws JsonProcessingException { | ||
|
||
ObjectMapper om = new ObjectMapper(); | ||
FcmMessageDto fcmMessageDto = FcmMessageDto.builder() | ||
.message(FcmMessageDto.Message.builder() | ||
.token(fcmSendDto.getToken()) | ||
.notification(FcmMessageDto.Notification.builder() | ||
.title(fcmSendDto.getTitle()) | ||
.body(fcmSendDto.getBody()) | ||
.image(null) | ||
.build() | ||
).build()).validateOnly(false).build(); | ||
|
||
return om.writeValueAsString(fcmMessageDto); | ||
} | ||
} |
Oops, something went wrong.