BankApp - 출금 처리

Gun·2023년 9월 20일

Spring Boot - BankApp

목록 보기
15/25
💡 학습 목표 
   1. 주소 설계 확인 
   2. withdrawForm.jsp 주소 설계 및 name 속성 확인 
   3. AccountController 출금 인증 검사, 유효성 검사 추가 
   4. AccountService 출금 기능 구현 및 트랜잭션 처리 
   5. MyBatis 맵퍼 확인 및 쿼리 확인 

withdraw.jsp

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


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


<div class="col-sm-8">
	<h2>출금 페이지(인증)</h2>
	<h5>어서오세요 환영합니다.</h5>
	<div class="bg-light p-md-5 h-75">
		<div class="form-group">
			<form action="/account/withdraw" method="post">
				<div class="form-group">
					<label for="amount">출금 금액</label>
					<input type="text" id="amount" class="form-control" placeholder="출금 금액을 입력하세요" name="amount">
				</div>
				<div class="form-group">
					<label for="wAccountNumber">출금 계좌번호</label>
					<input type="text" id="wAccountNumber" class="form-control" placeholder="출금 계좌번호를 입력하세요" name="wAccountNumber">
				</div>
				<div class="form-group">
					<label for="wAccountPassword">출금 계좌 비밀번호</label>
					<input type="password" id="wAccountPassword" class="form-control" placeholder="출금 계좌 비밀번호를 입력하세요" name="wAccountPassword">
				</div>
				<button type="submit" class="btn btn-primary">출금</button>
			</form>
		</div>
	</div>
	
	</div>
	</div>
</div>

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

AccountController.java


package com.tencoding.bank.controller;

import java.util.List;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.tencoding.bank.dto.DepositFormDto;
import com.tencoding.bank.dto.SaveFormDto;
import com.tencoding.bank.dto.WithDrawFormDto;
import com.tencoding.bank.handler.exception.CustomRestfulException;
import com.tencoding.bank.handler.exception.UnAuthorizedException;
import com.tencoding.bank.repository.model.Account;
import com.tencoding.bank.repository.model.User;
import com.tencoding.bank.service.AccountService;
import com.tencoding.bank.util.Define;

@Controller
@RequestMapping("/account")
public class AccountController {
	
	@Autowired
	private HttpSession session;
	@Autowired
	private AccountService accountService;
	
	// 계좌 목록 페이지
	// http://localhost:80/account/list
	
	@GetMapping("/list")
	public String list(Model model) {
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		
		List<Account> accountList = accountService.readAccountList(user.getId());
		
		if(accountList.isEmpty()) {
			model.addAttribute("accountList", null);
		} else {
			model.addAttribute("accountList", accountList);
		}
		
		return "account/list";
	}
	
	
	// 계좌 생성 페이지
	// http://localhost:80/account/save
	// /account/save - 화면 이동
	/**
	 * 계좌 생성 페이지 이동
	 */
	@GetMapping("/save")
	public String save() {
		// 1. 인증 여부 확인
		
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		
		return "account/save";
	}
	
	/**
	 * 계좌 생성 로직 구현
	 * @return
	 */
	@PostMapping("/save")
	public String saveProc(SaveFormDto saveFormDto) {
		// 1. 인증 검사
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		// 2. 유효성 검사
		if(saveFormDto.getNumber() == null
				|| saveFormDto.getNumber().isEmpty()) {
			throw new CustomRestfulException("계좌번호를 입력해주세요.", HttpStatus.BAD_REQUEST);
		}
		
		if(saveFormDto.getPassword() == null
				|| saveFormDto.getPassword().isEmpty()) {
			throw new CustomRestfulException("비밀번호를 입력해주세요.", HttpStatus.BAD_REQUEST);
		}
		
		if(saveFormDto.getBalance() == null 
				|| saveFormDto.getBalance() < 0) {
			throw new CustomRestfulException("잘못된 입력입니다.", HttpStatus.BAD_REQUEST);
		}
		// 3. 서비스 호출
		accountService.creatAccount(saveFormDto, user.getId());
		return "redirect:/account/list";
	}
	
	// 출금 페이지
	// http://localhost:80/account/withdraw
	
