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]: 기존 서버 Adapter 구현 및 AWS SNS Publisher 구축 #124

Merged
merged 14 commits into from
Nov 6, 2023
Merged
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ dependencies {

//AWS
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.0.0")
implementation 'io.awspring.cloud:spring-cloud-aws-starter-sns'

//swagger
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.gloddy.server.apply.domain.handler.ApplyQueryHandler;
import com.gloddy.server.apply.domain.service.*;
import com.gloddy.server.apply.domain.vo.Status;
import com.gloddy.server.apply.event.ApplyCreateEvent;
import com.gloddy.server.apply.event.producer.ApplyEventProducer;
import com.gloddy.server.auth.domain.User;
import com.gloddy.server.core.event.GroupParticipateEvent;
Expand All @@ -30,6 +31,7 @@ public class ApplyService {
private final GroupQueryHandler groupQueryHandler;
private final RejectedApplyCheckExecutor rejectedApplyCheckExecutor;
private final ApplyStatusUpdateExecutor applyStatusUpdateExecutor;
private final ApplyEventProducer applyEventProducer;

@Transactional
public ApplyResponse.Create createApply(Long userId, Long groupId, ApplyRequest.Create request) {
Expand All @@ -38,6 +40,7 @@ public ApplyResponse.Create createApply(Long userId, Long groupId, ApplyRequest.
Apply apply = applyCommandHandler.save(
group.createApply(user, request.getIntroduce(), request.getReason())
);
applyEventProducer.produceEvent(new ApplyCreateEvent(userId, groupId, apply.getId()));
return new ApplyResponse.Create(apply.getId());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import com.gloddy.server.apply.domain.Apply;
import com.gloddy.server.apply.domain.handler.ApplyQueryHandler;
import com.gloddy.server.apply.domain.vo.Status;
import com.gloddy.server.apply.event.ApplyStatusUpdateEvent;
import com.gloddy.server.apply.event.producer.ApplyEventProducer;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import static com.gloddy.server.apply.domain.vo.Status.*;

@Component
@RequiredArgsConstructor
public class ApplyStatusUpdateExecutor {
Expand All @@ -27,5 +30,7 @@ public void execute(Long userId, Long applyId, Status status) {
} else {
throw new RuntimeException("Apply Status Invalid");
}

applyEventProducer.produceEvent(new ApplyStatusUpdateEvent(userId, apply.getGroup().getId(), applyId, status));
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/gloddy/server/apply/event/ApplyCreateEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.gloddy.server.apply.event;

import com.gloddy.server.core.event.Event;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
public class ApplyCreateEvent implements Event {
private Long userId;
private Long groupId;
private Long applyId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.gloddy.server.apply.event;

import com.gloddy.server.apply.domain.vo.Status;
import com.gloddy.server.core.event.Event;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class ApplyStatusUpdateEvent implements Event {
private Long userId;
private Long groupId;
private Long applyId;
private Status status;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public void delete(Long userId, Long groupId) {
deleteGroupMemberVo(userId, groupId);
deleteGroupMember(userId, groupId);

groupMemberEventProducer.produceEvent(new GroupMemberLeaveEvent(userId));
groupMemberEventProducer.produceEvent(new GroupMemberLeaveEvent(userId, groupId));
}

private void deleteGroupMemberVo(Long userId, Long groupId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class GroupMemberLeaveEvent implements Event {
private Long userId;
private Long groupId;
}
4 changes: 4 additions & 0 deletions src/main/java/com/gloddy/server/messaging/AdapterEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.gloddy.server.messaging;

public interface AdapterEvent {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.gloddy.server.messaging;

import com.gloddy.server.messaging.adapter.apply.event.ApplyAdapterEvent;
import com.gloddy.server.messaging.adapter.group.event.GroupMemberAdapterEvent;

public interface MessagePublisher {
void publishApplyEvent(ApplyAdapterEvent event);
void publishGroupMemberEvent(GroupMemberAdapterEvent event);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.gloddy.server.messaging.adapter.apply.event;

import com.gloddy.server.messaging.AdapterEvent;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
public class ApplyAdapterEvent implements AdapterEvent {
private Long userId;
private Long groupId;
private Long applyId;
private ApplyEventType eventType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.gloddy.server.messaging.adapter.apply.event;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum ApplyEventType {
APPLY_CREATE("지원서가 생성 되었을 때"),
APPLY_APPROVE("지원서가 승인 처리 되었을 때"),
APPLY_REFUSE("지원서가 거절 처리 되었을 때");

private final String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.gloddy.server.messaging.adapter.apply.handler;

import com.gloddy.server.apply.event.ApplyCreateEvent;
import com.gloddy.server.apply.event.ApplyStatusUpdateEvent;
import com.gloddy.server.messaging.MessagePublisher;
import com.gloddy.server.messaging.adapter.apply.event.ApplyAdapterEvent;
import com.gloddy.server.messaging.adapter.apply.mapper.ApplyEventMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

@Component
@RequiredArgsConstructor
public class ApplyAdapterEventHandler {

private final MessagePublisher messagePublisher;

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(ApplyCreateEvent event) {
ApplyAdapterEvent adapterEvent = ApplyEventMapper.mapToApplyAdapterEventFrom(event);
messagePublisher.publishApplyEvent(adapterEvent);
}

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(ApplyStatusUpdateEvent event) {
ApplyAdapterEvent adapterEvent = ApplyEventMapper.mapToApplyAdapterEventFrom(event);
messagePublisher.publishApplyEvent(adapterEvent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.gloddy.server.messaging.adapter.apply.mapper;

import com.gloddy.server.apply.domain.vo.Status;
import com.gloddy.server.apply.event.ApplyCreateEvent;
import com.gloddy.server.apply.event.ApplyStatusUpdateEvent;
import com.gloddy.server.messaging.adapter.apply.event.ApplyAdapterEvent;
import com.gloddy.server.messaging.adapter.apply.event.ApplyEventType;

public class ApplyEventMapper {

public static ApplyAdapterEvent mapToApplyAdapterEventFrom(ApplyCreateEvent applyCreateEvent) {
return new ApplyAdapterEvent(
applyCreateEvent.getUserId(),
applyCreateEvent.getGroupId(),
applyCreateEvent.getApplyId(),
ApplyEventType.APPLY_CREATE
);
}

public static ApplyAdapterEvent mapToApplyAdapterEventFrom(ApplyStatusUpdateEvent applyStatusUpdateEvent) {
return new ApplyAdapterEvent(
applyStatusUpdateEvent.getUserId(),
applyStatusUpdateEvent.getGroupId(),
applyStatusUpdateEvent.getApplyId(),
getApplyEventType(applyStatusUpdateEvent.getStatus())
);
}

private static ApplyEventType getApplyEventType(Status status) {
if (status.isApprove()) {
return ApplyEventType.APPLY_APPROVE;
} else if (status.isRefuse()) {
return ApplyEventType.APPLY_REFUSE;
} else {
throw new RuntimeException("invalid apply status");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.gloddy.server.messaging.adapter.group.event;

import com.gloddy.server.messaging.AdapterEvent;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Getter
public class GroupMemberAdapterEvent implements AdapterEvent {
private Long userId;
private Long groupId;
private GroupMemberEventType eventType;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.gloddy.server.messaging.adapter.group.event;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum GroupMemberEventType {
GROUP_MEMBER_LEAVE("그룹 멤버가 모임을 나갔을 때");

private final String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.gloddy.server.messaging.adapter.group.handler;

import com.gloddy.server.group_member.event.GroupMemberLeaveEvent;
import com.gloddy.server.messaging.MessagePublisher;
import com.gloddy.server.messaging.adapter.group.event.GroupMemberAdapterEvent;
import com.gloddy.server.messaging.adapter.group.event.GroupMemberEventType;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

@Component
@RequiredArgsConstructor
public class GroupMemberAdapterEventHandler {
private final MessagePublisher messagePublisher;

@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void handle(GroupMemberLeaveEvent event) {
GroupMemberAdapterEvent adapterEvent = new GroupMemberAdapterEvent(
event.getUserId(),
event.getGroupId(),
GroupMemberEventType.GROUP_MEMBER_LEAVE);

messagePublisher.publishGroupMemberEvent(adapterEvent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.gloddy.server.messaging.sns.config;

import io.awspring.cloud.sns.core.TopicArnResolver;
import io.awspring.cloud.sns.core.TopicsListingTopicArnResolver;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.services.sns.SnsClient;

@Configuration
@EnableConfigurationProperties(SnsProperties.class)
public class SnsConfig {

@Bean
public TopicArnResolver topicArnResolver(SnsClient snsClient) {
return new TopicsListingTopicArnResolver(snsClient);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.gloddy.server.messaging.sns.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("spring.cloud.event")
@Getter
@Setter
public class SnsProperties {
private String applyTopic;
private String groupMemberTopic;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.gloddy.server.messaging.sns.publisher;

import com.gloddy.server.messaging.AdapterEvent;
import com.gloddy.server.messaging.MessagePublisher;
import com.gloddy.server.messaging.adapter.apply.event.ApplyAdapterEvent;
import com.gloddy.server.messaging.adapter.group.event.GroupMemberAdapterEvent;
import com.gloddy.server.messaging.sns.config.SnsProperties;
import io.awspring.cloud.sns.core.SnsTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RequiredArgsConstructor
public class SnsPublisher implements MessagePublisher {

private final SnsProperties snsProperties;
private final SnsTemplate snsTemplate;

@Override
public void publishApplyEvent(ApplyAdapterEvent event) {
send(snsProperties.getApplyTopic(), event, null);
}

@Override
public void publishGroupMemberEvent(GroupMemberAdapterEvent event) {
send(snsProperties.getGroupMemberTopic(), event, null);
}

private void send(String topicName, AdapterEvent event, @Nullable String subject) {
log.info("이벤트 발행 시작(AWS SNS)");
try {
snsTemplate.sendNotification(topicName, event, subject);
} catch (Exception e) {
log.error(e.getMessage());
}
log.info("이벤트 발행 완료(AWS SNS)");
}
}
12 changes: 11 additions & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,17 @@ spring:
max-file-size: ${MAX_FILE_SIZE}
max-request-size: ${MAX_REQUEST_SIZE}

cloud:
aws:
credentials:
access-key: ${AWS_ACCESS_KEY}
secret-key: ${AWS_SECRET_KEY}
region:
static: ap-northeast-2
event:
apply-topic: ${APPLY_TOPIC}
group-member-topic: ${GROUP_MEMBER_TOPIC}

logging:
level:
com.gloddy.server.authSms.infra: debug
Expand Down Expand Up @@ -79,4 +90,3 @@ springdoc:
swagger-ui:
url: /v3/api-docs
urls-primary-name: Gloddy

11 changes: 11 additions & 0 deletions src/test/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ spring:
pathmatch:
matching-strategy: ant_path_matcher

cloud:
aws:
credentials:
access-key: dummy-key
secret-key: dummy-key
region:
static: ap-northeast-2
event:
apply-topic: dummy-apply-topic
group-member-topic: dummy-group-member-topic

jwt:
header: X-AUTH-TOKEN
secret: testJwtSecret-testJwtSecret-testJwtSecret-testJwtSecret-testJwtSecret-testJwtSecret
Expand Down
Loading