💡 학습목표
1. AuthIntercepter 구현 클래스 만들기
2. WebMvcConfig 구현 클래스 만들기
3. 코드 수정 - 인증 처리 일괄 적용 하기 (AccountController 수정)
HandlerInterceptor 는 spring boot MVC 에서 제공하는 인터셉터로
AOP 개념과는 다르게 서블릿 필터처럼 동작 합니다.
즉, 클라언트의 요청이 컨트롤러에 도달하기 전에 인터셉터 요청/응답을 가로채어 필요한 로직을 수행할 수 있습니다.
반면, AOP(Aspect-Orented Programming)은 관점 지향 프로그래밍으로 횡단 관심사를
핵심 관심사(core concerns) 분리하여 구현하는 기법입니다.
따라서 HandlerInterceptor 는 AOP 와는 개념적으로 다르지만 AOP 유사한 효과를 얻을 수 있는 기능 입니다.
AuthInterceptor.java
package com.tencoding.bank.config;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.tencoding.bank.handler.exception.CustomRestfulException;
import com.tencoding.bank.repository.model.User;
import com.tencoding.bank.util.Define;
@Component // IoC 대상 - 싱글톤으로 관리 된다.
public class AuthInterceptor implements HandlerInterceptor{
// Controller 들어가기 전에 호출 되는 메서드
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle() 메서드 호출");
HttpSession session = request.getSession();
User principal = (User)session.getAttribute(Define.PRINCIPAL);
if(principal == null) {
throw new CustomRestfulException("로그인을 먼저 해주세요.", HttpStatus.UNAUTHORIZED);
}
return true;
}
// 뷰가 렌더링 되기 전에 호출되는 메서드
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
}
// // 요청 처리가 완료된 후, 즉, 뷰 렌더링이 완료된 후에 호출되는 메서드
// @Override
// public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
// @Nullable Exception ex) throws Exception {
// }
}
WebMvcConfig.java
package com.tencoding.bank.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Component // IoC 대상 - 2개 이상의 빈을 등록해야 할 때 사용
public class WebMvcConfig implements WebMvcConfigurer{
// DI 처리
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/account/**");
}
}
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.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.tencoding.bank.dto.DepositFormDto;
import com.tencoding.bank.dto.HistoryDto;
import com.tencoding.bank.dto.SaveFormDto;
import com.tencoding.bank.dto.TransferFormDto;
import com.tencoding.bank.dto.WithDrawFormDto;
import com.tencoding.bank.handler.exception.CustomRestfulException;
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);
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. 인증 여부 확인
return "account/save";
}
/**
* 계좌 생성 로직 구현
* @return
*/
@PostMapping("/save")
public String saveProc(SaveFormDto saveFormDto) {
// 1. 인증 검사
User user = (User)session.getAttribute(Define.PRINCIPAL);
// 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. 인증 여부 확인
return "account/withdraw";
}
// body -> String --> amount=1000&wAccountId=10&......
@PostMapping("/withdraw")
public String withdrawProc(WithDrawFormDto withDrawFormDto) {
// 1. 인증 여부 확인
User user = (User)session.getAttribute(Define.PRINCIPAL);
// 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. 인증 여부 확인
return "account/deposit";
}
@PostMapping("/deposit")
public String depositProc(DepositFormDto depositFormDto) {
// 1. 인증 여부 확인
// 2. 유효성 검사
if(depositFormDto.getAmount() == null) {
throw new CustomRestfulException("금액을 입력해주세요.", HttpStatus.BAD_REQUEST);
}
if(depositFormDto.getAmount() <= 0) {
throw new CustomRestfulException("잘못된 금액입니다.", HttpStatus.BAD_REQUEST);
}
if(depositFormDto.getDAccountNumber() == null
|| depositFormDto.getDAccountNumber().isEmpty()) {
throw new CustomRestfulException("입금 계좌번호를 입력해주세요.", HttpStatus.BAD_REQUEST);
}
accountService.updateAccountDeposit(depositFormDto);
return "redirect:/account/list";
}
// 이체 페이지
// http://localhost:80/account/transfer
@GetMapping("/transfer")
public String transfer() {
// 1. 인증 여부 확인
return "account/transfer";
}
// 1. 이체 금액 0원 이상 입력 여부 확인
// 2. 출금 계좌 번호 입력 여부 확인
// 3. 입금 계좌 번호 입력 여부 확인
// 4. 출금 계좌 비밀 번호 입력 여부 확인
@PostMapping("/transfer")
public String transferProc(TransferFormDto transferFormDto) {
// 1. 인증 여부 확인
User user = (User)session.getAttribute(Define.PRINCIPAL);
// 2. 유효성 검사
if(transferFormDto.getAmount() == null) {
throw new CustomRestfulException("이체 금액을 입력해주세요.", HttpStatus.BAD_REQUEST);
}
if(transferFormDto.getAmount() <= 0) {
throw new CustomRestfulException("이체 금액이 0원 이하일 수 없습니다.", HttpStatus.BAD_REQUEST);
}
if(transferFormDto.getWAccountNumber() == null
|| transferFormDto.getWAccountNumber().isEmpty()) {
throw new CustomRestfulException("출금 계좌번호를 확인해주세요.", HttpStatus.BAD_REQUEST);
}
if(transferFormDto.getDAccountNumber() == null
|| transferFormDto.getDAccountNumber().isEmpty()) {
throw new CustomRestfulException("입금 계좌번호를 확인해주세요.", HttpStatus.BAD_REQUEST);
}
if(transferFormDto.getWAccountPassword() == null
|| transferFormDto.getWAccountPassword().isEmpty()) {
throw new CustomRestfulException("출금 계좌 비밀번호를 확인해주세요.", HttpStatus.BAD_REQUEST);
}
// 3. 서비스 호출
accountService.updateAccountTransfer(transferFormDto, user.getId());
return "redirect:/account/list";
}
// TODO - 수정하기
// 상세 보기 페이지
// http://localhost:80/account/detail/1?type=all,deposit,withdraw
@GetMapping("/detail/{id}")
public String detail(@PathVariable Integer id,
@RequestParam(name = "type", defaultValue = "all", required = false) String type, Model model) {
// Todo - 주소 설계 추가하기
// 1. 인증 여부 확인
User user = (User)session.getAttribute(Define.PRINCIPAL);
// 서비스 호출
Account account = accountService.readAccount(id);
List<HistoryDto> historyList = accountService.readHistoryListByAccount(id, type);
model.addAttribute("principal", user);
model.addAttribute("account", account);
model.addAttribute("historyList", historyList);
System.out.println(historyList);
// Account <-
// List -> History <-
return "account/detail";
}
}