상품 주문 서비스 프로젝트
목차
프로젝트 간단 요약
상용 가능한 상품 주문 서비스 API를 만들기 위한 프로젝트
- REST API로 요청과 응답을 JSON으로 처리
- 스프링부트로 MVC 처리
- 스프링 시큐리티를 이용해 권한과 인가 처리
- JWT을 이용한 토큰 기반 인증 처리
- Spring Data JPA로 영속 계층 처리
사용한 기술 스택
Spring Boot
Spring Security
Spring Data JPA
MySQL
JWT
JUnit
프로젝트 정보
| 진행기간 | 목표 |
| --- | --- | --- |
| 2023-04-092023-04-10 | 프로젝트 설계 및 기본 구현 |2023-04-18 | 유저 기능, AOP 설계 및 구현 |
| 2023-04-10
| 2023-04-18~2023-04-21 | 상품, 주문 기능 설계 및 구현 |
프로젝트 구조
- ERD
- 패키지 다이어그램
- 클래스 다이어그램
- 시퀀스 다이어그램
- 사용자 회원가입
- 사용자 회원가입
상품 등록
상품 주문
프로젝트 설명
개요
- 공통 모듈 / 공통 유틸리티
- 사용자 권한 열거형 이용
- Auditing 기능을 사용한 자동 타임스탬프 생성
- 자주 사용하는 유틸을 모아둔 유틸 클래스
- MyDateUtil
- LocalDateTime타입을 DTO 반환을 위해 String으로 변환해주는 클래스
- MyResponseUtil
- 응답 DTO 클래스로 응답 DTO 작성시 사용하는 클래스로 성공을 응답하거나 실패를 응답한다.
- MyDateUtil
- AOP
- MyErrorLogAdvice
- @MyErrorLogRecord 커스텀 어노테이션 작성해, 로그인한 유저의 예외 발생시 자동으로 로깅처리
- MyValidationAdvice
- PostMapping과 PutMapping에 대해서 @Valid가 붙은 경우 유효성 검사 수행하고, Errors 객체에 결과를 담는다.
- MyExceptionHandler의 예외처리 메서드에 모두 @MyErrorLogRecord를 붙여서 예외발생시 기록하도록 한다.
- MyErrorLogAdvice
- 토큰을 이용한 인증
- 헤더에 JWT 토큰 노출
//(1) JS코드로 토큰에 접근해서 클라이언트의 로컬영역에 저장할 수 있도록 설정해야한다. (기본값이 disable) //(2) 실제 서버에서는 JWT 탈취 위험성 때문에 보안조치가 필요하다. //(3) 기본값은 cors-safelisted reponse header만 노출 configuration.addExposedHeader("Authorization");
- ApplicationListener로 로그인 로깅 구현
@Bean public ApplicationListener<AuthenticationSuccessEvent> authenticationSuccessListener() { return (ApplicationListener<AuthenticationSuccessEvent>) event -> { Authentication authentication = event.getAuthentication(); log.debug("디버그 : onAuthenticationSuccess 호출됨"); // 1. 로그인 유저 정보 가져오기 LoginUser userDetails = (LoginUser) authentication.getPrincipal(); User loginUser = userDetails.getUser(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); // 2. 최종 로그인 날짜 기록 (더티체킹 - update 쿼리 발생) // loginUser.(LocalDateTime.now()); // 3. 로그 테이블 기록 LoginLog loginLog = LoginLog.builder() .userId(loginUser.getId()) .userAgent(request.getHeader("User-Agent")) .clientIP(request.getRemoteAddr()) .build(); loginLogRepository.save(loginLog); }; }
- LAZY 로딩과 단방향 매핑을 이용해 쿼리를 수행하도록 한다.
- OrderSheet와 OrderProduct는 일대다 관계로, 단방향 매핑으로 연결
- 연관관계에 있는 두 엔티티는 비즈니스 로직에 따라 유기적으로 동작하도록 작성
- @EntityGraph로 LAZY LOADING 발동 하도록 해서 N+1문제 해결
- 요청과 응답은 반드시 독립적인 DTO로 처리
- 엔티티를 노출시키면 DB 공격에 취약할 수 있으므로 DTO를 이용해 필요한 데이터만 전달
- ResponseDto
- UserReqDto, UserRespDto
- OrderReqDto, OderRespDto
- ProductReqDto, ProductRespDto
- 엔티티를 노출시키면 DB 공격에 취약할 수 있으므로 DTO를 이용해 필요한 데이터만 전달
테스트
테스트시 인증처리 용이하도록 설정
//(1) 테스트를 위한 코드 실행전에 로그인 필요 //(2) 실제 로그인 로직 : jwt -> 인증 필터 -> 시큐리티 세션 생성 //(3) JWT를 이용한 토큰 방식의 로그인보다는, 세션에 직접 LoginUser를 주입하는 방식으로 강제 로그인 진행 // @WithUserDetails(value = "ssar") //DB에서 해당 유저를 조회해서 세션에 담아주는 어노테이션 // setUp()으로 추가 했음에도 setupBefore=TEST_METHOD 에러 발생 //(4) TEST_METHOD 설정시 @WithUserDetails가 setUp() 메서드 수행 전에 실행시간이 같다. //(5) TEST_EXECUTION 설정으로 @WithUserDetails가 setUp() 메서드 수행 후에 실행하도록 한다. @WithUserDetails(value = "ssar", setupBefore = TestExecutionEvent.TEST_EXECUTION) //DB에서 해당 유저를 조회해서 세션에 담아주는 어노테이션
테스트를 위한 더미 오브젝트 작성
더미 오브젝트는 단위테스트를 위해 id를 명시적으로 지정한다.
public class DummyObject { //모두 스태틱 메서드 protected User newUser(String username){ BCryptPasswordEncoder passwordEncoder= new BCryptPasswordEncoder(); String encPassword = passwordEncoder.encode("1234"); return User.builder() .username(username) // .password("1234") .password(encPassword) .email(username+"@nate.com") .role(UserEnum.CUSTOMER) .build(); } protected static User newMockUser(Long id,String username){ BCryptPasswordEncoder passwordEncoder= new BCryptPasswordEncoder(); String encPassword = passwordEncoder.encode("1234"); return User.builder() .id(id) .username(username) // .password("1234") .password(encPassword) .email(username+"@nate.com") .role(UserEnum.CUSTOMER) .build(); }
모키토 통합 테스트시 사용하는 어노테이션
@ActiveProfiles("test") //(1) dev 모드에서 발동하는 DummyInit의 유저가 삽입되므로, 테스트에서 test 프로퍼티파일 사용하도록 하는 설정 //@Transactional @Sql("classpath:db/teardown.sql") //(2) 테스트코드에서는 @Transactional 어노테이션 사용하는 대신, // 외래키 제약조건 해제 후, 테이블 truncate 수행한다음 다시 외래키 제약조건 설정 @AutoConfigureMockMvc //(3) 모키토 환경에서 MockMvc 객체를 사용하기 위한 어노테이션 @SpringBootTest(webEnvironment = WebEnvironment.MOCK) //(4) 웹 애플리케이션을 위한 Mock 객체를 빈으로 주입해주는 어노테이션
'Server Programming > BackEnd Project' 카테고리의 다른 글
[패스트캠퍼스 백엔드 개발자 부트캠프] 5. 기자단 중간 회고 (1) | 2023.05.18 |
---|---|
138일자 - TIL (0) | 2023.04.28 |
[패스트캠퍼스 백엔드 개발자 부트캠프] 3. 서버의 진화 과정과 보안 (0) | 2023.04.03 |
108일자 - TIL (0) | 2023.03.31 |
101일차 -TIL (0) | 2023.03.23 |