ResponseDto
class
package api.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ResponseDto<T> {
private T data;
private String message;
}
ApiErrorCode
enum
package api.enums;
import lombok.Getter;
import org.springframework.http.HttpStatus;
import java.util.Arrays;
/**
* ApiErrorCode 주석
*
* ERROR_CODE 넘버링 : DOMAIN1(1) / DOMAIN2(2) / DOMAIN3(3) / ... / COMMON(8) / EXTERNAL(9)
*/
@Getter
public enum ApiErrorCode {
// 1. DOMAIN1
// 1.1. sub-domain1
// 1.2. sub-domain2
// 1.3. sub-domain3
SUBDOMAIN_ONE_NOT_FOUND("1101", HttpStatus.NOT_FOUND, "error message 1"),
SUBDOMAIN_TWO_ERROR("1201", HttpStatus.NOT_FOUND, "error message 2"),
AUTH_INVALID("1301", HttpStatus.UNAUTHORIZED, "error message 3"),
// 8. COMMON
METHOD_NOT_ALLOWED("8001", HttpStatus.METHOD_NOT_ALLOWED, "Not Allowed Request"),
TOO_MANY_REQUESTS("8002", HttpStatus.TOO_MANY_REQUESTS, "Too Many Requests"),
OTHER_ERROR("8003", HttpStatus.INTERNAL_SERVER_ERROR, "Unknown Server Error"),
SERVICE_UNAVAILABLE("8004", HttpStatus.SERVICE_UNAVAILABLE, "Service Under Inspection"),
INVALID_TYPE("8005", HttpStatus.BAD_REQUEST, "Unavailable Type"),
// 9. EXTERNAL
// 9.1. DB
// 9.2. CONVERTOR
// 9.3. ES
CONNECT_TIMEOUT("9003", HttpStatus.INTERNAL_SERVER_ERROR, "Connection Delay to External Server"),
RESPONSE_TIMEOUT("9004", HttpStatus.INTERNAL_SERVER_ERROR, "Response Delay to External Server"),
DB_ERROR("9101", HttpStatus.INTERNAL_SERVER_ERROR, "Database Error occur"),
PDF_CONVERSION_ERROR("9201", HttpStatus.INTERNAL_SERVER_ERROR, "Pdf Conversion Error"),
HTML_CONVERSION_ERROR("9202", HttpStatus.INTERNAL_SERVER_ERROR, "Html Conversion Error"),
UNKNOWN_CONVERSION_ERROR("9203", HttpStatus.INTERNAL_SERVER_ERROR, "Unknown Conversion Error"),
UNKNOWN_ES_ERROR("9301", HttpStatus.INTERNAL_SERVER_ERROR, "Unknown ES Error"),
OTHER_NETWORK_ERROR("9999", HttpStatus.INTERNAL_SERVER_ERROR, "Unknown Error to External Server");
private final String errorCode;
private final HttpStatus httpStatus;
private final String message;
ApiErrorCode(String errorCode, HttpStatus httpStatus, String message) {
this.errorCode = errorCode;
this.httpStatus = httpStatus;
this.message = message;
}
public static ApiErrorCode findByErrorCode(String errorCode){
return Arrays.stream(values())
.filter(e -> e.getErrorCode().equals(errorCode))
.findAny()
.orElse(null);
}
}
ErrorResponseDto
class
package api.common.dto;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@Builder
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ErrorResponseDto {
private String timeStamp;
private String errorCode;
private String errorMessage;
private String moreInfo;
}
ExceptionController
class
package api.exception;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import feign.FeignException;
import io.jsonwebtoken.JwtException;
import api.common.dto.ErrorResponseDto;
import api.enums.ApiErrorCode;
import api.common.dto.ResponseDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.persistence.EntityNotFoundException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 전역 Exception Handler
* */
@Slf4j
@RestControllerAdvice
public class ExceptionController{
private final ObjectMapper objectMapper;
public ExceptionController(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@ExceptionHandler(IOException.class)
public ResponseEntity<ErrorResponseDto> handleIOException(IOException e) {
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(
ErrorResponseDto.builder()
.timeStamp(String.valueOf(LocalDateTime.now()))
.errorCode(e.getMessage())
.errorMessage(ApiErrorCode.FILE_NOT_FOUND.getMessage())
.build()
);
}
@ExceptionHandler({
NoMatchExtException.class,
NoSuchElementException.class,
EntityNotFoundException.class,
NotFoundException.class,
IllegalArgumentException.class,
JwtException.class,
IllegalStateException.class,
DuplicateException.class,
})
public ResponseEntity<ErrorResponseDto> handleNoMatchExtException(RuntimeException e) {
String paramCode = e.getMessage();
ApiErrorCode apiErrorCode = ApiErrorCode.findByErrorCode(paramCode);
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
Enumeration<String> parameterList = request.getParameterNames();
while(parameterList.hasMoreElements()){
String parameter = parameterList.nextElement();
log.error("Request Parameter Name : " + parameter + "\\tRequest Parameter Value : " + request.getParameter(parameter));
}
return ResponseEntity.status(apiErrorCode.getHttpStatus()).body(
ErrorResponseDto.builder()
.timeStamp(String.valueOf(LocalDateTime.now()))
.errorCode(apiErrorCode.getErrorCode())
.errorMessage(apiErrorCode.getMessage()).build()
);
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<ResponseDto<Object>> handleRuntimeException(RuntimeException e){
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ResponseDto.builder()
.data(e.getMessage())
.build()
);
}
@ExceptionHandler(FeignException.class)
public ResponseEntity<ErrorResponseDto> handlePaperConvertException(FeignException feignException){
log.error(feignException.getMessage(), feignException);
ApiErrorCode apiErrorCode = ApiErrorCode.UNKNOWN_CONVERSION_ERROR;
try {
String responseError = feignException.contentUTF8();
Map<String, Object> responseMap = objectMapper.readValue(responseError, Map.class);
ArrayList<String> detailMessage = (ArrayList<String>) responseMap.get("detailMessage");
String errorMessage = detailMessage.stream().filter(message -> message.contains("[ERROR]")).collect(Collectors.joining("\\n"));
return ResponseEntity.status(apiErrorCode.getHttpStatus()).body(
ErrorResponseDto.builder()
.timeStamp(String.valueOf(LocalDateTime.now()))
.errorCode(apiErrorCode.getErrorCode())
.errorMessage(errorMessage).build()
);
} catch (IOException ex) { // json 파싱 실패
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(
ErrorResponseDto.builder()
.timeStamp(String.valueOf(LocalDateTime.now()))
.errorCode(ApiErrorCode.OTHER_NETWORK_ERROR.getErrorCode())
.errorMessage(ex.getMessage()).build());
}
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ResponseDto<Object>> exception(RuntimeException e){
log.error(e.getMessage(), e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ResponseDto.builder()
.data(e.getMessage())
.build()
);
}
}