- [Springboot] 30. Intercepter 활용 (인증검사 공통 처리)2024년 08월 13일
- Song hyun
- 작성자
- 2024.08.13.:48
728x90반응형[Springboot] 30. Intercepter 활용 (인증검사 공통 처리)
1. Intercepter란?
(1) Intercepter의 개념:
-인터셉터는 Spring MVC의 핵심 기능 중 하나로, 웹 애플리케이션에서 공통적인 처리를 재사용할 수 있게 해주는 강력한 도구이다.
(2) Intercepter의 활용 사례:
(3) Intercepter의 작동 원리
(4) filter와 intercepter
2. Intercepter 사용해보기
(1) Intercepter 클래스 생성하기
package com.tenco.bank.handler; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @Component // IoC 대상(싱글톤 패턴) public class AuthIntercepter implements HandlerInterceptor{ // prehandle 동작 흐름 (단, 스프링부트 설정 파일/클래스에 등록되어야 한다.) // 컨트롤러 들어오기 전에 동작하는 녀석! // true --> 컨트롤러 안으로 들여 보낸다. // false --> 컨트롤러 안으로 못들어감 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return HandlerInterceptor.super.preHandle(request, response, handler); } // postHandle // 뷰가 렌더링 되기 바로 전에 콜백되는 메서드 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } // afterCompletion // 요청 처리가 완료된 후, 즉 뷰가 완전 렌더링이 된 후에 호출 된다. @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
(2) Controller 전 인증검사 메서드 만들기
package com.tenco.bank.handler; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.tenco.bank.handler.exception.UnAuthorizedException; import com.tenco.bank.repository.model.User; import com.tenco.bank.utils.Define; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpSession; @Component // IoC 대상(싱글톤 패턴) public class AuthIntercepter implements HandlerInterceptor{ // prehandle 동작 흐름 (단, 스프링부트 설정 파일/클래스에 등록되어야 한다.) // 컨트롤러 들어오기 전에 동작하는 녀석! // true --> 컨트롤러 안으로 들여 보낸다. // false --> 컨트롤러 안으로 못들어감 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); User principal = (User) session.getAttribute(Define.PRINCIPAL); if(principal == null) { throw new UnAuthorizedException("로그인 먼저 해주세요.", HttpStatus.UNAUTHORIZED); } return true; } // postHandle // 뷰가 렌더링 되기 바로 전에 콜백되는 메서드 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } // afterCompletion // 요청 처리가 완료된 후, 즉 뷰가 완전 렌더링이 된 후에 호출 된다. @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { HandlerInterceptor.super.afterCompletion(request, response, handler, ex); } }
(3) WebMvcConfigurer을 구현해 인터셉터 등록하기
package com.tenco.bank.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import com.tenco.bank.handler.AuthIntercepter; import lombok.RequiredArgsConstructor; @Configuration // <-- 하나의 클래스를 IOC 하고 싶다면 사용 @RequiredArgsConstructor public class WebMvcConfig implements WebMvcConfigurer { @Autowired // DI private final AuthIntercepter authIntercepter; // @RequiredArgsConstructor <-- 생성자 대신 사용 가능! // 우리가 만든 AuthIntercepter를 등록해야 한다. @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authIntercepter) .addPathPatterns("/account/**") .addPathPatterns("/auth/**"); } }
*AccountController 리팩토링
package com.tenco.bank.controller; import java.util.Arrays; 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.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.SessionAttribute; import org.springframework.web.servlet.ModelAndView; import com.tenco.bank.dto.DepositDTO; import com.tenco.bank.dto.SaveDTO; import com.tenco.bank.dto.TransferDTO; import com.tenco.bank.dto.WithdrawalDTO; import com.tenco.bank.handler.exception.DataDeliveryException; import com.tenco.bank.handler.exception.UnAuthorizedException; import com.tenco.bank.repository.interfaces.AccountRepository; import com.tenco.bank.repository.interfaces.HistoryRepository; import com.tenco.bank.repository.model.Account;import com.tenco.bank.repository.model.HistoryAccount; import com.tenco.bank.repository.model.User; import com.tenco.bank.service.AccountService; import com.tenco.bank.utils.Define; import jakarta.servlet.http.HttpSession; import lombok.RequiredArgsConstructor; @Controller // IoC 대상(싱글톤으로 관리) @RequestMapping("/account") @RequiredArgsConstructor public class AccountController { private final HttpSession session; private final AccountService accountService; /** * 계좌 생성 페이지 요청 * 주소 설계 : http://localhost:8080/account/save * @return save.jsp */ @GetMapping("/save") public String savePage() { return "account/save"; } /** * 계좌 생성 기능 요청 * 주소 설계 : http://localhost:8080/account/save * @param dto * @return */ @PostMapping("/save") public String saveProc(SaveDTO dto, @SessionAttribute(Define.PRINCIPAL) User principal) { // 1. form 데이터 추출(파싱 전략) // 2. 인증 검사 // 3. 유효성 검사 // 4. 서비스 호출 if(dto.getNumber()==null||dto.getNumber().isEmpty()) { throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST); } if(dto.getPassword()==null||dto.getPassword().isEmpty()) { throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST); } if(dto.getBalance()==null||dto.getBalance()<=0) { throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST); } accountService.createAccount(dto,principal.getId()); return "redirect:/account/list"; } /** * 계좌 목록 화면 요청 * 주소 설계: http://localhost:8080/account/list ... * @return list.jsp */ @GetMapping({"/list","/"}) public String listPage(Model model, @RequestParam(name="currentPage", defaultValue="1") Integer currentPage, @RequestParam(name="totalPage", defaultValue="3") Integer totalPage, @SessionAttribute(Define.PRINCIPAL) User principal) { if(currentPage==null) { currentPage=1; } Integer limit=2; // 한 페이지당 내역 수 Integer offset=currentPage; // 몇번부터 뽑을지 // 총 내역 수 Integer totalAccount=(accountService.readAccountListByUserId(principal.getId())).size(); // 총 페이지 수 Integer totalPages=(int)Math.ceil((double)totalAccount/limit); // 페이지별 내역 수 List<Account> accountList=accountService.readAccountListByUserIdForPaging(principal.getId(),limit,currentPage); if(accountList.isEmpty()) { model.addAttribute("accountList",null); } else { model.addAttribute("accountList",accountList); } model.addAttribute("currentPage", currentPage); model.addAttribute("totalPages", totalPages); model.addAttribute("totalPages", totalPages); // JSP 데이터를 넣어주는 방법 return "account/list"; } /** * 출금 페이지 요청 * @return */ @GetMapping("/withdrawal") public String withDrawalPage() { return "account/withdrawal"; } /** * 계좌 출금 요청 * @param dto * @return */ @PostMapping("/withdrawal") public String withDrawalProc(WithdrawalDTO dto, @SessionAttribute(Define.PRINCIPAL) User principal) { // 유효성 검사 (자바 코드를 개발) --> 스프링부트 @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) { throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST); } if(dto.getWAccountPassword()==null) { throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST); } accountService.updateAccountWithdrawal(dto, principal.getId()); return "redirect:/account/list"; } /** * 입금 페이지 요청 */ @GetMapping("/deposit") public String depositPage() { return "account/deposit"; } /** * */ /** * 입금 요청 처리 */ @PostMapping("/deposit") public String depositProc(DepositDTO dto, @SessionAttribute(Define.PRINCIPAL) User principal) { // 입금시 검사해야 할 것 // 1. 계좌가 존재하는지 // 2. 돈이 존재하는지 if (dto.getAmount() == null) { throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST); } if(dto.getAmount()<=0) { throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST); } if(dto.getDAccountNumber()==null) { throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST); } accountService.updateAccountDeposit(dto, principal.getId()); return "redirect:/account/list"; } /** * 이체 페이지 요청 */ @GetMapping("/transfer") public String transferPage() { return "account/transfer"; } /** * */ /** * 이체 요청 처리 */ @PostMapping("/transfer") public String transferProc(TransferDTO dto, @SessionAttribute(Define.PRINCIPAL) User principal) { // 입금시 검사해야 할 것 // 1. 계좌가 존재하는지 // 2. 돈이 존재하는지 System.out.println(dto); // 입금-출금 계좌 중복 여부 확인 확인 if(dto.getDAccountNumber().equals(dto.getWAccountNumber())) { throw new DataDeliveryException(Define.INVALID_INPUT, HttpStatus.BAD_REQUEST); } // 입금 금액 널 확인 if (dto.getAmount() == null) { throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST); } // 입금 금액 - 확인 if(dto.getAmount()<=0) { throw new DataDeliveryException(Define.ENTER_YOUR_BALANCE, HttpStatus.BAD_REQUEST); } // 출금 계좌 널 확인 if(dto.getDAccountNumber()==null) { throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST); } // 입금 계좌 널 확인 if(dto.getWAccountNumber()==null) { throw new DataDeliveryException(Define.ENTER_YOUR_ACCOUNT_NUMBER, HttpStatus.BAD_REQUEST); } // 출금 계좌 비밀번호 널 확인 if(dto.getPassword()==null) { throw new DataDeliveryException(Define.ENTER_YOUR_PASSWORD, HttpStatus.BAD_REQUEST); } accountService.updateAccountTransfer(dto, principal.getId()); return "redirect:/account/list"; } /** * 계좌 상세 보기 페이지 * 주소 설계 : http://localhost:800/account/detail/${1}?type=all, deposit, withdraw * @return */ @GetMapping("/detail/{accountId}") public String detail(@PathVariable(name="accountId") Integer accountId, @RequestParam(required=false, name="type") String type, @RequestParam(name="page", defaultValue = "1") int page, @RequestParam(name="size", defaultValue = "2") int size, Model model) { // 유효성 검사 // arrays.asList() -> array 선언과 동시에 초기화해주는 메서드 // 사용자가 선택한 타입(입출금/입금/출금 검색)을 검사한다. List<String> validTypes=Arrays.asList("all","deposit","withdrawal"); if(!validTypes.contains(type)) { throw new DataDeliveryException("유효하지 않은 접근입니다.", HttpStatus.BAD_REQUEST); } // 페이지 개수를 계산하기 위해서, 총 페이지의 수를 계산해주어야 한다. int totalRecords=accountService.countHistoryByAccountIdAndType(type, accountId); int totalPages=(int)Math.ceil((double)totalRecords/size); // 계좌/내역 정보 Account account = accountService.readAccountById(accountId); List<HistoryAccount> historyList= accountService.readHistoryByAccountId(type, accountId,page,size); model.addAttribute("account",account); model.addAttribute("historyList", historyList); model.addAttribute("currentPage", page); model.addAttribute("totalPages", totalPages); model.addAttribute("type",type); model.addAttribute("size",size); return "account/detail"; } }
728x90반응형'Springboot' 카테고리의 다른 글
[Springboot] 32. 사용자 비밀번호 암호화 처리 (0) 2024.08.13 [Springboot] 31. DB 마이그레이션 (H2->MySQL) (0) 2024.08.13 [Springboot] 29. 계좌 상세 보기 기능(5단계-계좌 목록 페이징 처리) (0) 2024.08.12 [Springboot] 28. 계좌 상세 보기 기능(5단계-정답 코드) (1) 2024.08.12 [Springboot] 27. 계좌 상세 보기 기능(5단계-JSTL 사용 및 페이징 기능) (0) 2024.08.12 다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)