-
Notifications
You must be signed in to change notification settings - Fork 27
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
Feature/nyh365 step3 #31
base: base/nyh365
Are you sure you want to change the base?
Changes from all commits
15352e9
e9a9162
4f37766
98b35b0
940eaec
31752c4
8b168a8
0bb7b18
b39c88e
ae4b0bf
d8797fc
0478f01
245990d
37a4adc
1a6e47b
def1910
bb9f31c
49edc05
9029292
a39e1d5
53560c5
cca982f
6a14bdc
b0e4b4d
be1fb48
a980471
4987099
87eb9c6
18de610
0b47496
2d85cde
7915c2c
aeed0bb
965c0b2
7aee74a
a0229d2
7dcf5b4
01e9522
c704a69
8e88df9
53eaf2c
c4e4638
0bcf0f1
83d0b55
14eb44e
a0ea42f
b8eaa19
e748dd4
babdff7
2c5b703
a15b04d
6c26829
9db7511
532c732
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package org.c4marathon.assignment.config; | ||
|
||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.scheduling.annotation.EnableAsync; | ||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
|
||
@Configuration | ||
@EnableAsync | ||
public class AsyncConfig { | ||
public static final String ASYNC_LISTENER_TASK_EXECUTOR_NAME = "AsyncListenerTaskExecutor"; | ||
public static final String ASYNC_SCHEDULER_TASK_EXECUTOR_NAME = "AsyncSchedulerTaskExecutor"; | ||
private static final int CORE_POOL_SIZE = 2; | ||
private static final int MAX_POOL_SIZE = 4; | ||
|
||
@Bean(name = ASYNC_LISTENER_TASK_EXECUTOR_NAME) | ||
public ThreadPoolTaskExecutor asyncListenerTaskExecutor() { | ||
return getThreadPoolTaskExecutor(ASYNC_LISTENER_TASK_EXECUTOR_NAME); | ||
} | ||
|
||
@Bean(name = ASYNC_SCHEDULER_TASK_EXECUTOR_NAME) | ||
public ThreadPoolTaskExecutor asyncSchedulerTaskExecutor() { | ||
return getThreadPoolTaskExecutor(ASYNC_SCHEDULER_TASK_EXECUTOR_NAME); | ||
} | ||
|
||
private ThreadPoolTaskExecutor getThreadPoolTaskExecutor(String asyncSchedulerTaskExecutorName) { | ||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); | ||
executor.setCorePoolSize(CORE_POOL_SIZE); | ||
executor.setMaxPoolSize(MAX_POOL_SIZE); | ||
executor.setThreadNamePrefix(asyncSchedulerTaskExecutorName); | ||
executor.setWaitForTasksToCompleteOnShutdown(true); | ||
executor.setAwaitTerminationSeconds(10); | ||
executor.initialize(); | ||
return executor; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package org.c4marathon.assignment.config; | ||
|
||
import org.springframework.amqp.core.Binding; | ||
import org.springframework.amqp.core.BindingBuilder; | ||
import org.springframework.amqp.core.DirectExchange; | ||
import org.springframework.amqp.core.Queue; | ||
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory; | ||
import org.springframework.amqp.rabbit.connection.ConnectionFactory; | ||
import org.springframework.amqp.rabbit.core.RabbitTemplate; | ||
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter; | ||
import org.springframework.amqp.support.converter.MessageConverter; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
public class RabbitmqConfig { | ||
|
||
@Value("${spring.rabbitmq.host}") | ||
private String host; | ||
|
||
@Value("${spring.rabbitmq.username}") | ||
private String username; | ||
|
||
@Value("${spring.rabbitmq.password}") | ||
private String password; | ||
|
||
@Value("${spring.rabbitmq.port}") | ||
private int port; | ||
|
||
@Value("${rabbitmq.queue.name}") | ||
private String queueName; | ||
|
||
@Value("${rabbitmq.exchange.name}") | ||
private String exchangeName; | ||
|
||
@Value("${rabbitmq.routing.key}") | ||
private String routingKey; | ||
|
||
@Bean | ||
DirectExchange directExchange() { | ||
return new DirectExchange(exchangeName); | ||
} | ||
|
||
@Bean | ||
Queue queue() { | ||
return new Queue(queueName); | ||
} | ||
|
||
@Bean | ||
Binding binding(DirectExchange directExchange, Queue queue) { | ||
return BindingBuilder.bind(queue).to(directExchange).with(routingKey); | ||
} | ||
|
||
@Bean | ||
ConnectionFactory connectionFactory() { | ||
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); | ||
connectionFactory.setHost(host); | ||
connectionFactory.setPort(port); | ||
connectionFactory.setUsername(username); | ||
connectionFactory.setPassword(password); | ||
return connectionFactory; | ||
} | ||
|
||
@Bean | ||
MessageConverter messageConverter() { | ||
return new Jackson2JsonMessageConverter(); | ||
} | ||
|
||
@Bean | ||
RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory, MessageConverter messageConverter) { | ||
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); | ||
rabbitTemplate.setMessageConverter(messageConverter); | ||
return rabbitTemplate; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package org.c4marathon.assignment.controller; | ||
|
||
import org.c4marathon.assignment.dto.request.PostMainAccountReq; | ||
import org.c4marathon.assignment.dto.request.PostSavingsAccountReq; | ||
import org.c4marathon.assignment.dto.request.TransferReq; | ||
import org.c4marathon.assignment.dto.request.WithdrawMainAccountReq; | ||
import org.c4marathon.assignment.dto.response.MainAccountInfoRes; | ||
import org.c4marathon.assignment.dto.response.TransferRes; | ||
import org.c4marathon.assignment.dto.response.WithdrawInfoRes; | ||
import org.c4marathon.assignment.service.AccountService; | ||
import org.springframework.http.HttpStatus; | ||
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.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@RequestMapping("/v1/accounts") | ||
@RequiredArgsConstructor | ||
public class AccountController { | ||
private final AccountService accountService; | ||
|
||
@PostMapping("/savings") | ||
public ResponseEntity<Void> createSavingsAccount(@RequestBody @Valid PostSavingsAccountReq postSavingsAccountReq) { | ||
accountService.createSavingsAccount(postSavingsAccountReq); | ||
return ResponseEntity.status(HttpStatus.CREATED).build(); | ||
} | ||
@PostMapping("/main/deposit") | ||
public MainAccountInfoRes depositMainAccount(@RequestBody @Valid PostMainAccountReq postMainAccountReq) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ResponseStatus나 ResponseEntity를 사용하지 않은 이유가 어차피 200 반환해서 굳이 사용 안하신건가요?? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 그렇긴 한데..그러다 보니 create 같은 요청에 적절한 응답 코드를 반환하는 걸 놓쳤네요. 명시적으로 반환하도록 수정하여 반영하겠습니다. |
||
return accountService.depositMainAccount(postMainAccountReq); | ||
} | ||
@PostMapping("/savings/withdraw") | ||
public WithdrawInfoRes withdrawForSavings(@RequestBody @Valid WithdrawMainAccountReq withdrawMainAccountReq) { | ||
return accountService.withdrawForSavings(withdrawMainAccountReq); | ||
} | ||
|
||
@PostMapping("/main/transfer") | ||
public TransferRes transfer(@RequestBody @Valid TransferReq transferReq) { | ||
return accountService.transfer(transferReq); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package org.c4marathon.assignment.controller; | ||
|
||
import org.c4marathon.assignment.dto.request.PostSettlementReq; | ||
import org.c4marathon.assignment.dto.response.SettlementInfoRes; | ||
import org.c4marathon.assignment.service.SettlementService; | ||
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; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@RestController | ||
@RequestMapping("/v1/settlement") | ||
@RequiredArgsConstructor | ||
public class SettlementController { | ||
private final SettlementService settlementService; | ||
|
||
@PostMapping | ||
public SettlementInfoRes requestSettlement(@RequestBody @Valid PostSettlementReq settlementReq) { | ||
return settlementService.requestSettlement(settlementReq); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package org.c4marathon.assignment.controller; | ||
|
||
import jakarta.validation.Valid; | ||
import lombok.RequiredArgsConstructor; | ||
import org.c4marathon.assignment.dto.request.PostUserReq; | ||
import org.c4marathon.assignment.service.UserService; | ||
import org.springframework.http.HttpStatus; | ||
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.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/v1/users") | ||
@RequiredArgsConstructor | ||
public class UserController { | ||
private final UserService userService; | ||
|
||
@PostMapping() | ||
public ResponseEntity<Void> registerUser(@RequestBody @Valid PostUserReq postUserReq) { | ||
userService.registerUser(postUserReq); | ||
return ResponseEntity.status(HttpStatus.CREATED).build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.c4marathon.assignment.dto; | ||
|
||
import lombok.AccessLevel; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.ToString; | ||
|
||
@Getter | ||
@ToString | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class MessageDto { | ||
long transferTransactionId; | ||
|
||
long senderMainAccount; | ||
|
||
long receiverMainAccount; | ||
long amount; | ||
|
||
@Builder | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DTO에 빌더 패턴을 적용하신 이유가 있으실까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 단순히 가독성 때문에 사용했습니다. |
||
public MessageDto(long transferTransactionId, long senderMainAccount, long receiverMainAccount, long amount) { | ||
this.transferTransactionId = transferTransactionId; | ||
this.senderMainAccount = senderMainAccount; | ||
this.receiverMainAccount = receiverMainAccount; | ||
this.amount = amount; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package org.c4marathon.assignment.dto; | ||
|
||
import lombok.Builder; | ||
import lombok.Getter; | ||
|
||
@Getter | ||
public class TransferTransactionEvent { | ||
private static final int INIT_TRANSFER_TRANSACTION_ID = -1; | ||
String userName; | ||
long transferTransactionId; | ||
long senderMainAccount; | ||
long receiverMainAccount; | ||
long amount; | ||
|
||
@Builder | ||
public TransferTransactionEvent(String userName, long senderMainAccount, long receiverMainAccount, long amount) { | ||
this.userName = userName; | ||
this.transferTransactionId = INIT_TRANSFER_TRANSACTION_ID; | ||
this.senderMainAccount = senderMainAccount; | ||
this.receiverMainAccount = receiverMainAccount; | ||
this.amount = amount; | ||
} | ||
|
||
public void updateTransferTransactionId(long transferTransactionId) { | ||
this.transferTransactionId = transferTransactionId; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import jakarta.validation.constraints.Positive; | ||
|
||
public record PostMainAccountReq( | ||
@Positive(message = "회원 번호는 양수가 되어야 합니다.") | ||
long userId, | ||
|
||
@Positive(message = "이체 금액은 양수가 되어야 합니다.") | ||
long amount | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import jakarta.validation.constraints.Email; | ||
import jakarta.validation.constraints.NotBlank; | ||
|
||
public record PostSavingsAccountReq( | ||
@NotBlank | ||
String email | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import java.util.List; | ||
|
||
import org.c4marathon.assignment.entity.SettlementType; | ||
|
||
import jakarta.validation.constraints.NotNull; | ||
import jakarta.validation.constraints.Positive; | ||
|
||
public record PostSettlementReq( | ||
@Positive(message = "회원 번호는 양수가 되어야 합니다.") | ||
long requester, | ||
|
||
@Positive(message = "정산 금액은 양수가 되어야 합니다.") | ||
long totalAmount, | ||
|
||
@NotNull | ||
SettlementType type, | ||
|
||
@NotNull | ||
List<Long> userIds | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import jakarta.validation.constraints.Email; | ||
import jakarta.validation.constraints.NotBlank; | ||
import jakarta.validation.constraints.Size; | ||
|
||
public record PostUserReq( | ||
@Size(max = 100) | ||
@NotBlank | ||
String username, | ||
|
||
@NotBlank | ||
String email, | ||
|
||
@Size(max = 100) | ||
@NotBlank | ||
String nickname | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import jakarta.validation.constraints.Positive; | ||
|
||
public record TransferReq( | ||
@Positive(message = "사용자 번호는 양수가 되어야 합니다.") | ||
long senderId, | ||
|
||
@Positive(message = "메인 계좌번호는 양수가 되어야 합니다.") | ||
long receiverMainAccount, | ||
|
||
@Positive(message = "송금 금액은 양수가 되어야 합니다.") | ||
long amount | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package org.c4marathon.assignment.dto.request; | ||
|
||
import jakarta.validation.constraints.Positive; | ||
|
||
public record WithdrawMainAccountReq( | ||
@Positive(message = "회원 번호는 양수가 되어야 합니다.") | ||
long userId, | ||
@Positive(message = "적금 계좌번호는 양수가 되어야 합니다.") | ||
long savingsAccount, | ||
@Positive(message = " 금액은 양수가 되어야 합니다.") | ||
long amount | ||
) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스레드 풀을 하나로 쓰지 않고 둘로 나눈 이유가 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아직 학습 중이라 코드상에는 반영을 못했습니다. 스레드 풀을 분리한 이유는 이벤트 처리로 인한 작업량이 많을 것 같아 스레드 풀을 분리하여 각 기능에 적합하게 구성하고자 했습니다.