Spring boot

Bank App 만들기 - 이체 기능

ryeonng 2024. 8. 13. 17:46

 

화면 확인 하기

 

transfer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>

<!-- header.jsp -->
<%@ include file="/WEB-INF/view/layout/header.jsp"%>

<!-- start of content.jsp(xxx.jsp) -->
<div class="col-sm-8">
	<h2>계좌 이체(인증)</h2>
	<h5>Bank App에 오신걸 환영합니다.</h5>
	<form action="/account/transfer"  method="post">
		<div class="form-group">
			<label for="amount">이체 금액:</label> 
			<input type="number" class="form-control" placeholder="Enter amount" id="amount" name="amount" value="1000">
		</div>
		<div class="form-group">
			<label for="wAccountNumber">출금 계좌 번호:</label>
			<input type="text" class="form-control" placeholder="Enter account number" id="wAccountNumber" name="wAccountNumber" value="1111">
		</div>
		<div class="form-group">
			<label for="pwd">출금 계좌 비밀번호:</label> 
			<input type="password" class="form-control" placeholder="Enter password" id="pwd" name="password" value="1234">
		</div>
		<div class="form-group">
			<label for="dAccountNumber">입금(이체) 계좌 번호:</label>
			<input type="text" class="form-control" placeholder="Enter account number" id="dAccountNumber" name="dAccountNumber" value="2222">
		</div>
		<div class="text-right">
		<button type="submit" class="btn btn-primary">이체 요청</button>
		</div>
	</form>
</div>
<!-- end of col-sm-8 -->
</div>
</div>
<!-- end of content.jsp(xxx.jsp) -->

<!-- footer.jsp -->
<%@ include file="/WEB-INF/view/layout/footer.jsp"%>

 

TransferDTO
package com.tenco.bank.dto;

import lombok.Data;

@Data
public class TransferDTO {
	
	private Long amount; // 거래 금액 
	private String wAccountNumber; // 출금계좌 번호  
	private String dAccountNumber; // 입금계좌 번호 
	private String password; // 출금 계좌 비밀번호   
}

 

AccountController
/**
	 * 이체 페이지 요청
	 * 
	 * @return transfer.jsp
	 */
	@GetMapping("/transfer")
	public String transferPage() {
		// 인증검사
		User principal = (User) session.getAttribute(Define.PRINCIPAL);
		if (principal == null) {
			throw new UnAuthorizedException(Define.NOT_AN_AUTHENTICATED_USER, HttpStatus.UNAUTHORIZED);
		}
		return "account/transfer";
	}

	/**
	 * 이체 기능 처리 요청
	 * 
	 * @param dto
	 * @return
	 */
	@PostMapping("/transfer")
	public String tranferProc(TransferDTO dto) {

		// 1. 인증검사
		User principal = (User) session.getAttribute(Define.PRINCIPAL);
		if (principal == null) {
			throw new UnAuthorizedException(Define.NOT_AN_AUTHENTICATED_USER, HttpStatus.UNAUTHORIZED);
		}
		
		// 유효성 검사
		if (dto.getAmount() == null) {
			throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST);
		}

		if (dto.getAmount().longValue() <= 0) {
			throw new DataDeliveryException(Define.W_BALANCE_VALUE, HttpStatus.BAD_REQUEST);
		}
		
		if (dto.getWAccountNumber() == null) {
			throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST);
		}

		if (dto.getPassword() == null || dto.getPassword().isEmpty()) {
			throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST);
		}
		
		if (dto.getDAccountNumber() == null) {
			throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST);
		}
		
		accountService.updateAccountTransfer(dto, principal.getId());

		return "redirect:/account/list";
	}

 

AccountService
// 이체 기능 만들기
	// 1. 출금계좌 존재 여부 확인 -- select
	// 2. 입금계좌 존재 여부 확인 -- select (객체 리턴 받은 상태)
	// 3. 출금 계좌 본인 소유 여부 확인 -- 객체 상태값과 세션 아이디를 비교
	// 4. 출금 계좌 비밀번호 확인 -- 겍체 상태값과 dto 비밀번호 비교 
	// 5. 출금 계좌 잔액 여부 확인 -- 객체 상태값과 dto 비교
	// 6. 입금 계좌 객체 상태값 변경 처리 (거래금액 증가 처리)
	// 7. 입금 계좌 -- update 처리
	// 8. 출금 계좌 객체 상태값 변경 처리 (잔액 - 거래금액)
	// 9. 출금 계좌 -- update 처리
	// 10. 거래 내역 등록 처리
	// 11. 트랜잭션 처리
	@Transactional
	public void updateAccountTransfer(TransferDTO dto, Integer principalId) {
		
		// 1. 출금계좌 존재 여부 확인
		Account waccountEntity = accountRepository.findByNumber(dto.getWAccountNumber());
		if(waccountEntity == null ) {
			throw new DataDeliveryException(Define.NOT_EXIST_ACCOUNT, HttpStatus.BAD_REQUEST);
		}
		
		// 2. 입금계좌 존재 여부 확인
		Account daccountEntity = accountRepository.findByNumber(dto.getDAccountNumber());
		if(daccountEntity == null ) {
			throw new DataDeliveryException("입금할 상대의 계좌번호가 없습니다.", HttpStatus.BAD_REQUEST);
		}
		
		// 3. 출금 계좌 본인 소유 여부 확인
		waccountEntity.checkOwner(principalId);
		
		// 4. 출금 계좌 비밀번호 확인
		waccountEntity.checkPassword(dto.getPassword());
		
		// 5. 출금 계좌 잔액 여부 확인
		waccountEntity.checkBalance(dto.getAmount());
		
		// 6. 입금 계좌 객체 상태값 변경 처리
		daccountEntity.deposit(dto.getAmount());
		
		// 7. 입금 계좌 -- update 처리
		int resultRowCountWithdraw = accountRepository.updateById(daccountEntity);
		
		// 8. 출금 계좌 객체 상태값 변경 처리
		waccountEntity.withdraw(dto.getAmount());
		
		// 9. 출금 계좌 -- update 처리
		int resultRowCountDeposit = accountRepository.updateById(waccountEntity);
		
		if(resultRowCountWithdraw != 1 && resultRowCountDeposit != 1) {
			throw new DataDeliveryException(Define.FAILED_PROCESSING, HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		// 10. 거래 내역 등록 처리
		// TransferDTO 에 History 객체를 반환하는 메서들 만들어 줄 수 있습니다. 
		// 여기서는 직접 만들도록 하겠습니다. 
		History history = History.builder().amount(dto.getAmount()) // 이체 금액
				.wAccountId(waccountEntity.getId()) // 출금 계좌
				.dAccountId(daccountEntity.getId()) // 입금 계좌
				.wBalance(waccountEntity.getBalance()) // 출금 계좌 남은 잔액
				.dBalance(daccountEntity.getBalance()) // 입금 계좌 남은 잔액
				.build();
		
		int resultRowCountHistory =  historyRepository.insert(history);
		if(resultRowCountHistory != 1) {
			throw new DataDeliveryException(Define.FAILED_PROCESSING, HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}