13장의 입출금 시스템 구현 확장
개요
- 발신인 계좌에서 지정된 금액을 인출한다.
- 수취인 계좌에 해당 금액을 입금한다.
Model
public class Account {
@Id
private long id;
private String name;
private BigDecimal amount;
}
Repository
public interface AccountRepository extends CrudRepository<Account, Long> {
@Query("SELECT * FROM account WHERE name = :name")
List<Account> findAccountsByName(String name);
@Modifying
@Query("UPDATE account SET amount = :amount WHERE id = :id")
void changeAmount(long id, BigDecimal amount);
}
Service
- 변동성 있는 서비스 메서드에
@Transactional 애너테이션을 붙여 애스펙트를 사용한다.
- Spring Data에서 기본적으로
findById(), findAll() 등의 메서드를 제공한다.
Iterable은 List의 상위 타입이다.
@Service
public class TransferService {
private final AccountRepository accountRepository;
public TransferService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
@Transactional
public void transferMoney(
long idSender,
long idReceiver,
BigDecimal amount
) {
Account sender = accountRepository.findById(idSender)
.orElseThrow(() -> new AccountNotFoundException());
Account receiver = accountRepository.findById(idReceiver)
.orElseThrow(() -> new AccountNotFoundException());
BigDecimal senderNewAmount = sender.getAmount().subtract(amount);
BigDecimal receiverNewAmount = receiver.getAmount().add(amount);
accountRepository.changeAmount(idSender, senderNewAmount);
accountRepository.changeAmount(idReceiver, receiverNewAmount);
}
public Iterable<Account> getAllAccounts() {
return accountRepository.findAll();
}
public List<Account> findAccountsByName(String name) {
return accountRepository.findAccountsByName(name);
}
}
Exception
public class AccountNotFoundException extends RuntimeException {
}
Controller
- 계좌 상세 정보를 반환할 때 비필수 매개변수(
required = false)로 이름을 받아 조건부로 조회한다.
@RestController
public class AccountController {
private final TransferService transferService;
public AccountController(TransferService transferService) {
this.transferService = transferService;
}
@PostMapping("/transfer")
public void transferMoney(
@RequestBody TransferRequest request
) {
transferService.transferMoney(
request.getSenderAccountId(),
request.getReceiverAccountId(),
request.getAmount()
);
}
@GetMapping("/accounts")
public Iterable<Account> getAllAccounts(
@RequestParam(required = false) String name
) {
if (name == null) return transferService.getAllAccounts();
else return transferService.findAccountsByName(name);
}
}
DTO
public class TransferRequest {
private long senderAccountId;
private long receiverAccountId;
private BigDecimal amount;
}