새소식

Spring

[Spring boot] Bank App - 계좌 목록 조회

  • -
728x90

👨‍💻 지난 포스팅에서 계좌생성을 구현했습니다. 이어 이번 포스팅에서는 계좌 목록 조회 과정을 다뤄보겠습니다. 🚀

Spring Boot를 활용한 계좌 목록 조회 기능 구현 🚀

이번 글에서는 계좌 목록을 조회하는 기능을 단계별로 구현하겠습니다.


📌 학습 목표

  1. AccountRepositoryaccount.xml을 수정하여 계좌 목록 조회 기능 추가
  2. AccountService 및 AccountController에서 계좌 목록 조회 기능 구현
  3. account/list.jsp를 생성하여 계좌 목록 화면 구성

1. AccountRepository 및 account.xml 코드 수정

기존 문제점 확인

<select id="findAllByUserId" resultType="com.tenco.bank.repository.model.Account">
	select * from account_tb 
</select>

 

위와 같은 쿼리는 모든 계좌를 조회하는 문제가 있습니다.
따라서 특정 사용자(userId)의 계좌만 조회하도록 수정해야 합니다.

 

수정된 account.xml 코드

<select id="findAllByUserId" resultType="com.tenco.bank.repository.model.Account">
	select * from account_tb where user_id = #{userId}
</select>

AccountRepository.java 코드 수정

package com.tenco.bank.repository.interfaces;

import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.tenco.bank.repository.model.Account;

@Mapper  
public interface AccountRepository {
	
	// 코드 확인 (계좌 생성) 
	public int insert(Account account);
	public int updateById(Account account);
	public int deleteById(Integer id);
	
	// 계좌 조회 - 1 유저 , N 계좌 
	public List<Account> findAllByUserId();
	public Account findByNumber(Integer id);
	
}

 

위 코드의 findAllByUserId()는 특정 사용자의 계좌만 조회하는 것이 아니라
모든 계좌를 조회하는 문제가 발생할 수 있습니다.

 

수정된 코드 (사용자 ID 기반 조회)

@Mapper  
public interface AccountRepository {
	
	// 계좌 조회 - 특정 사용자의 모든 계좌 조회
	// @Param 어노테이션을 사용하여 XML과 변수명을 맞춰줌
	public List<Account> findAllByUserId(@Param("userId") Integer principalId);
}

📌 변경 사항

  • 특정 사용자(principalId)의 계좌만 조회하도록 SQL 쿼리 변경
  • MyBatis의 @Param 어노테이션을 사용하여 XML과 일관된 변수명을 유지
  • 여러 개의 파라미터가 필요할 경우 @Param을 반드시 사용해야 함

📌 데이터베이스의 N:M(다대다) 관계 해결 방법

우리 서비스에서는 모임 통장 개념을 사용하지 않으며,
한 명의 사용자는 여러 개의 계좌를 가질 수 있는 1:N(일대다) 관계로 모델링합니다.

하지만 만약 N:M(다대다) 관계가 필요한 경우에는 중간 테이블을 활용하여 두 개의 1:N 관계로 변환하는 것이 일반적입니다.

N:M 관계의 예제

한 학생(Student)이 여러 개의 강좌(Course)를 수강할 수 있고,
한 강좌도 여러 명의 학생이 수강할 수 있다고 가정하겠습니다.

📌 잘못된 모델링 (N:M 관계)

CREATE TABLE 학생 (
    학생ID INT PRIMARY KEY,
    이름 VARCHAR(100)
);

CREATE TABLE 강좌 (
    강좌ID INT PRIMARY KEY,
    강좌명 VARCHAR(100)
);

이렇게 구성하면 어떤 학생이 어떤 강좌를 듣는지 직접적으로 표현할 수 없습니다.


  해결 방법: 중간 테이블(연결 테이블) 활용

중간 테이블을 생성하여 두 개의 1:N 관계로 변환합니다.
이를 통해 다대다(N:M) 관계를 1:N + N:1 관계로 분리할 수 있습니다.

CREATE TABLE 학생 (
    학생ID INT PRIMARY KEY,
    이름 VARCHAR(100)
);

CREATE TABLE 강좌 (
    강좌ID INT PRIMARY KEY,
    강좌명 VARCHAR(100)
);

-- 학생과 강좌를 연결하는 중간 테이블 (수강 테이블)
CREATE TABLE 수강 (
    학생ID INT,
    강좌ID INT,
    PRIMARY KEY (학생ID, 강좌ID),
    FOREIGN KEY (학생ID) REFERENCES 학생(학생ID),
    FOREIGN KEY (강좌ID) REFERENCES 강좌(강좌ID)
);

 

중간 테이블을 활용하는 이유

  • 중복된 데이터를 방지할 수 있음
  • 추가적인 속성(수강 날짜, 성적 등)을 저장할 수 있음
  • 데이터베이스 정규화를 통해 관리가 용이함

2. 계좌 목록 기능 만들기

