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] 알림 관련 기능 구현 #82

Merged
merged 10 commits into from
Nov 29, 2024
Merged
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/.idea/
/notification/src/main/resources/firebase-adminsdk.json
/notification/src/main/resources/application.yml
2 changes: 2 additions & 0 deletions notification/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,5 @@ out/
.vscode/
/src/main/resources/application-prod.yml
/src/main/resources/application-local.yml
/src/main/resources/firebase-adminsdk.json
/src/main/resources/application.yml
45 changes: 26 additions & 19 deletions notification/build.gradle
Original file line number Diff line number Diff line change
@@ -1,39 +1,46 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.4'
id 'io.spring.dependency-management' version '1.1.6'
id 'java'
id 'org.springframework.boot' version '3.3.4'
id 'io.spring.dependency-management' version '1.1.6'
}

group = 'org.bookwoori'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
compileOnly {
extendsFrom annotationProcessor
}
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'

implementation 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'com.google.firebase:firebase-admin:7.1.1'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

tasks.named('test') {
useJUnitPlatform()
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.bookwoori.notification.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {

@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(30);
executor.setQueueCapacity(50);
executor.setThreadNamePrefix("NOTIFICATION-SERVER-SYNC-");
executor.initialize();
return executor;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.bookwoori.notification.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.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.util.Arrays;

@Configuration
public class FcmConfig {

@Value("${fcm.firebase-create-scoped}")
private String fireBaseCreateScoped;

@Value("${fcm.key}")
private String key;

@Bean
public FirebaseMessaging init() throws IOException {
GoogleCredentials googleCredentials = GoogleCredentials.fromStream(new ClassPathResource(key).getInputStream())
.createScoped((Arrays.asList(fireBaseCreateScoped)));

FirebaseOptions secondaryAppConfig = FirebaseOptions.builder()
.setCredentials(googleCredentials)
.build();
FirebaseApp app = FirebaseApp.initializeApp(secondaryAppConfig);
return FirebaseMessaging.getInstance(app);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.bookwoori.notification.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;

@Configuration
public class MongoConfig {

@Value("${spring.data.mongodb.uri}")
private String connection;

@Bean
public MongoDatabaseFactory mongoDatabaseFactory() {
return new SimpleMongoClientDatabaseFactory(connection);
}

@Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoDatabaseFactory());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.bookwoori.notification.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
@EnableRedisRepositories
public class RedisConfig {

@Value("${spring.data.redis.host}")
private String host;

@Value("${spring.data.redis.port}")
private int port;

minseoooooo marked this conversation as resolved.
Show resolved Hide resolved
@Value("${spring.data.redis.password}")
private String password;

@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
config.setPassword(password);
return new LettuceConnectionFactory(config);
}

@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.bookwoori.notification.controller;


import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bookwoori.notification.dto.request.RegisterRequestDto;
import org.bookwoori.notification.dto.response.CommonResponseDto;
import org.bookwoori.notification.dto.response.DataResponseDto;
import org.bookwoori.notification.dto.response.DeviceResponseDto;
import org.bookwoori.notification.service.DeviceService;
import org.bookwoori.notification.service.ResponseService;
import org.springframework.web.bind.annotation.*;


@Slf4j
@RestController
@Tag(name = "Notification(Device)")
@RequestMapping("/notification/devices")
@RequiredArgsConstructor
public class DeviceController {

private final ResponseService responseService;
private final DeviceService deviceService;

@Operation(summary = "등록 정보 조회", description = "등록 정보를 조회합니다.")
@GetMapping("/{id}")
public DataResponseDto<Object> getDevice(@PathVariable("id") Long userId) {
DeviceResponseDto response = deviceService.getDevice(userId);
return responseService.getDataResponse(response);
}

@Operation(summary = "기기 등록", description = "기기를 등록합니다.")
@PostMapping
public CommonResponseDto register(@Valid @RequestBody RegisterRequestDto request) {
deviceService.register(request);
return responseService.getSuccessResponse();
}

@Operation(summary = "기기 삭제", description = "기기를 삭제합니다.")
@DeleteMapping({"/{id}"})
public CommonResponseDto delete(@PathVariable("id") Long userId) {
deviceService.delete(userId);
return responseService.getSuccessResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.bookwoori.notification.controller;


import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bookwoori.notification.dto.request.ChannelMessageRequestDto;
import org.bookwoori.notification.dto.request.ChatMessageRequestDto;
import org.bookwoori.notification.dto.request.DirectMessageRequestDto;
import org.bookwoori.notification.dto.request.EmojiMessageRequestDto;
import org.bookwoori.notification.dto.response.CommonResponseDto;
import org.bookwoori.notification.service.NotificationService;
import org.bookwoori.notification.service.ResponseService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@Slf4j
@RestController
@Tag(name = "Notification")
@RequestMapping("/notification-server")
@RequiredArgsConstructor
public class NotificationController {

private final ResponseService responseService;
private final NotificationService notificationService;

@Operation(summary = "DM 알림", description = "DM 알림을 보냅니다.")
@PostMapping("/direct")
public CommonResponseDto sendDirectMessage(@Valid @RequestBody DirectMessageRequestDto request) {
try {
notificationService.send(request);
} catch (Exception e) {
e.printStackTrace();
}
return responseService.getSuccessResponse();
}

@Operation(summary = "채널 생성 알림", description = "채널 생성 알림을 보냅니다.")
@PostMapping("/channel")
public CommonResponseDto sendChannelMessage(@Valid @RequestBody ChannelMessageRequestDto request) {
try {
notificationService.send(request);
} catch (Exception e) {
e.printStackTrace();
}
return responseService.getSuccessResponse();
}

@Operation(summary = "감상평 이모지 알림", description = "감상평 이모지 알림을 보냅니다.")
@PostMapping("/emoji")
public CommonResponseDto sendEmojiMessage(@Valid @RequestBody EmojiMessageRequestDto request) {
try {
notificationService.send(request);
} catch (Exception e) {
e.printStackTrace();
}
return responseService.getSuccessResponse();
}

@Operation(summary = "채팅 채널 알림", description = "채팅 채널에 달린 채팅에 대한 알림을 보냅니다.")
@PostMapping("/chat")
public CommonResponseDto sendChatMessage(@Valid @RequestBody ChatMessageRequestDto request) {
try {
notificationService.send(request);
} catch (Exception e) {
e.printStackTrace();
}
return responseService.getSuccessResponse();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.bookwoori.notification.domain;

import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;
}
Loading