목차
0. 작업 순서
- withdrawal.jsp 파일 생성 및 코드 추가
- 출금 화면 요청 및 기능 구현
- 전체 코드 확인
- 디버그 모드 동작 시켜 보기
1. withdrawal.jsp 파일 생성 및 코드 추가
withdrawal.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 context.jsp(xxx.jsp) -->
<div class="col-sm-8">
<h2>출금 요청(인증)</h2>
<h5>Bank App에 오신걸 환영합니다.</h5>
<!-- 예외적으로 로그인은 보안때문에 post로 던지자 -->
<form action="/account/withdrawal" 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="wAccountPassword">출금 계좌 비밀 번호:</label> <input type="password" class="form-control" placeholder="Enter password" id="wAccountPassword" name="wAccountPassword" value="1234">
</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 context.jsp(xxx.jsp) -->
<!-- footer.jsp -->
<%@ include file="/WEB-INF/view/layout/footer.jsp"%>
결과 화면 확인
2. 출금 화면 요청 및 기능 구현
WithdrawalDTO
package com.tenco.bank.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class WithdrawalDTO {
private Long amount;
private String wAccountNumber;
private String wAccountPassword;
}
AccountController
/**
* 출금 페이지 요청
*
* @return withdrawal.jsp
*/
@GetMapping("/withdrawal")
public String withdrawalPage() {
User principal = (User) session.getAttribute(Define.PRINCIPAL);
if (principal == null) {
throw new UnAuthorizedException(Define.NOT_AN_AUTHENTICATED_USER, HttpStatus.UNAUTHORIZED);
}
return "account/withdrawal";
}
@PostMapping("/withdrawal")
public String withdrawalProc(WithdrawalDTO dto) {
User principal = (User) session.getAttribute(Define.PRINCIPAL);
if (principal == null) {
throw new UnAuthorizedException(Define.NOT_AN_AUTHENTICATED_USER, HttpStatus.UNAUTHORIZED);
}
// 유효성 검사 (자바 코드를 개발) --> 스프링 부트 @Valid 라이브러리가 존재
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 || dto.getWAccountNumber().trim().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST);
}
if (dto.getWAccountPassword() == null || dto.getWAccountPassword().trim().isEmpty()) {
throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST);
}
accountService.updateAccountWithdraw(dto, principal.getId());
return "redirect:/account/list";
}
AccountService
// 한번에 모든 기능을 생각하는건 힘듦
// 1. 계좌 존재 여부를 확인
// 2. 본인 계좌 여부를 확인 -- 객체 상태값에서 비교
// 3. 계좌 비번 확인 -- 객체 상태값에서 비교
// 4. 잔액 여부 확인 -- 객체 상태값에서 확인
// 5. 출금 처리 -- update
// 6. 거래 내역 등록 -- insert(history)
public void updateAccountWithdraw(WithdrawalDTO dto, Integer principalId) {
// 1.
Account accountEntity = accountRepository.findByNumber(dto.getWAccountNumber());
if (accountEntity == null) {
throw new DataDeliveryException(Define.NOT_EXIST_ACCOUNT, HttpStatus.BAD_REQUEST);
}
accountEntity.checkOwner(principalId);
accountEntity.checkPassword(dto.getWAccountPassword());
accountEntity.checkBalance(dto.getAmount());
// 5.
accountEntity.withdraw(dto.getAmount());
accountRepository.updateById(accountEntity);
// 6.
History history = History.builder()
.amount(dto.getAmount())
.wAccountId(accountEntity.getId())
.wBalance(accountEntity.getBalance())
.dAccountId(null)
.dBalance(null)
.build();
int rowResultCount = historyRepository.insert(history);
if (rowResultCount != 1) {
throw new DataDeliveryException(Define.FAILED_PROCESSING, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Account
package com.tenco.bank.repository.model;
import java.sql.Timestamp;
import org.springframework.http.HttpStatus;
import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.utils.Define;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class Account {
private Integer id;
private String number;
private String password;
private Long balance;
private Integer userId;
private Timestamp createdAt;
// 출금 기능
public void withdraw(Long amount) {
// 방어적 코드
this.balance -= amount;
}
// 입금 기능
public void deposit(Long amount) {
// 방어적 코드
this.balance += amount;
}
// 계좌 소유자 확인 기능
public void checkOwner(Integer userId) {
if (this.userId != userId) {
throw new DataDeliveryException(Define.NOT_ACCOUNT_OWNER, HttpStatus.BAD_REQUEST);
}
}
// 패스워드 체크
public void checkPassword(String password) {
if (!this.password.equals(password)) {
throw new DataDeliveryException(Define.FAIL_ACCOUNT_PASSWORD, HttpStatus.BAD_REQUEST);
}
}
// 잔액 여부 확인
public void checkBalance(Long amount) {
if (balance < amount) {
throw new DataDeliveryException(Define.LACK_Of_BALANCE, HttpStatus.BAD_REQUEST);
}
}
}
AccountRepository
package com.tenco.bank.repository.interfaces;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import com.tenco.bank.repository.model.Account;
// AccountRepository 인터페이스와 account.xml 파일을 매칭 시킨다.
@Mapper
public interface AccountRepository {
public int insert(Account account);
public int updateById(Account account);
public int deleteById(Integer id);
// interface 파라미터명과 xml에 사용할 변수명을 다르게 사용해야 된다면 @param 어노테이션을
// 사용할 수 있다. 그리고 2개 이상의 파라미터를 사용할 경우 반드시 @param 어노테이션을 사용하자!
public List<Account> findByUserId(@Param("userId") Integer principalId);
// --> account number 값으로 계좌 정보 조회
public Account findByNumber(@Param("number") String id);
}
account.xml
<select
id="findByNumber"
resultType="com.tenco.bank.repository.model.Account">
select * from account_tb where number = #{number}
</select>
<update id="updateById">
update account_tb set number = #{number}, password = #{password},
balance = #{balance}, user_id = #{userId} where id = #{id}
</update>
history.xml
<insert id="insert">
insert into history_tb(amount, w_balance, d_balance, w_account_id, d_account_id)
values(#{amount},#{wBalance},#{dBalance},#{wAccountId},#{dAccountId})
</insert>
'Spring Boot > Bank App 만들기 (deployment)' 카테고리의 다른 글
21. 이체 기능 만들기 (0) | 2024.08.08 |
---|---|
20. 입금 기능 만들기 (0) | 2024.08.08 |
18. 중간 리팩토링 (0) | 2024.08.08 |
17. 계좌 목록 만들기(1단계) (0) | 2024.08.08 |
16. 계좌 생성(유효성, 인증검사 중 누가 먼저 일까?) (0) | 2024.08.07 |