Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 푸시 알림 기능 추가 #116

Merged
merged 2 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ dependencies {
implementation 'software.amazon.ion:ion-java:1.0.3'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'

// firebase
implementation 'com.google.firebase:firebase-admin:9.2.0'
implementation 'com.fasterxml.jackson.core:jackson-core:2.16.1'

implementation 'org.springframework.boot:spring-boot-starter-webflux'
if (isAppleSilicon()) {
runtimeOnly("io.netty:netty-resolver-dns-native-macos:4.1.94.Final:osx-aarch_64")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@


import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -21,10 +20,14 @@ public class SigninRequestDto {
@NotBlank(message = "password is required")
private String password;

@NotBlank(message = "pushToken is required")
private String pushToken;

public SigninServiceDto toServiceDto() {
return SigninServiceDto.builder()
.username(getEmail())
.password(getPassword())
.pushToken(getPushToken())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ public record SignupRequestDto(
LocalDate birth,
String nationality,
List<String> languages,
List<ProfileImageRequestDto> profileImages

List<ProfileImageRequestDto> profileImages,
String pushToken
){}
23 changes: 17 additions & 6 deletions src/main/java/meltingpot/server/auth/service/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import meltingpot.server.auth.controller.dto.ReissueTokenRequestDto;
import meltingpot.server.auth.controller.dto.ReissueTokenResponseDto;
import meltingpot.server.auth.controller.dto.SignupRequestDto;
import meltingpot.server.domain.entity.AccountLanguage;
import meltingpot.server.domain.entity.AccountProfileImage;
import meltingpot.server.domain.entity.*;
import meltingpot.server.domain.entity.enums.Gender;
import meltingpot.server.domain.repository.AccountPushTokenRepository;
import meltingpot.server.domain.repository.MailVerificationRepository;
import meltingpot.server.exception.*;
import meltingpot.server.config.TokenProvider;
import meltingpot.server.domain.entity.RefreshToken;
import meltingpot.server.domain.entity.Account;
import meltingpot.server.domain.repository.RefreshTokenRepository;
import meltingpot.server.domain.repository.AccountRepository;
import meltingpot.server.auth.controller.dto.AccountResponseDto;
Expand All @@ -21,6 +18,7 @@
import meltingpot.server.util.ResponseCode;
import meltingpot.server.util.SecurityUtil;
import meltingpot.server.util.TokenDto;
import meltingpot.server.util.push.PushService;
import meltingpot.server.util.r2.FileService;
import meltingpot.server.util.r2.FileUploadResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
Expand All @@ -46,7 +44,9 @@ public class AuthService implements UserDetailsService {
private final RefreshTokenRepository refreshTokenRepository;
private final PasswordEncoder passwordEncoder;
private final FileService fileService;
private final MailVerificationRepository mailVerificationRepository;
private final AccountPushTokenRepository accountPushTokenRepository;

private final PushService pushService;

// 회원가입
@Transactional
Expand Down Expand Up @@ -94,6 +94,7 @@ public AccountResponseDto signup(SignupRequestDto signupRequest) {
return signin(SigninServiceDto.builder()
.username(account.getUsername())
.password(signupRequest.password())
.pushToken(signupRequest.pushToken())
.build());

}
Expand Down Expand Up @@ -124,6 +125,16 @@ public AccountResponseDto signin(SigninServiceDto serviceDto){

refreshTokenRepository.save(refreshToken);


if (!accountPushTokenRepository.existsAccountPushByAccountAndToken(account, serviceDto.getPushToken())) {
AccountPushToken accountPushToken = AccountPushToken.builder()
.account(account)
.token(serviceDto.getPushToken())
.build();

accountPushTokenRepository.save(accountPushToken);
}

//인증된 Authentication를 SecurityContext에 저장
SecurityContextHolder.getContext().setAuthentication(authentication);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class SigninServiceDto {
private final String username;
private final String password;

private final String pushToken;

// 미인증 토큰 생성
public UsernamePasswordAuthenticationToken toAuthentication() {
return new UsernamePasswordAuthenticationToken(getUsername(), getPassword());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package meltingpot.server.domain.entity;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.*;
import meltingpot.server.domain.entity.common.BaseEntity;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@DynamicInsert
@DynamicUpdate
@Entity
public class AccountPushToken extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private long id;

@NotNull
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "account_id")
private Account account;

@NotNull
@Column
private String token;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package meltingpot.server.domain.repository;

import meltingpot.server.domain.entity.Account;
import meltingpot.server.domain.entity.AccountPushToken;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

public interface AccountPushTokenRepository extends JpaRepository<AccountPushToken, Long> {
List<AccountPushToken> findAllByAccount(Account account);
Boolean existsAccountPushByAccountAndToken(Account account, String token);
}
32 changes: 32 additions & 0 deletions src/main/java/meltingpot/server/util/push/PushConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package meltingpot.server.util.push;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.FileInputStream;

@Configuration
public class PushConfig {
@Value("${cloud.firebase.config}")
private String firebaseConfig;

@Bean
public FirebaseApp firebaseApp() {
try {
FileInputStream serviceAccount =
new FileInputStream(firebaseConfig);

FirebaseOptions options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();

return FirebaseApp.initializeApp(options);
} catch (Exception e) {
return null;
}
}
}
42 changes: 42 additions & 0 deletions src/main/java/meltingpot/server/util/push/PushService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package meltingpot.server.util.push;

import com.google.firebase.FirebaseApp;
import com.google.firebase.messaging.FirebaseMessaging;
import com.google.firebase.messaging.Message;
import lombok.RequiredArgsConstructor;
import meltingpot.server.domain.entity.Account;
import meltingpot.server.domain.entity.AccountPushToken;
import meltingpot.server.domain.repository.AccountPushTokenRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@RequiredArgsConstructor
public class PushService {
private final AccountPushTokenRepository accountPushTokenRepository;
private final FirebaseApp firebaseApp;

private final Logger logger = LoggerFactory.getLogger(this.getClass());

public void sendPush(Account account, String title, String body) {
List<AccountPushToken> tokens = accountPushTokenRepository.findAllByAccount(account);

FirebaseMessaging messaging = FirebaseMessaging.getInstance(firebaseApp);
for (AccountPushToken token : tokens) {
Message message = Message.builder()
.setToken(token.getToken())
.putData("title", title)
.putData("body", body)
.build();

try {
messaging.send(message);
} catch (Exception e) {
logger.error(e.getMessage());
}
}
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ cloud:
credentials:
accessKey: ${AWS_ACCESS_KEY}
secretKey: ${AWS_SECRET_KEY}
firebase:
config: ${FIREBASE_CONFIG}