Skip to content

Commit

Permalink
Merge pull request #67 from 28th-meetup/feat/sendFcm
Browse files Browse the repository at this point in the history
Feat/send fcm
  • Loading branch information
summit45 authored Nov 21, 2023
2 parents 1c474d3 + 5e26df7 commit b1ff60b
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 3 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ dependencies {
implementation group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1'
implementation 'org.json:json:20210307'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
//firebase
implementation 'com.google.firebase:firebase-admin:9.1.1'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kusitms.jipbap.notifiication;
package com.kusitms.jipbap.notification;

import static com.querydsl.core.types.PathMetadataFactory.*;

Expand Down
41 changes: 41 additions & 0 deletions src/main/java/com/kusitms/jipbap/config/FCMConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.kusitms.jipbap.config;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.messaging.FirebaseMessaging;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Configuration
public class FCMConfig {
@Bean
FirebaseMessaging firebaseMessaging() throws IOException {
ClassPathResource resource = new ClassPathResource("firebase/meetup-2e72d-firebase-adminsdk-r4n9k-ea28a00578.json");
InputStream serviceAccount = resource.getInputStream();

FirebaseApp firebaseApp = null;
List<FirebaseApp> firebaseAppList = FirebaseApp.getApps();

if(firebaseAppList != null && !firebaseAppList.isEmpty()) {
for (FirebaseApp app : firebaseAppList) {
if (app.getName().equals(FirebaseApp.DEFAULT_APP_NAME)) {
firebaseApp = app;
}
}
} else {
FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();

firebaseApp = FirebaseApp.initializeApp(options);
}
return FirebaseMessaging.getInstance(firebaseApp);
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/kusitms/jipbap/notification/FCMController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.kusitms.jipbap.notification;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
@RequiredArgsConstructor
public class FCMController {

private final FCMNotificationService fcmNotificationService;

@PostMapping("/send/message")
public String sendNotificationByToken (@RequestBody FCMRequestDto dto) {
String answer = fcmNotificationService.sendNotificationByToken(dto);
return answer;
}

@PostMapping("/valid/fcm")
public String isValidFcmToken(@RequestBody FCMValidRequestDto dto) {
Boolean ans = fcmNotificationService.isValidToken(dto.getFcmToken());
if(ans) return "True";
else return "False";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.kusitms.jipbap.notification;

import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseAuthException;
import com.google.firebase.auth.FirebaseToken;
import com.google.firebase.messaging.Notification;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.FirebaseMessagingException;
import com.google.firebase.messaging.Message;
import com.kusitms.jipbap.user.User;
import com.kusitms.jipbap.user.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.ExecutionException;

@Slf4j
@Service
@RequiredArgsConstructor
public class FCMNotificationService {
private static final String API_URI = "https://fcm.googleapis.com/v1/projects/jinminboard/messages:send";

private final FirebaseMessaging firebaseMessaging;
private final UserRepository userRepository;

public String sendNotificationByToken(FCMRequestDto dto) {
Optional <User> user = userRepository.findById(dto.getUserId());

if (user.isPresent()){
log.info("fcm토큰" + user.get().getFcmToken());
if (user.get().getFcmToken() != null) {

Message message = Message.builder()
.setToken(user.get().getFcmToken())
.setNotification(Notification.builder()
.setTitle(dto.getTitle())
.setBody(dto.getBody())
.build())
.build();
try {
firebaseMessaging.send(message);
System.out.println("알림을 성공적으로 전송했습니다. targetUserId=" + user.get().getId());
return "알림을 성공적으로 전송했습니다. targetUserId=" + user.get().getId();
} catch (FirebaseMessagingException e) {
e.printStackTrace();;
return "알림 보내기를 실패했습니다. targetUserId=" + user.get().getId();
}
}
else{
return "서버에 저장된 해장 유저의 FirebaseToken이 존재하지 않습니다. targetUserId=" + user.get().getId();
}
}
else{
return "해당 유저가 존재하지 않습니다. targetUserId=" + user.get().getId();
}

//비동기
//String asyncMessage = firebaseMessaging.sendAsync(message).get();
//return asyncMessage;
}

public boolean isValidToken(String fcmToken) {
try {
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdToken(fcmToken);
String uid = decodedToken.getUid();
// 토큰이 검증되면 true를 반환합니다.
return true;
} catch (FirebaseAuthException e) {
// 토큰이 유효하지 않으면 false를 반환합니다.
System.out.println(e.getMessage());
return false;
}
}
//`targetToken`에 해당하는 기기로 푸시 알림 전송 요청
// (targetToken 은 프론트 사이드에서 얻기!)

/*
public void sendMessageTo(String targetToken, String title, String body) throws FirebaseMessagingException, IOException, ExecutionException, InterruptedException {
//Request + Response 사용
//RequestBody requestBody = getRequestBody(makeFcmMessage(targetToken, title, body));
//Request request = getRequest(requestBody);
//Response response = getResponse(request);
//log.info(response.body().string());
//FirebaseMessaging 사용
Message message = makeMessage(targetToken, title, body);
String response = FirebaseMessaging.getInstance().send(message);
log.info(response);
//비동기
String asyncMessage = FirebaseMessaging.getInstance().sendAsync(message).get();
}
private Response getResponse(Request request) throws IOException {
return client.newCall(request).execute();
}
private Request getRequest(RequestBody requestBody) {
return new Request.Builder()
.url(API_URI)
.post(requestBody)
.addHeader(HttpHeaders.AUTHORIZATION, "Bearer " + googleCredentials.getAccessToken().getTokenValue())
.addHeader(HttpHeaders.CONTENT_TYPE, "application/json; UTF-8")
.build();
}
private RequestBody getRequestBody(String message) {
return RequestBody.create(message, MediaType.get("application/json; charset=utf-8"));
}
private String makeFcmMessage(String targetToken, String title, String body) throws JsonProcessingException {
FCMMessage fcmMessage = FCMMessage.builder()
.message(Message.builder()
.setToken(targetToken)
.setNotification(new FCMNotification(title, body))
.build())
.validateOnly(false)
.build();
//log.info("message 변환(Object -> String) \n" + objectMapper.writeValueAsString(fcmMessage));
return objectMapper.writeValueAsString(fcmMessage);
}
private Message makeMessage(String targetToken, String title, String body) {
FCMMessage fcmMessage = FcmMessage.builder()
.message(Message.builder()
.setToken(targetToken)
.setNotification(new FCMNotification(title, body))
.build())
.validateOnly(false)
.build();
return fcmMessage.getMessage();
}
*/
}
16 changes: 16 additions & 0 deletions src/main/java/com/kusitms/jipbap/notification/FCMRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.kusitms.jipbap.notification;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class FCMRequestDto {
Long userId;
String title;
String body;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kusitms.jipbap.notification;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class FCMValidRequestDto {
String fcmToken;
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.kusitms.jipbap.notifiication;
package com.kusitms.jipbap.notification;

import com.kusitms.jipbap.common.entity.DateEntity;
import com.kusitms.jipbap.user.User;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ private void setUserData(User user, GlobalRegion globalRegion, UserAddressReques
user.setAddress(dto.getAddress());
user.setDetailAddress(dto.getDetailAddress());
user.setPostalCode(dto.getPostalCode());
user.setFcmToken(dto.getFcmToken());
}

private PostalAddressDto findPostalAddress(GeocodingAddressDto geocodingAddressDto) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/kusitms/jipbap/user/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public interface UserRepository extends JpaRepository<User, Long> {
boolean existsByEmail(String email);
boolean existsByUsername(String username);
Optional<User> findByEmail(String email);

Optional<User> findByUsername(String username);
//Optional<User> findByFCMToken(String FCMToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public class UserAddressRequest {
String address;
String detailAddress;
String postalCode;
String fcmToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"type": "service_account",
"project_id": "meetup-2e72d",
"private_key_id": "ea28a00578e042f8280d71f624e3f62fb6068a7e",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDDwSke1GBvgPAE\nkkq0HS7x5VYWr64yXhBtrystAOyYgQrDpOxV8eBZjhHA2LeNnwWyaI/B9H33a4lU\nPOvW5kBy+/ke/jl45nu5JS94FcPB075j3NThwaH94wGFP2E+wNdoYCaCyWcpCWH9\nJl+SGQm8N0urfWGxJz8UGG29Cvn+c0Z8/jAxujXdNSLqZUqxJFzMsxRtS7aSwz2+\nMyyq9/4uaIVpoBij57BEpYDVGzBvpJNyz8psIWvzFtS575yj8AW4i6B3vEw2saK1\nY/PGfsfl83XEcMoWVSjtM3AwYIdCvtAFGEXv7O/PC1vAKY2dq0xBjLTCIkwHcxvK\nn7nQjvsLAgMBAAECggEAWXgT9MDJkL0ENnqshRTfi3Svu6+w9NlUNeV9XNTSzkMQ\naeobkI575UKPL659ek+HuYqbxeCaoDZ4rlUnz3EuXL94ladJGk5xluX9g6ui7Jh8\nKMVaURKAmPsji0S0DAv0iAKGJ3mo2jMtI5hhzvL9pZY6Uhd8yoyvAl7F7USyjQ5S\nxT0DNbaHuj+C0HtCicw725AwSHmiSwKG+uzHpAL3UuKxzYVnMERVgsXribiZoyBK\nq8wHfP2qMo+gRKSoZQNLx8IWO6zpPmpZVUeMNiTRG01iP5qQBI6QCdRZGLRTRcb8\nh6027O2cVXE3HMWQIMMSrE8htGeXKMOChhnjsx1bgQKBgQDu5ITNpvH7asNQXrmI\nv/94P5x1SocBXH5Q87JL//Kb54YFEwZ8Zo5yQDARor2OeXBbNai6j6rpnNJFEwbc\nu2ZB7a4I5vzy179W3CpIaeNhovU0l4cH1CcHlRvwE5J0/BMs6MaTbIF5J9QVBjqO\nD+tTbzbzBEP5kLQmuVQSZjuMgQKBgQDRxdDMv6C8LW//SXkGYNMAnH0pGPu3M72x\nSBbEWLH3Zh47VNMqW/me6LnFKUvxRI4sltE8GR3gDXYEc5eEsjkWPI/YCMhvT7p+\nWEv+Srbq1LmsEDg3I/nUIYXZqcOu53JO7xfCWVTzFjBGsk3kTNdWv+J0a6KPQt3i\niaHSgdUxiwKBgFpP+gTlQEYULpKLvQh9zU7gfX26Fx/kn7xq5NTmhgl6lagFcUZG\nX0PCEGoaZB8gueFBf/BHsA1xQ+zpLIb2Mcpq2Ih1CtujxKpJwZJutY+L07d2MY48\nHiU3scApJg0j3vvzZF8HfksXS45HNIvQaN66BMQKsMgAdJrPJYFvNMQBAoGAFKrx\nxIqI0qGDbFqX0voNL/07E6aDfmxZnzLkE1pNxntINT5JQ94l/PMfAn7sHYxMmbYO\nTWaIHAAXhZ7B6fAJUdiLr5RF8zmevT4D1r0TwpVM6df7QeuIfM8EugpQ3lWtXHuQ\nErTserrP7Nc6d2jeuoxTSnckYAsNg3ld+TiTgbsCgYEAo/cgHjBbmUiDQCzfMP25\no55GXVFyvtzMCBIGbYY2VVqY9VsUBGomkxei+g5UORGeiiZo6mnapIxxY9YBbmYh\nGpbVufUT2Uy/5Yj6Dq93Z0o3Wk298EcG9gf6fq2n8LoAjUmauOKI4/hCk65t5dq3\np1dCqEcs9M913r76MtPZMuo=\n-----END PRIVATE KEY-----\n",
"client_email": "[email protected]",
"client_id": "112504503118202778985",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-r4n9k%40meetup-2e72d.iam.gserviceaccount.com",
"universe_domain": "googleapis.com"
}

0 comments on commit b1ff60b

Please sign in to comment.