계좌 목록 조회 서비스 구현

	/**
	 * 복잡한 Select 쿼리문일 경우 트랜잭션 처리를 해주 것이 좋습니다.  
	 * 여기서는 단순한 Select 구문이라 바로 진행 합니다. 
	 * @param principalId
	 * @return
	 */
	public List<Account> readAccountListByUserId(Integer principalId) {
		List<Account> accountListEntity = null;
		try {
			accountListEntity = accountRepository.findAllByUserId(principalId);
		} catch (DataAccessException e) {
			throw new DataDeliveryException("잘못된 처리 입니다", HttpStatus.INTERNAL_SERVER_ERROR);
		} catch (Exception e) {
			// 예외 처리 - 에러 페이지로 이동
			throw new RedirectException("알 수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
		}
		return accountListEntity;
	}

 

핵심 포인트

  • 특정 사용자의 계좌 목록을 데이터베이스에서 조회
  • 트랜잭션 처리 불필요 (단순 SELECT 쿼리)
  • 예외 처리 적용
    • DataAccessException → 데이터베이스 관련 오류 발생 시 처리
    • RedirectException → 알 수 없는 오류 발생 시 에러 페이지로 리디렉트

📌AccountController 코드 추가 (계좌 목록 페이지 요청 처리)

	/**
	 * 계좌 목록 페이지
	 * 
	 * @param model - accountList
	 * @return list.jsp
	 */
	@GetMapping({ "/list", "/" })
	public String listPage(Model model) {
		
		// 1.인증 검사가 필요(account 전체 필요)
		User principal = (User) session.getAttribute("principal");
		if (principal == null) {
			throw new UnAuthorizedException("인증된 사용자가 아닙니다", HttpStatus.UNAUTHORIZED);
		}

		// 경우의 수 -> 유, 무
		List<Account> accountList = accountService.readAccountListByUserId(principal.getId());

		if (accountList.isEmpty()) {
			model.addAttribute("accountList", null);
		} else {
			model.addAttribute("accountList", accountList);
		}

		return "account/list";
	}

 

핵심 포인트

  • 로그인한 사용자만 계좌 목록을 조회할 수 있도록 인증 검사 적용
  • 계좌 목록 조회 후 Model 객체에 저장하여 JSP로 전달
  • 사용자가 계좌를 가지고 있지 않을 경우 null로 설정하여 예외 방지
  • 뷰 페이지(account/list.jsp)로 이동하여 결과를 출력

3. account/list.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(메인 영역)   -->
<div class="col-sm-8">
	<h2>계좌 목록(인증)</h2>
	<h5>Bank App 오신 걸 환영합니다.</h5>
		<c:choose>
		<c:when test="${accountList != null }">
			<table class="table">
				<thead>
					<tr>
						<th>계좌 번호</th>
						<th>잔액</th>
					</tr>
				</thead>
				<tbody>
					<c:forEach var="account" items="${accountList}">
						<tr>
							<td>${account.number}</td>
							<td>${account.balance}</td>
						</tr>
					</c:forEach>

				</tbody>
			</table>
		</c:when>
		<c:otherwise>
		<div class="jumbotron display-4">
			<h5><small>아직 생성된 계좌가 없습니다</small></h5>
		</div>
		</c:otherwise>
	</c:choose>
</div>
</div>
</div>

<!-- end of content.jsp(메인 영역)   -->

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

 

핵심 포인트

  • c:choose를 활용하여 계좌 목록이 있을 경우 테이블로 출력
  • 계좌 목록이 없을 경우 "아직 생성된 계좌가 없습니다" 메시지 출력
  • c:forEach를 활용하여 계좌 데이터를 반복 출력

📌 결과 화면

 

📌 계좌가 없을 경우 화면


📌 전체 요약

특정 사용자의 계좌 목록을 조회하도록 AccountRepository 수정
AccountService에서 예외 처리를 포함한 계좌 목록 조회 로직 구현
AccountController에서 로그인한 사용자만 계좌 목록을 볼 수 있도록 인증 적용
JSP(account/list.jsp)에서 계좌 목록을 테이블로 출력 (없을 경우 안내 메시지 출력)


🎯 마무리

이제 /account/list 페이지에서 로그인한 사용자의 계좌 목록을 확인할 수 있습니다!
이러한 흐름을 이해하면 계좌 상세 조회, 계좌 이체, 출금 기능도 쉽게 확장할 수 있습니다.

🚀 다음 포스팅에서는 출금 기능에 대해서 적어볼게요! 🚀


계좌 생성이 궁금하다면??

 

[Spring boot] Bank App - 계좌 생성

👨‍💻 지난 포스팅에서 로그인, 로그아웃을 구현하였습니다. 이번 포스팅에서는 계좌 생성 과정을 다뤄보겠습니다. 🚀Spring Boot로 계좌 생성 기능 구현하기웹 애플리케이션에서 계좌 생성

seohong.tistory.com

 

 

 

 

Contents