일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 개발자
- 리엑트
- 스프링
- 국비지원
- react-native
- 비전공자
- 클론코딩
- 리엑트 네이티브
- 풀스택 개발자
- Redux
- 상태관리
- Spring
- 프론트 엔드
- spring boot
- 인스타그램
- 비전공
- 프론트엔드
- 백엔드
- 국비 지원
- 스타트업
- 풀스택
- ffmpeg
- react
- Java
- 개발
- react native
- 자바
- expo
- 코딩
- 스프링 부트
- Today
- Total
오티스의개발일기
[SPRING BOOT + REACT NATIVE] 인스타그램 클론 코딩 (6) aop 와 customException 설정하기 -git 참조- 본문
[SPRING BOOT + REACT NATIVE] 인스타그램 클론 코딩 (6) aop 와 customException 설정하기 -git 참조-
안되면 될때까지.. 2022. 12. 29. 14:34
< 이전글
다음글 >
이번 시간에는 저번시간에 이어
aop 와 customException 을 설정해 볼것이다.
시작하기에 앞서 이전 포스팅에 aop 와 customException 에대해 포스팅한적이있다.
이것에대해 잘모른다면 먼저 참고하고 오자
1. aop
2022.12.29 - [개발/spring boot] - [SPRING BOOT] aop 를 활용하여 request요청 log찍기
2.customException
그럼 시작해보겠다.
# 0 . aop 와 customException 에 대해서
1. aop
우리는 이 aop를 사용하여 매번 오는 request 의 로그를 출력할것이다.
2. customException
그전시간에 만든 Controller 이후 이제 service 단을 생성할차례인데
service 단에서 우리가 의도한 예외상황이 발생했을시 우리가원하는 HttpStatus 와
메시지를 클라이언트 단에 전송하기위함의 작업이다.
# 1 . 흐름
1. aop
사용자가 데이터 요청을한다
Request: POST http://localhost:8080/api/user/register: (2ms)
로그인 이런 형식의 로그를 찍어준다
{요청인지 반환인지} : {메서드 종류} {요청한 uri} {걸린시간}
2. customException
예를들어 사용자가 로그인 요청을 시도하였을때
우리가 백엔드에서 해야할일은
아이디와 비밀번호가 일치하는 회원이 있는지?
있으면 코드 200 과 정상처리
없으면 원래는 nullpointException 혹은 또다른 예외가 걸리면서 서버가 정지되거나
클라이언트 단에 저 오류가 그대로 노출될것이다
그러기에 우리는 customException 을 따로만들어
"에러코드 : 400, 아이디 혹은 비밀번호가 잘못됬습니다."
라는 데이터를 넘겨줄수있다.
일단 그전에 이것에대해 다룬 포스팅이 있으므로
보고 따라하기 바란다
이포스팅에는 단순 작업한 코드만 올려놓도록 하겠다
# 2. 폴더 구조
# 3. LogAdvice.java 생성
package com.example.backend.common.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Component
@Aspect
public class LogAdvice {
private static final Logger logger = LoggerFactory.getLogger(LogAdvice.class);
@Bean
public RequestContextListener requestContextListener(){ return new RequestContextListener();}
// 어디에 관심이 있는지 등록
@Pointcut("within(com.example.backend.controller..*)")
public void onRequest() {
}
// 위에 만든 onRequest가 동작할시 requestLogging 동작함
@Around("com.example.backend.common.aop.LogAdvice.onRequest()")
public Object requestLogging(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
HttpServletRequest request = null;
try {
request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
} catch (IllegalStateException e) {
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}
long start = System.currentTimeMillis();
try {
return proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
} finally {
long end = System.currentTimeMillis();
logger.info("Request: {} {}: ({}ms)", request.getMethod(), request.getRequestURL(), end - start);
}
}
}
# 4. CustomApiException.java 생성
package com.example.backend.common.exception;
import lombok.Data;
import org.springframework.http.HttpStatus;
@Data
public class CustomApiException extends RuntimeException{
private static final long serialVersionUID = 1L;
public String message;
public HttpStatus httpStatus;
public CustomApiException(String message, HttpStatus httpStatus) {
super(message);
this.message = message;
this.httpStatus = httpStatus;
}
}
이곳이 실직적으로 UserService 에서 호출하는 클래스이다.
# 5. ApiExceptionHandler.java 생성
package com.example.backend.common.handler;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.dto.CMRespDto;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice
@RequiredArgsConstructor
public class ApiExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(ApiExceptionHandler.class);
@ExceptionHandler(CustomApiException.class)
public ResponseEntity<?> customApiException(CustomApiException e, HttpServletRequest request) {
logger.error("Request: {} {})", request.getMethod(), request.getRequestURL());
return new ResponseEntity<>(
new CMRespDto<>(
e.httpStatus.value(),
e.message,
null),
HttpStatus.BAD_REQUEST);
}
}
이곳은 CustomApiException 이 호출되는 순간 연결되어 핸들링되는 클래스이다.
# 6. ValidationExceptionHandler.java 생성
package com.example.backend.common.handler;
import com.example.backend.common.aop.LogAdvice;
import com.example.backend.dto.CMRespDto;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import javax.servlet.http.HttpServletRequest;
@ControllerAdvice
@RequiredArgsConstructor
public class ValidationExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(LogAdvice.class);
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> validationApiException(MethodArgumentNotValidException e, HttpServletRequest request) {
logger.error("Request: {} {})", request.getMethod(), request.getRequestURL());
return new ResponseEntity<>(
new CMRespDto<>(
HttpStatus.BAD_REQUEST.value(),
e.getBindingResult().getAllErrors().get(0).getDefaultMessage(),
null),
HttpStatus.BAD_REQUEST);
}
}
이곳은 dto 에서 정규식이 틀렸을때 호출되는 핸들러이다
정규식이란
@NotNull 등 Dto 변수 위에 어노테이션으로 붙어있는것을 말한다.
# 7. UserService.java 생성
package com.example.backend.service;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.dto.user.request.RequestUserRegisterDto;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public void register (RequestUserRegisterDto requestUserRegisterDto) {
if (requestUserRegisterDto.getUserName().equals("홍길동")) {
throw new CustomApiException("홍길동은 이름이 될수 없습니다.", HttpStatus.BAD_REQUEST);
}
}
}
임시 테스트를 위해 홍길동이란 이름으로 요청이 들어왔을때 커스텀예외가 실행되도록 설정하였다.
# 8. UserController.java 생성
package com.example.backend.controller;
import com.example.backend.common.exception.CustomApiException;
import com.example.backend.dto.CMRespDto;
import com.example.backend.dto.user.request.RequestUserRegisterDto;
import com.example.backend.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@RestController
@RequiredArgsConstructor
@CrossOrigin(origins = {"*"})
@RequestMapping("/api/user")
public class UserController {
private final UserService userService;
@PostMapping("/register")
public CMRespDto<?> register (@Valid @RequestBody RequestUserRegisterDto requestUserRegisterDto) {
userService.register();
return new CMRespDto<>(200, "회원 가입", requestUserRegisterDto);
}
}
컨트롤러이다 아무런 문제가없으면 코드 200 과 회원가입이라는 메시지 그리고 받은 파라미터가 그대로 반환되도록 설정하였다.
이름을 홍길동이라고했을때
예외가 생성되도록 UserService에 작성해놨다.
의도한대로 결과가 나오는것을 볼수있다.
또한 로그도 잘찍히는걸 볼수있다.
이번에는 홍길동말고 다른이름을 써보자
정상적으로 코드 200과 회원가입이라는 메시지를 볼수있다
또한 로그도 잘찍힌다.
이것으로 aop 와 customException 포스팅을 마치도록 하겠다.
다음시간에는
QuerydslRepositorySupport & JpaRepository
에대해 포스팅 해보겠다
다음 포스팅은 실직적으로 데이터베이스에 들어온 요청에대해 회원가입을 하는 로직을 구성해볼것이다.
아래에 참조할수있는 깃이 있으니 참조바란다.
https://github.com/1domybest/react-native-ig-clone.git
다음글 >