	@GetMapping("/withdraw")
	public String withdraw() {
		// 1. 인증 여부 확인
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		
		return "account/withdraw";
	}
	
	// body -> String --> amount=1000&wAccountId=10&......
	@PostMapping("/withdraw")
	public String withdrawProc(WithDrawFormDto withDrawFormDto) {
		// 1. 인증 여부 확인
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		
		// 2. 유효성 검사
		if(withDrawFormDto.getAmount() == null) {
			throw new CustomRestfulException("금액을 입력해주세요.", HttpStatus.BAD_REQUEST);
		}
		if(withDrawFormDto.getAmount() <= 0) {
			throw new CustomRestfulException("잘못된 금액입니다.", HttpStatus.BAD_REQUEST);
		}
		if(withDrawFormDto.getWAccountNumber() == null
				|| withDrawFormDto.getWAccountNumber().isEmpty()) {
			throw new CustomRestfulException("출금 계좌번호를 확인해주세요.", HttpStatus.BAD_REQUEST);
		}
		if(withDrawFormDto.getWAccountPassword() == null
				|| withDrawFormDto.getWAccountPassword().isEmpty()) {
			throw new CustomRestfulException("출금 계좌 비밀번호를 확인해주세요.", HttpStatus.BAD_REQUEST);
		}
		
		accountService.updateAccountWithdraw(withDrawFormDto, user.getId());
		
		
		return "redirect:/account/list";
	}
	
	// 입금 페이지
	// http://localhost:80/account/deposit
	
	@GetMapping("/deposit")
	public String deposit() {
		// 1. 인증 여부 확인
		User user = (User)session.getAttribute(Define.PRINCIPAL);;
		if(user == null) {
			throw new UnAuthorizedException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
		}
		return "account/deposit";
	}
	
	// 이체 페이지
	// http://localhost:80/account/transfer
	
	@GetMapping("/transfer")
	public String transfer() {
		return "account/transfer";
	}
	
	
	// TODO - 수정하기
	// 상세 보기 페이지
	// http://localhost:80/account/detail/1
	
	@GetMapping("/detail")
	public String detail() {
		return "account/detail";
	}
}

AccountService.java


package com.tencoding.bank.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tencoding.bank.dto.DepositFormDto;
import com.tencoding.bank.dto.SaveFormDto;
import com.tencoding.bank.dto.WithDrawFormDto;
import com.tencoding.bank.handler.exception.CustomRestfulException;
import com.tencoding.bank.repository.interfaces.AccountRepository;
import com.tencoding.bank.repository.interfaces.HistoryRepository;
import com.tencoding.bank.repository.model.Account;
import com.tencoding.bank.repository.model.History;

@Service // IoC 대상 + 싱글톤 패턴으로 -> 스프링 컨테이너 메모리에 객체가 생성
public class AccountService {
	
	@Autowired
	private AccountRepository accountRepository;
	
	@Autowired
	private HistoryRepository historyRepository;
	
