이번에는 계좌 상세 보기 기능을 단계별로 구현하는 방법을 설명하겠습니다.
계좌 상세 보기를 통해 특정 계좌의 입금, 출금, 이체 내역을 확인할 수 있습니다.
사용자는 전체 거래 내역 또는 특정 유형(입금, 출금)만 필터링할 수도 있습니다.
- 계좌 상세 보기: 특정 계좌의 거래 내역을 확인하는 기능입니다.
- 유형별 조회: 모든 거래, 입금만, 출금만 보기 기능을 제공합니다.
- 목표: 계좌 번호와 사용자의 인증 상태를 확인하고, DB에서 내역을 조회하여 화면에 출력합니다.
1. 데이터베이스 테이블 생성
테이블 구조
create table user_tb(
id int auto_increment primary key,
username varchar(50) not null unique,
password varchar(100) not null,
fullname varchar(50) not null,
created_at timestamp not null default now()
);
create table account_tb(
id int auto_increment primary key,
number varchar(30) not null unique,
password varchar(30) not null,
balance bigint not null comment '계좌잔액',
created_at timestamp not null default now(),
user_id int
);
create table history_tb(
id int auto_increment primary key comment '거래내역 ID',
amount bigint not null comment '거래금액',
w_account_id int comment '출금 계좌 ID',
d_account_id int comment '입금 계좌 ID',
w_balance bigint comment '출금 후 잔액',
d_balance bigint comment '입금 후 잔액',
created_at timestamp not null default now()
);
- user_tb: 사용자 정보 저장 테이블입니다.
- account_tb: 사용자 계좌 정보 저장 테이블입니다.
- history_tb: 모든 거래 내역을 저장하는 테이블입니다. 각 거래는 출금 계좌와 입금 계좌를 기록합니다.
2. 계좌 상세 보기 페이지 컨트롤러 구현
컨트롤러 메서드 (detailPage)
@GetMapping("/detail/{accountId}")
public String detailPage(@PathVariable(name = "accountId") Integer accountId,
@RequestParam(required = false, name = "type" ) String type) {
// 1. 인증 검사
User principal = (User) session.getAttribute(Define.PRINCIPAL);
if (principal == null) {
throw new UnAuthorizedException(Define.ENTER_YOUR_LOGIN, HttpStatus.UNAUTHORIZED);
}
// 2. 유효성 검사
List<String> validTypes = Arrays.asList("all", "deposit", "withdrawal");
if(!validTypes.contains(type)) {
throw new DataDeliveryException("유효하지 않은 접근 입니다", HttpStatus.BAD_REQUEST);
}
// 계좌 상세 보기 페이지로 이동
return "/account/detail";
}
- 인증된 사용자만 접근할 수 있도록 합니다.
- 거래 내역 유형(type)이 all, deposit, withdrawal 중 하나인지 검증합니다.
- 검증에 실패할 경우 예외를 던집니다.
3. 서비스 레이어에서 단일 계좌 조회
계좌 ID로 단일 계좌 정보를 조회하는 메서드입니다.
public Account readAccountId(Integer accountId) {
Account account = accountRepository.findByAccountId(accountId);
if(account == null) {
throw new DataDeliveryException(Define.NOT_EXIST_ACCOUNT, HttpStatus.BAD_REQUEST);
}
return account;
}
- accountId로 단일 계좌 정보를 조회합니다.
- 조회된 계좌가 없을 경우 예외를 던집니다.
4. 리포지토리 코드 추가
AccountRepository에 계좌 조회 메서드 추가
@Mapper
public interface AccountRepository {
public Account findByAccountId(Integer accountId);
}
account.xml - SQL 쿼리
<select id="findByAccountId" resultType="com.tenco.bank.repository.model.Account">
SELECT * FROM account_tb WHERE id = #{accountId}
</select>
- AccountRepository에 findByAccountId 메서드를 추가하여 계좌 정보를 조회합니다.
- SQL 쿼리를 통해 특정 accountId의 계좌 정보를 가져옵니다.
5. 거래 내역 조회 기능
HistoryRepository에 동적 쿼리 메서드 추가
@Mapper
public interface HistoryRepository {
public List<HistoryAccountDTO> findByAccountIdAndTypeOfHistory(@Param("type") String type,
@Param("accountId") Integer accountId);
}
history.xml - 동적 쿼리
동적 쿼리를 사용하여 거래 유형에 따라 다른 결과를 반환합니다.
<select id="findByAccountIdAndTypeOfHistory" resultType="com.tenco.bank.dto.HistoryAccountDTO">
<if test="type == 'all'">
SELECT
h.id, h.amount,
CASE
WHEN h.w_account_id = #{accountId} THEN h.w_balance
WHEN h.d_account_id = #{accountId} THEN h.d_balance
END AS balance,
COALESCE(CAST(wa.number AS CHAR(10)), 'ATM') as sender,
COALESCE(CAST(da.number AS CHAR(10)), 'ATM') as receiver,
h.created_at
FROM history_tb AS h
LEFT JOIN account_tb AS da ON h.d_account_id = da.id
LEFT JOIN account_tb AS wa ON h.w_account_id = wa.id
WHERE h.d_account_id = #{accountId} OR h.w_account_id = #{accountId};
</if>
<if test="type == 'withdrawal'">
SELECT
h.id, h.amount, h.w_balance AS balance, h.created_at,
COALESCE(CAST(da.number AS CHAR(10)), 'ATM') as receiver,
wa.number as sender
FROM history_tb AS h
LEFT JOIN account_tb AS wa ON wa.id = h.w_account_id
LEFT JOIN account_tb AS da ON da.id = h.d_account_id
WHERE h.w_account_id = #{accountId}
</if>
<if test="type == 'deposit'">
SELECT
h.id, h.amount, h.d_balance as balance, h.created_at,
COALESCE(CAST(wa.number AS CHAR(10)), 'ATM') as sender,
da.number as receiver
FROM history_tb AS h
LEFT JOIN account_tb AS da ON da.id = h.d_account_id
LEFT JOIN account_tb AS wa ON wa.id = h.w_account_id
WHERE h.d_account_id = #{accountId}
</if>
</select>
- 거래 유형(type)에 따라 all, withdrawal, deposit 각각 다른 쿼리를 실행합니다.
- 거래 내역에 따라 송금자와 수신자를 다르게 표시합니다.
6. 거래 내역 출력 페이지 예시 (JSP/HTML)
<table>
<thead>
<tr>
<th>거래 일시</th>
<th>보낸 사람</th>
<th>받는 사람</th>
<th>금액</th>
<th>잔액</th>
</tr>
</thead>
<tbody>
<c:forEach var="historyAccount" items="${historyList}">
<tr>
<td>${historyAccount.createdAt}</td>
<td>${historyAccount.sender}</td>
<td>${historyAccount.receiver}</td>
<td>${historyAccount.amount}</td>
<td>${historyAccount.balance}</td>
</tr>
</c:forEach>
</tbody>
</table>
- JSP 페이지에서 historyList 데이터를 루프를 돌며 출력합니다.
- 거래 일시, 송금자, 수신자, 거래 금액, 잔액을 각각의 열로 표시합니다
계좌 상세 보기 기능은 특정 계좌의 거래 내역을 확인할 수 있는 중요한 기능입니다.
all, withdrawal, deposit 필터를 적용하여 사용자가 원하는 데이터만 볼 수 있도록 설계되었습니다.
데이터베이스와 연동하여 효율적인 조회와 출력이 가능하게 구현하였습니다.