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;
@Mapper //AccountRepository 인터페이스와 account.xml 파일을 매칭 시킨다.
public interface AccountRepository {
public int insert(Account account);
public int updateById(Account account);
public int deleteById(Integer id, String name);
// ※ 계좌 조회 기능
// 한 사람의 유저는 여러 개의 계좌번호를 가질 수 있다. : 리스트
// interface 파라미터명과 xml에 사용할 변수명을 다르게 사용해야 한다면 @Pram 애노테이션을 사용할 수 있다.
// 그리고 2개 이상의 파라미터를 사용할 경우, 반드시 @Pram 애노테이션을 사용하자!
public List<Account> findByUserId(@Param("userId") Integer principalId); // 유저 아이디로 조회 시 몇 개의 계좌가 있는지 조회
// account id 값으로 계좌 정보 조회하는 기능 필요
public Account findByNumber(@Param("number") String id);
}
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)
);
만약 N:N 관계, 한 학생이 여러 개의 강좌를 수강할 수 있고, 한 강좌가 여러 학생에 의해 수강될 수 있는 경우 데이터베이스에 모델링하는 것은 불가능하기 때문에, 일반적으로 중간 테이블(또는 연결 테이블, 조인 테이블이라고도 함)을 사용하여 N:N 관계를 두 개의 1:N(일대다) 관계로 분리한다.
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(xxx.jsp) -->
<div class="col-sm-8">
<h2>계좌목록(인증)</h2>
<h5>Bank App에 오신걸 환영합니다.</h5>
<!-- 계좌가 없는 경우와 있는 경우 두 가지로 분리 -->
<!-- 계좌가 있는 사용자일 경우, 반복문 활용 예정 (계좌가 여러 개 일 수 있으니) -->
<c:choose>
<c:when test="${accountList != null}"> <%-- 계좌가 존재하는 경우 --%>
<%-- jstl 태그 안에서는 html 주석 사용 시 오류발생 --%>
<table class="table">
<thead>
<tr>
<th>계좌 번호</th>
<th>잔액</th>
</tr>
</thead>
<tbody>
<c:forEach var="account" items="${accountList}"> <%-- 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>아직 생성된 계좌가 없습니다.</h5>
</div>
</c:otherwise>
</c:choose>
</div>
<!-- end of col-sm-8 -->
</div>
</div>
<!-- end of content.jsp(xxx.jsp) -->
<!-- footer.jsp -->
<%@ include file="/WEB-INF/view/layout/footer.jsp"%>
AccountController
package com.tenco.bank.controller;
import java.util.List;
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.tenco.bank.dto.SaveDTO;
import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.UnAuthorizedException;
import com.tenco.bank.repository.model.Account;
import com.tenco.bank.repository.model.User;
import com.tenco.bank.service.AccountService;
import jakarta.servlet.http.HttpSession;
@Controller // IoC대상 (싱글톤으로 관리)
@RequestMapping("/account") // 대문열기
public class AccountController {
// 계좌 생성 화면 요청 - DI 처리
private final HttpSession session;
private final AccountService accountService; // 멤버변수 선언 시 final 사용하면 성능적으로 더 낫다.
// @Autowired
public AccountController(HttpSession session, AccountService accountService) {
this.session = session;
this.accountService = accountService;
}
/**
* 계좌 생성 페이지 요청
* 주소설계 - http://localhost:8080/account/save
* @return save.jsp
*/
@GetMapping("/save")
public String savePage() {
// 1. 인증 검사 필요(account 전체가 필요하다.)
User principal = (User)session.getAttribute("principal");
if(principal == null) { // 로그인 하지 않았다면
throw new UnAuthorizedException("인증되지 않은 사용자 입니다.", HttpStatus.UNAUTHORIZED);
}
return "account/save";
}
/**
* 계좌 생성 기능 요청
* 주소설계 - http://localhost:8080/account/save
* @return : 추후 계좌 목록 페이지로 이동 처리
*/
@PostMapping("/save")
public String saveProc(SaveDTO dto) {
// 1. form 데이터 추출 (파싱 전략)
// 2. 인증 검사
User principal = (User)session.getAttribute("principal");
if(principal == null) { // 로그인 하지 않았다면
throw new UnAuthorizedException("인증되지 않은 사용자 입니다.", HttpStatus.UNAUTHORIZED);
}
// 3. 유효성 검사
if(dto.getNumber() == null || dto.getNumber().isEmpty()) {
throw new DataDeliveryException("계좌번호를 입력해주세요", HttpStatus.BAD_REQUEST);
}
if(dto.getPassword() == null || dto.getPassword().isEmpty()) {
throw new DataDeliveryException("비밀번호를 입력해주세요", HttpStatus.BAD_REQUEST);
}
if(dto.getBalance() == null || dto.getBalance() <= 0) {
throw new DataDeliveryException("계좌 잔액을 입력하세요.", HttpStatus.BAD_REQUEST);
}
// 4. 서비스 호출
accountService.createAccount(dto, principal.getId());
return "redirect:/index";
}
/**
* 계좌 목록 페이지 요청
* 주소설계 - http://localhost:8080/account/list , ..../
* @return
*/
@GetMapping({"/list", "/"}) // url 매핑을 두 개 설정 가능하다.
public String listPage(Model model) { // TODO - 검색 기능 + 페이징 처리 추가 가능
// 1. 인증검사
User principal = (User)session.getAttribute("principal");
if(principal == null) {
throw new UnAuthorizedException("인증되지 않은 사용자 입니다.", HttpStatus.UNAUTHORIZED);
}
// 2. 유효성 검사 - 추출할 데이터 없으므로 아직 필요 x
// 3. 서비스 호출
List<Account> accountList = accountService.readAccountListByUserId(principal.getId());
if(accountList.isEmpty()) { // 리스트는 있으나, 값이 비어있는 경우
model.addAttribute("accountList", null); // 값은 null
} else {
model.addAttribute("accountList", accountList);
}
// JSP에 데이터를 넣어주는 기술 - set/getAttribute
return "account/list";
}
}
accountService
package com.tenco.bank.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.tenco.bank.dto.SaveDTO;
import com.tenco.bank.handler.exception.DataDeliveryException;
import com.tenco.bank.handler.exception.RedirectException;
import com.tenco.bank.repository.interfaces.AccountRepository;
import com.tenco.bank.repository.model.Account;
@Service
public class AccountService {
private final AccountRepository accountRepository;
@Autowired // 생략 가능 - DI 처리
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
/**
* 계좌 생성 기능
* @param dto
* @param id
*/
@Transactional // 트랜잭션 처리
public void createAccount(SaveDTO dto, Integer principalId) {
int result = 0;
try {
result = accountRepository.insert(dto.toAccount(principalId));
} catch (DataAccessException e) {
throw new DataDeliveryException("잘못된 요청입니다.", HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
throw new RedirectException("알 수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
}
if(result == 0) {
throw new DataDeliveryException("정상적으로 처리되지 않았습니다.", HttpStatus.INTERNAL_SERVER_ERROR);
}
}
/**
* 계좌 목록 페이지 요청
* @param id
*/
public List<Account> readAccountListByUserId(Integer userId) {
List<Account> accountListEntity = null;
try {
accountListEntity = accountRepository.findByUserId(userId);
} catch (DataAccessException e) {
throw new DataDeliveryException("잘못된 처리입니다.", HttpStatus.INTERNAL_SERVER_ERROR);
} catch (Exception e) {
throw new RedirectException("알 수 없는 오류", HttpStatus.SERVICE_UNAVAILABLE);
}
return accountListEntity;
}
}
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;
@Mapper //AccountRepository 인터페이스와 account.xml 파일을 매칭 시킨다.
public interface AccountRepository {
public int insert(Account account);
public int updateById(Account account);
public int deleteById(Integer id, String name);
// ※ 계좌 조회 기능
// 한 사람의 유저는 여러 개의 계좌번호를 가질 수 있다. : 리스트
// interface 파라미터명과 xml에 사용할 변수명을 다르게 사용해야 한다면 @Pram 애노테이션을 사용할 수 있다.
// 그리고 2개 이상의 파라미터를 사용할 경우, 반드시 @Pram 애노테이션을 사용하자!
public List<Account> findByUserId(@Param("userId") Integer principalId); // 유저 아이디로 조회 시 몇 개의 계좌가 있는지 조회
// account id 값으로 계좌 정보 조회하는 기능 필요
public Account findByNumber(@Param("number") String id);
// 코드 추가 예정
}
'Spring boot' 카테고리의 다른 글
Bank App 만들기 - 출금 기능 (0) | 2024.08.13 |
---|---|
Bank App 만들기 - 중간 리팩토링 (0) | 2024.08.13 |
Bank App 만들기 - 계좌 생성(유효성, 인증검사 중 무엇이 우선인가) (0) | 2024.08.13 |
Bank App 만들기 - 헤더 링크 설정 및 JSTL 태그 활용 (1) | 2024.08.12 |
Bank App 만들기 - 로그인 처리(세션 메모리지는 누가 관리하고 있을까) (0) | 2024.08.12 |