	@Transactional
	public void creatAccount(SaveFormDto saveFormDto, Integer principalId) {
		// 등록 처리 - insert
		Account account = new Account();
		account.setNumber(saveFormDto.getNumber());
		account.setPassword(saveFormDto.getPassword());
		account.setBalance(saveFormDto.getBalance());
		account.setUserId(principalId);
		
		int resultRowCount = accountRepository.insert(account);
		if(resultRowCount != 1) {
			throw new CustomRestfulException("계좌 생성 실패", HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}
	
	/**
	 * 계좌 목록 보기 ( 로그인 된 사용자 )
	 * @param userId
	 * @return
	 */
	@Transactional
	public List<Account> readAccountList(Integer userId) {
		List<Account> list = accountRepository.findByUserId(userId);
		return list;
	}

	// 출금 기능 로직을 고민해보기
	// 1. 계좌 존재 여부 확인 - select query
	// 2. 본인 계좌 여부 확인 - select query
	// 3. 계좌 비밀번호 확인 - select query
	// 4. 계좌 잔액 여부 확인 - select query
	// 5. 출금 처리 --> update query
	// 6. 거래 내역 등록 -> insert query - history_tb
	// 7. 트랜잭션 처리
	
	@Transactional
	public void updateAccountWithdraw(WithDrawFormDto withDrawFormDto, Integer id) {
		Account accountEntity = accountRepository.findByNumber(withDrawFormDto.getWAccountNumber());
		// 1
		if(accountEntity == null) {
			throw new CustomRestfulException("해당 계좌가 없습니다.", HttpStatus.BAD_REQUEST);
		}
		// 2
		if(accountEntity.getUserId() != id) {
			throw new CustomRestfulException("본인 소유 계좌가 아닙니다.", HttpStatus.BAD_REQUEST);
		}
		// 3
		if(accountEntity.getPassword().equals(withDrawFormDto.getWAccountPassword()) == false) {
			throw new CustomRestfulException("출금 계좌 비밀번호가 일치하지 않습니다.", HttpStatus.BAD_REQUEST);
		}
		// 4
		if(accountEntity.getBalance() < withDrawFormDto.getAmount()) {
			throw new CustomRestfulException("계좌 잔액이 부족합니다.", HttpStatus.BAD_REQUEST);
		}
		// 5 -> update query (모델 객체 상태 변경 -> 객체 다시 던지기)
		accountEntity.withdraw(withDrawFormDto.getAmount());
		// 쿼리 던지기
		accountRepository.updateById(accountEntity);
		// 6 - 거래 내역 등록 History 객체 생성
		History history = new History();
		history.setAmount(withDrawFormDto.getAmount());
		// 출금 시점에 해당 계좌에 잔액을 입력
		history.setWBalance(accountEntity.getBalance());
		history.setDBalance(null);
		history.setWAccountId(accountEntity.getId());
		history.setDAccountId(null);
		
		int resultRowCount = historyRepository.insert(history);
		if(resultRowCount != 1) {
			throw new CustomRestfulException("정상적으로 처리되지 않았습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
		}
	}

}

WithDrawFormDto.java


package com.tencoding.bank.dto;

import lombok.Data;

@Data
public class WithDrawFormDto {

	// 화면 name태그 기준
	private Long amount;
	private String wAccountNumber;
	private String wAccountPassword;
	
}

account.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tencoding.bank.repository.interfaces.AccountRepository"> 
	
	<select id="findByUserId" resultType="com.tencoding.bank.repository.model.Account">
		 select * from account_tb where user_id = #{userId}
	</select>
	
	<insert id="insert">
		insert into account_tb (number, password, balance, user_id, created_at) 
		values(#{number}, #{password}, #{balance}, #{userId}, now())
	</insert>
	
	<update id="updateById">
		update account_tb set number = #{number}, password = #{password}, balance = #{balance} where id = #{id}
	</update>

	<delete id="deleteById">
		 delete from account_tb where id = #{id}
	</delete>
	
	<select id="findById" resultType="com.tencoding.bank.repository.model.Account">
		select * from account_tb where id = #{id}
	</select>
	
	<select id="findAll" resultType="com.tencoding.bank.repository.model.Account">
		select * from account_tb
	</select>
	
	<select id="findByNumber" resultType="com.tencoding.bank.repository.model.Account">
		select * from account_tb where number = #{number}
	</select>
	
	 
	
</mapper>

history.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.tencoding.bank.repository.interfaces.HistoryRepository"> 
	<insert id="insert">
		insert into history_tb (amount, w_account_id, d_account_id, w_balance, d_balance, created_at) 
		values(#{amount}, #{wAccountId}, #{dAccountId}, #{wBalance}, #{dBalance}, now())
	</insert>
	
	<update id="updateById">
		update history_tb set amount = #{amount} , w_balance = #{wBalance}, d_balance = #{dBalance}, 
		w_account_id = #{wAccountId}, d_account_id = #{dAccountId} where id = #{id} 
	</update>
	
	<delete id="deleteById">
		delete from history_tb where id = #{id}
	</delete>
	 
	 <select id="findAll" resultType="com.tencoding.bank.repository.model.History">
	 	select * from history_tb
	 </select>
	 
	 <select id="findById" resultType="com.tencoding.bank.repository.model.History">
	 	select * from history_tb where id = #{id}
	 </select>
	
	
</mapper>

0개의 댓글