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

티켓 오픈 홍보 알림 테스트 코드 #3

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
21 changes: 20 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,30 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'

implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.9.0'

//lombok
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

//test
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.springdoc:springdoc-openapi-starter-webmvc-ui:2.6.0'

//mysql
runtimeOnly 'com.mysql:mysql-connector-j'

//kafka
implementation 'org.springframework.kafka:spring-kafka'

//Mail
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
}

tasks.named('test') {
Expand Down
21 changes: 21 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:

zookeeper:
image: wurstmeister/zookeeper:latest
ports:
- "2181:2181"

kafka:
image: wurstmeister/kafka:latest
ports:
- "9092:9092"
expose:
- "9093"
environment:
KAFKA_LISTENERS: INSIDE://0.0.0.0:9093,OUTSIDE://0.0.0.0:9092
KAFKA_ADVERTISED_LISTENERS: INSIDE://kafka:9093,OUTSIDE://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
volumes:
- /var/run/docker.sock:/var/run/docker.sock
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories("com.server.kubacknotification.infra.jpa.repositoryImpl")
public class KubackNotificationApplication {

public static void main(String[] args) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.server.kubacknotification.api;

import com.server.kubacknotification.application.dto.request.TicketOpenMessage;
import com.server.kubacknotification.application.service.NotificationService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RequiredArgsConstructor
@RestController
public class NotificationController {
private final NotificationService notificationService;

@PostMapping("/api/notifications")
public void createTicketOpenNotifications(@RequestBody TicketOpenMessage ticketOpenMessage) {
notificationService.createTicketOpenNotification(ticketOpenMessage);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.server.kubacknotification.application.dto.request;

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

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class TicketOpenMessage {
private String title; // 공연 제목
private String description; // 공연 설명
private String email;
private Long userId;
private String userName;
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.server.kubacknotification.application.service;

import com.server.kubacknotification.application.dto.request.TicketOpenMessage;
import com.server.kubacknotification.global.common.PaymentMessage;
import jakarta.mail.internet.MimeMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring6.SpringTemplateEngine;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class EmailService {

private final JavaMailSender javaMailSender;
private final SpringTemplateEngine templateEngine;

// Kafka로부터 PaymentMessage를 수신하고 이메일 발송
@KafkaListener(topics = "ticketOpen", groupId = "group2", containerFactory = "ticketOpenMessageKafkaListenerContainerFactory")
public void consumeNoticeMessage(TicketOpenMessage ticketOpenMessage) {
sendTicketOpenEmail(ticketOpenMessage);
}

@Async
public void sendTicketOpenEmail(TicketOpenMessage ticketOpenMessage) {
MimeMessage mimeMessage = javaMailSender.createMimeMessage();
try {
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
mimeMessageHelper.setTo(ticketOpenMessage.getEmail()); // 수신자 이메일을 TicketOpenMessage 의 email 필드로 설정
mimeMessageHelper.setSubject("티켓 오픈 안내"); // 이메일 제목

// HTML 콘텐츠 생성
String htmlContent = setTicketOpenContext(ticketOpenMessage);
mimeMessageHelper.setText(htmlContent, true); // HTML 여부 true 설정

javaMailSender.send(mimeMessage);
log.info("Succeeded to send Email to: {}", ticketOpenMessage.getUserId());
} catch (Exception e) {
log.error("Failed to send Email to: {}", ticketOpenMessage.getUserId(), e);
throw new RuntimeException(e);
}
}

// HTML 템플릿에 TicketOpenMessage 데이터 주입
public String setTicketOpenContext(TicketOpenMessage ticketOpenMessage) {
Context context = new Context();
context.setVariable("ticketOpenMessage", ticketOpenMessage);
return templateEngine.process("ticketOpen", context); // "ticketOpen.html" 템플릿 사용
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.server.kubacknotification.application.service;

import com.server.kubacknotification.application.dto.request.TicketOpenMessage;
import lombok.RequiredArgsConstructor;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@RequiredArgsConstructor
@Service
public class NotificationService {
private final KafkaTemplate<String, TicketOpenMessage> kafkaTemplate;
private static final String TOPIC = "ticketOpen";

public void createTicketOpenNotification(TicketOpenMessage ticketOpenMessage) {
kafkaTemplate.send(TOPIC, ticketOpenMessage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
@Getter
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class A {
public class Notification {
private Long id;
private String name;
private Long userId;
private String title;
private String content;

public static A toDomain(
public static Notification toDomain(
Long id,
String name) {
return new A(id, name);
Long userId,
String title,
String content) {
return new Notification(id, userId, title, content);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.server.kubacknotification.domain.repository;

import com.server.kubacknotification.domain.entity.Notification;
import org.springframework.stereotype.Repository;

@Repository
public interface NotificationRepository {
Notification findById(Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.server.kubacknotification.global.common;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "결제 메시지")
public class PaymentMessage {

@Schema(description = "유저 ID", example = "1")
private Long userId;

@Schema(description = "유저 이메일", example = "@gmail.com")
private String email;

@Schema(description = "유저 이름", example = "문희상")
private String userName;

@Schema(description = "좌석 번호", example = "A12")
private String seatNumber;

@Schema(description = "좌석 등급", example = "VIP")
private String seatGrade;

@Schema(description = "결제 금액", example = "15000")
private String payment;

@Schema(description = "결제 날짜", example = "2024-10-06T14:00:00")
private LocalDateTime payDate;

@Schema(description = "원래 가격", example = "20000")
private String originalPrice;

@Schema(description = "할인 금액", example = "5000")
private String salePrice;

@Schema(description = "최종 결제 금액", example = "15000")
private String finalPrice;
}



Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.server.kubacknotification.global.config;

import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

import java.util.Properties;

@Configuration
@RequiredArgsConstructor
public class EmailConfig {

private static final String MAIL_SMTP_AUTH = "mail.smtp.auth";
private static final String MAIL_DEBUG = "mail.smtp.debug";
private static final String MAIL_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout";
private static final String MAIL_SMTP_STARTTLS_ENABLE = "mail.smtp.starttls.enable";

// SMTP 서버
@Value("${spring.mail.host}")
private String host;

// 계정
@Value("${spring.mail.username}")
private String username;

// 비밀번호
@Value("${spring.mail.password}")
private String password;

// 포트번호
@Value("${spring.mail.port}")
private int port;

@Value("${spring.mail.properties.mail.smtp.auth}")
private boolean auth;

@Value("${spring.mail.properties.mail.smtp.debug}")
private boolean debug;

@Value("${spring.mail.properties.mail.smtp.connectiontimeout}")
private int connectionTimeout;

@Value("${spring.mail.properties.mail.starttls.enable}")
private boolean startTlsEnable;

@Bean
public JavaMailSender javaMailService() {
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
javaMailSender.setHost(host);
javaMailSender.setUsername(username);
javaMailSender.setPassword(password);
javaMailSender.setPort(port);

Properties properties = javaMailSender.getJavaMailProperties();
properties.put(MAIL_SMTP_AUTH, auth);
properties.put(MAIL_DEBUG, debug);
properties.put(MAIL_CONNECTION_TIMEOUT, connectionTimeout);
properties.put(MAIL_SMTP_STARTTLS_ENABLE, startTlsEnable);

javaMailSender.setJavaMailProperties(properties);
javaMailSender.setDefaultEncoding("UTF-8");

return javaMailSender;
}

}
Loading