@ExceptionHandler
설정
에러 처리는 @ExceptionHandler
를 통해 처리하도록 구성
크리티컬한 에러는 Dooray 메신저로 에러 전송을 하도록 구성함
자세한 내용은 Dooray 메신저 에러 전송 설정 가이드 참조
https://parkingcloud.dooray.com/project/2525192394467198586?contentsType=wiki&pageId=2608604964277753769
exception 패키지 구조
Imis V2 API의 exception
패키지 구조를 참조
common
: 공통 Exception 처리 패키지imisFile
: ImisFileController의 Exception 처리를 위한 패키지excel
: excel component Exception 처리를 위한 패키지jooq
: jooq Exception 처리를 위한 패키지
ErrorUtil
@ExceptionHandler
에 출력할 에러 메세지를 가공하는 Util
getErrorMap
@ExceptionHandler
를 통해 전달 받은 HttpServletRequest
에서 요청정보 데이터를 추출하여 ErrorMap에 담아서 리턴 해준다
ErrorMap에 담긴 요청 정보는 에러 메시지를 로그로 남길 때 표출 해준다
/**
* Error Map 생성
* 에러 메세지 맵을 생성하여 메신저에 전송한다
* @param errorMap
* @param request
* @return
*/
public static Map<String, Object> getErrorMap(Map<String, Object> errorMap, HttpServletRequest request) {
if(errorMap == null) errorMap = new LinkedHashMap<>();
errorMap.put("Request URI",request.getRequestURI());
errorMap.put("HttpMethod",request.getMethod());
errorMap.put("Servlet Path",request.getServletPath());
errorMap.put("Client IP",request.getLocalAddr());
errorMap.put("QueryString",request.getQueryString());
errorMap.put("Parameters",request.getParameterMap());
return errorMap;
}
errorWriter
log.error
메세지 가공 및 출력 Util
errorWriter
를 통해 출력된 에러 메세지는 Dooray 메신저로 전송된다
크리티컬한 에러에 대해서만 처리되도록 한다
/**
* 에러메세지 출력
* @param CLASS_NAME
* @param ERROR_MSG
* @param errorMap
* @param e
*/
public static void errorWriter(String CLASS_NAME, String ERROR_MSG, Map<String, Object> errorMap, Exception e){
log.error("[{}] ERROR 메세지 :: {}\n\n요청 정보 ::\n{}\n\nException ::\n{}",CLASS_NAME,ERROR_MSG,JsonUtils.toJson(errorMap),e.getMessage(),e);
}
warnWriter
log.warn
메세지 가공 및 출력 Util
warnWriter
를 통해 출력된 에러 메세지는 Dooray 메신저로 전송되지 않으며
로그에만 기록이 된다
일반적으로 크리티컬하지 않으며 커스텀한 @ExceptionHandler
를 통해 예외처리 한 WARN로그를 기록하는 용도로 사용한다
/**
* WARN 에러메세지 출력
* @param CLASS_NAME
* @param ERROR_MSG
* @param errorMap
* @param errorMsg
*/
public static void warnWriter(String CLASS_NAME, String ERROR_MSG, Map<String, Object> errorMap, String errorMsg){
log.warn("[{}] WARN 메세지 :: {}\n\n요청 정보 ::\n{}\n\nException ::\n{}",CLASS_NAME,ERROR_MSG,JsonUtils.toJson(errorMap),errorMsg);
}
infoWriter
log.info
메세지 가공 및 출력 Util
infoWriter
를 통해 출력된 에러 메세지는 Dooray 메신저로 전송되지 않으며
로그에만 기록이 된다
일반적으로 크리티컬하지 않으며 커스텀한 @ExceptionHandler
를 통해 예외처리 한 INFO 로그를 기록하는 용도로 사용한다
/**
* INFO 에러메세지 출력
* @param CLASS_NAME
* @param ERROR_MSG
* @param errorMap
* @param errorMsg
*/
public static void infoWriter(String CLASS_NAME, String ERROR_MSG, Map<String, Object> errorMap, String errorMsg){
log.info("[{}] INFO 메세지 :: {}\n\n요청 정보 ::\n{}\n\nException ::\n{}",CLASS_NAME,ERROR_MSG,JsonUtils.toJson(errorMap),errorMsg);
}
common
common 패키지에는 공통 Exception Handler 와 공통 Exception 클래스가 위치함
서버에서 발생한 예외처리 하지 못한 크리티컬한 Exception에 대해 모두 처리한다
/**
* Handler 에서 예외처리 되지 않은 Exception 처리
* @param e
* @return
*/
@ExceptionHandler(Exception.class)
public CommonResult allException(Exception e, HttpServletRequest request, WebRequest webRequest) throws IOException {
String ERROR_MSG = e.getMessage();
setErrorMap(request, webRequest); // ErrorMap 기본 셋팅
ErrorUtils.errorWriter("",ERROR_MSG,errorMap,e); //에러메세지 출력
return new CommonResult<>(ERROR, ERROR_MSG, null);
}
setErrorMap
Handler 에서 추가로 ErrorMap에 추가할 데이터를 셋팅 해준다
/**
* Exception Handler ErrorMap 기본 셋팅
* @param request
* @throws IOException
*/
private void setErrorMap(HttpServletRequest request, WebRequest webRequest) throws IOException {
errorMap = ErrorUtils.getErrorMap(errorMap, request); //에러 맵 생성
errorMap.put("Request USER ID",AuthUtils.getUserId(request.getHeader("jwt"), secretKey));
errorMap.put("Request Body",webRequest.getAttribute("body", RequestAttributes.SCOPE_REQUEST));
}
custom
custom 패키지에는 공통 이외에 각 업무별 컨트롤러의 Handler를 아래와 같은 형식으로 작성하면 된다
기본적으로 예외처리 하지 못한 Exception에 대해 처리하는 @ExceptionHandler
와 각 Exception별 @ExceptionHandler
처리를 하면 된다
작성 요령은 아래의 작성 내용을 참조 하면 된다
커스텀 에러 핸들러 작성시 주의 할 점
@Order(Ordered.HIGHEST_PRECEDENCE)
어노테이션으로 실행순서를 commonErrorHandler
보다 먼저 실행 되도록 설정한다
/**
* Created by KMS on 05/11/2019.
* ImisFileController 에러 핸들러
*/
@Slf4j
@RestControllerAdvice(assignableTypes = {ImisFileController.class})
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ImisFileErrorHandler {
private String CLASS_NAME = "ImisFileController";
private Map<String, Object> errorMap = new LinkedHashMap<>();
@Value("${jwt.secret-key}")
String secretKey;
private RequestContext requestContext;
/**
* 임시 파일 적용 시 BODY가 없을 때
* @param e
* @param request
* @return
* @throws IOException
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public CommonResult requestBodyError(HttpMessageNotReadableException e, HttpServletRequest request, WebRequest webRequest) throws IOException {
String ERROR_MSG = "TEMP 파일을 적용할 RequestBody가 없습니다";
setImisFileErrorMap(request, webRequest); // ImisFile ErrorMap 기본 셋팅
ErrorUtils.warnWriter(CLASS_NAME,ERROR_MSG,errorMap,e.getMessage()); //에러메세지 출력
return new CommonResult<>(FILE_TEMP_APPLY_FAILED, ERROR_MSG, null);
}
/**
* 필수 파라메터 체크
* @param e
* @return
*/
@ExceptionHandler(ImisFileRequestParamRequiredException.class)
public CommonResult ImisFileRequestParamRequiredException(ImisFileRequestParamRequiredException e, HttpServletRequest request, WebRequest webRequest) throws IOException {
String ERROR_MSG = e.getMessage();
setImisFileErrorMap(request, webRequest); // ImisFile ErrorMap 기본 셋팅
ErrorUtils.warnWriter(CLASS_NAME,ERROR_MSG,errorMap,e.getMessage()); //에러메세지 출력
return new CommonResult<>(FILE_DUPLACATE, ERROR_MSG, null);
}
/**
* 지정 되지 않은 에러 발생 시 처리
* @param e
* @param request
* @return
* @throws IOException
*/
@ExceptionHandler(Exception.class)
public CommonResult imisFileException(Exception e, HttpServletRequest request, WebRequest webRequest) throws IOException {
String ERROR_MSG = e.getMessage();
setImisFileErrorMap(request, webRequest); // ImisFile ErrorMap 기본 셋팅
ErrorUtils.errorWriter(CLASS_NAME,ERROR_MSG,errorMap,e); //에러메세지 출력
return new CommonResult<>(ERROR, ERROR_MSG, null);
}
/**
* ImisFile Exception Handler ErrorMap 기본 셋팅
* @param request
* @param webRequest
* @throws IOException
*/
private void setImisFileErrorMap(HttpServletRequest request, WebRequest webRequest) throws IOException {
errorMap = ErrorUtils.getErrorMap(errorMap, request); //에러 맵 생성
errorMap.put("Request USER ID",AuthUtils.getUserId(request.getHeader("jwt"), secretKey));
errorMap.put("Request Body",webRequest.getAttribute("reqImisFileTempApply", RequestAttributes.SCOPE_REQUEST));
}
}
특정 컨트롤러에 대한 @ExceptionHandler
특정 컨트롤러에서 발생한 Exception을 처리하고 싶으면
아래와 같이 assignableTypes
에 해당 컨트롤러 클래스를 지정해주면 된다
@RestControllerAdvice(assignableTypes = {ImisFileController.class})
@ExceptionHandler
에 @RequestBody
요청 값 전달하기
@RequestBody
요청 값에 대해서는 일반적인 방법으로는 @ExceptionHandler
에서 값을 받아오기가 번거롭다
하지만 WebRequest
를 이용해서 attribute에 포함시키면 @ExceptionHandler
로 @RequestBody
요청 값을 쉽게 받아올 수 있다
1. Controller
에 WebRequest
를 파라메터로 추가
컨트롤러에 아래와 같이
WebRequest
를 파라메터로 추가 한다WebRequest
에 전달받은 Body 객체를RequestAttributes.SCOPE_REQUEST
에 body라는 키 명으로setAttribute
한다@PostMapping("/temp") public CommonResult<List<ResImisFile>> postTempFiles( @RequestHeader(value = "jwt", required = true) String jwt, @RequestBody(required = true) ReqImisFileTempApply reqImisFileTempApply, WebRequest webRequest ) throws Exception { // requestBody가 있는 경우 SCOPE_REQUEST에 attribute를 등록하면 exceptionHandler에서 값을 받아 올 수 있다 webRequest.setAttribute("body", reqImisFileTempApply, RequestAttributes.SCOPE_REQUEST); // TEMP 파일 적용 서비스 호출 return service.applyTempFile(jwt, reqImisFileTempApply); }
WebRequest
를 파라메터로 추가하면 Swagger에서 WebRequest
파라메터 항목이 표출되는데 Swagger에서
해당 파라메터 항목을 제거 하고 싶으면 아래와 같이 Swagger 설정하면된다
return new Docket(DocumentationType.SWAGGER_2)
.ignoredParameterTypes(WebRequest.class) //특정 파라메터 무시하기
2. @ExceptionHandler
에서 @RequestBody
요청 값 받아오기
@ExceptionHandler
에WebRequest
를 파라메터로 추가한다- Controller에서 셋팅한
WebRequest
의RequestAttributes.SCOPE_REQUEST
에
set 했던@RequestBody
attribute 값을 get하면 쉽게 받아올 수 있다
webRequest.getAttribute("body", RequestAttributes.SCOPE_REQUEST)
- 별도로 커스텀
@ExceptionHandler
설정을 하지 않는다면 공통@ExceptionHandler
에는 body라는 키명으로 받아 올 수 있도록 이미 설정되어있다
/**
* 임시 파일 적용 시 BODY가 없을 때
* @param e
* @param request
* @return
* @throws IOException
*/
@ExceptionHandler(value = HttpMessageNotReadableException.class)
public CommonResult requestBodyError(HttpMessageNotReadableException e, HttpServletRequest request, WebRequest webRequest) throws IOException {
String ERROR_MSG = "TEMP 파일을 적용할 RequestBody가 없습니다";
setImisFileErrorMap(request, webRequest); // ImisFile ErrorMap 기본 셋팅
ErrorUtils.warnWriter(CLASS_NAME,ERROR_MSG,errorMap,e.getMessage()); //에러메세지 출력
return new CommonResult<>(FILE_TEMP_APPLY_FAILED, ERROR_MSG, null);
}
setErrorMap
Handler 에서 추가로 ErrorMap에 추가할 데이터를 셋팅 해준다
/**
* ImisFile Exception Handler ErrorMap 기본 셋팅
* @param request
* @param webRequest
* @throws IOException
*/
private void setErrorMap(HttpServletRequest request, WebRequest webRequest) throws IOException {
errorMap = ErrorUtils.getErrorMap(errorMap, request); //에러 맵 생성
errorMap.put("Request USER ID",AuthUtils.getUserId(request.getHeader("jwt"), secretKey));
errorMap.put("Request Body",webRequest.getAttribute("body", RequestAttributes.SCOPE_REQUEST));
}
'프로젝트' 카테고리의 다른 글
[SpringBoot 예외처리] 커스텀 Exception 처리 (0) | 2020.06.20 |
---|---|
[SpringBoot 예외처리] @ExceptionHandler 리팩토링 코드 가이드 (0) | 2020.06.20 |
[SpringBoot 예외처리] Exception 전략 (0) | 2020.06.20 |
[SpringBoot 설정]DB Connection 제외 설정 (0) | 2020.06.20 |
[SpringBoot 설정] CORS 허용 설정 (0) | 2020.06.20 |
댓글