> For the complete documentation index, see [llms.txt](https://tech.x2bee.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tech.x2bee.com/dev-guide/dev-start/interactive-blocks/undefined.md).

# 에러메시지 및 예외 처리

다음은 에러메시지 및 예외 처리에 대해 설명합니다.

***

## 예외 처리

서버에서 Exception이 발생되어 ‘예외 처리’를 하는 경우는 다음과 같습니다.

* 서버 페이지(Next.js)를 호출할 때 (BO 서버 프로젝트)
* Restful API를 호출할 때(API 서버 프로젝트)

일반적인 API서버들의 경우 Common에 있는 GlobalControllerAdvice 및 각각 API 프로젝트의 DisplayControllerAdvice(GlobalControllerAdvice를 상속) 등에서 예외를 처리합니다.

* **GlobalControllerAdvice.class&#x20;**<mark style="color:$danger;">**(해당 파일은 Common에서 작성되며, 이러한 Exception들을 처리하는 것으로 인식하면 됩니다.)**</mark>

GlobalControllerAdvice Class의 경우 공통에서 처리해야 될 예외 사항들을 처리합니다.

일반적인 Exception의 경우 Httpstatus값을 500으로 반환하고 있으며, ValidationException과 같이 400번대 오류들의 경우 앞에 9를 붙여서 9400, 9404, 9401, 9403등으로 반환합니다.

예시 소스(일부 발췌):

{% code title="GlobalControllerAdvice.java" %}

```java
/** * GlobalControllerAdvice */
@Slf4j
public class GlobalControllerAdvice {

    @ExceptionHandler(Exception.class)
    protected ResponseEntity<Object> handleException(Exception e, HttpServletRequest request) {
        RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
        log.error("", e);
        String code = String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value());
        String message = e.getMessage();
        int httpStatus = Integer.parseInt(code);
        ErrorCode errorCode = ErrorCode.builder()
            .code(code)
            .message(message)
            .httpStatus(httpStatus)
            .build();
        return handleExceptionInternal(errorCode);
    }

    @ExceptionHandler(BindException.class)
    protected ResponseEntity<Object> handleBindException(BindException e, HttpServletRequest request) {
        RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, this.attributeError);
        log.warn("", e);
        String code = CommonAppError.BINDING_ERROR.getCode();
        String message = getBindingErrorMessage(e.getBindingResult());
        String httpStatusCode = String.valueOf(HttpStatus.BAD_REQUEST.value());
        int httpStatus = getBadRequestHttpStatusCode(httpStatusCode);
        ErrorCode errorCode = ErrorCode.builder()
            .code(code)
            .message(message)
            .httpStatus(httpStatus)
            .build();
        return handleExceptionInternal(e, errorCode);
    }

    // ...... 그외 등등 소스코드가 길어서 생략함.
}
```

{% endcode %}

## 예외 반환 응답값

GlobalControllerAdvice에서 처리하는 Exception 목록 (Exception들은 대부분 추가 되었으나, 혹시 제외된 ‘예외 처리’가 있다면 추가될 수 있습니다.)

| Exception 종류                                                                                                                                                                                                                                                                                                                              | 반환응답값                        | 비고                                                                                                                                              |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Exception.class                                                                                                                                                                                                                                                                                                                           | 500                          | handleException 함수에서 처리하며, ControllerAdvice에서 잡지 못하는 모든 예외 사항은 해당 함수에서 처리함. 해당 Exception의 메시지값과 500 http status값을 반환함.                          |
| NullPointerException.class, IOException.class, ArrayIndexOutOfBoundsException.class, EntityNotFoundException.class, StringIndexOutOfBoundsException.class, IndexOutOfBoundsException.class, UnsupportedEncodingException.class                                                                                                            | 500                          | handleErrorException 함수에서 처리하며, 종류에 정의된 Exception들의 경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 500 http status값을 반환함.                                  |
| IllegalArgumentException.class, IllegalStateException.class, ConstraintViolationException.class, JsonParseException.class, com.fasterxml.jackson.core.JsonParseException.class, HttpMessageNotReadableException.class, MethodArgumentTypeMismatchException.class, MissingServletRequestParameterException.class, MultipartException.class | 500                          | handleIllegalException 함수에서 처리하며, 종류에 정의된 Exception들의 경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 500 http status값을 반환함.                                |
| HttpInterfaceResponseException.class                                                                                                                                                                                                                                                                                                      | HttpInterface 에서 반환하는 응답값    | handleHttpInterfaceException 함수에서 처리하며, HttpInterface 기능에서 Exception이 날경우 해당 함수에서 처리함. HttpInterface를 호출하는 상대쪽에서 반환하는 메시지값과 http status값을 반환함.  |
| HttpException.class                                                                                                                                                                                                                                                                                                                       | RestApiInterface 에서 반환하는 응답값 | handleHttpException 함수에서 처리하며, RestApiInterface 기능에서 Exception이 날경우 해당 함수에서 처리함. RestApiInterface를 호출하는 상대쪽에서 반환하는 메시지값과 http status값을 반환함.     |
| WebClientResponseException.class                                                                                                                                                                                                                                                                                                          | WebClient에서 반환하는 응답값         | handleWebClientResponseException 함수에서 처리하며, WebClient 기능에서 Exception이 날경우 해당 함수에서 처리함. WebClient를 호출하는 상대쪽에서 반환하는 메시지값과 http status값을 반환함.      |
| WebClientRequestException.class                                                                                                                                                                                                                                                                                                           | 500                          | handleWebClientRequestException 함수에서 처리하며, WebClient 요청시 Exception이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 500 http status값을 반환함.                 |
| AsyncRequestTimeoutException.class                                                                                                                                                                                                                                                                                                        | 500                          | handleAsyncRequestTimeoutException 함수에서 처리하며, 비동기 요청시 Timeout Exception이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 500 http status값을 반환함.            |
| ValidationException.class                                                                                                                                                                                                                                                                                                                 | 원래 400이지만 9400으로 처리함. 9400   | handleValidationException 함수에서 처리하며, ValidationException이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9400 http status값을 반환함.                          |
| BindException.class                                                                                                                                                                                                                                                                                                                       | 원래 400이지만 9400으로 처리함. 9400   | handleBindException 함수에서 처리하며, BindException이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9400 http status값을 반환함.                                      |
| MethodArgumentNotValidException.class                                                                                                                                                                                                                                                                                                     | 원래 400이지만 9400으로 처리함. 9400   | handleMethodArgumentNotValidException 함수에서 처리하며, MethodArgumentNotValidException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9400 http status값을 반환함. |
| HttpRequestMethodNotSupportedException.class                                                                                                                                                                                                                                                                                              | 원래 405이지만 9405으로 처리함. 9405   | handleNotSupportedException 함수에서 처리하며, HttpRequestMethodNotSupportedException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9405 http status값을 반환함.    |
| NoHandlerFoundException.class                                                                                                                                                                                                                                                                                                             | 원래 404이지만 9404으로 처리함. 9404   | handleNoHandlerFoundException 함수에서 처리하며, NoHandlerFoundException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9404 http status값을 반환함.                 |
| MaxUploadSizeExceededException.class                                                                                                                                                                                                                                                                                                      | 원래 413이지만 9413으로 처리함. 9413   | handleMaxSizeException 함수에서 처리하며, MaxUploadSizeExceededException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9413 http status값을 반환함.                 |
| AuthenticationException.class                                                                                                                                                                                                                                                                                                             | 원래 401이지만 9401으로 처리함. 9401   | handleAuthenticationException 함수에서 처리하며, AuthenticationException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9401 http status값을 반환함.                 |
| JwtException.class                                                                                                                                                                                                                                                                                                                        | 원래 401이지만 9401으로 처리함. 9401   | handleJwtException 함수에서 처리하며, JwtException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9401 http status값을 반환함.                                       |
| AccessDeniedException.class                                                                                                                                                                                                                                                                                                               | 원래 403이지만 9403으로 처리함. 9403   | handleAccessDeniedException 함수에서 처리하며, AccessDeniedException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9403 http status값을 반환함.                     |
| ExpiredJwtException.class                                                                                                                                                                                                                                                                                                                 | 원래 403이지만 9403으로 처리함. 9403   | handleExpiredJwtException 함수에서 처리하며, ExpiredJwtException 이 날경우 해당 함수에서 처리함. 해당 Exception의 메시지값과 9403 http status값을 반환함.                         |

* **DisplayControllerAdvice.class**

(EventControllerAdvice 등등 각 API서버들의 ControllerAdvice Class)

<mark style="color:$danger;">(해당 파일은 각 프로젝트에서 작성되며 GlobalControllerAdvice를 상속받아서 AppException.class 만이 추가 되었습니다. 해당 Class 또한 특별하게 수정할 일이 없는 경우, 확인만 진행하면 됩니다.)</mark>

예시 소스(발췌):

{% code title="DisplayControllerAdvice.java" %}

```java
/** * DisplayControllerAdvice */
@RestControllerAdvice
@Slf4j
public class DisplayControllerAdvice extends GlobalControllerAdvice {

    @ExceptionHandler(AppException.class)
    protected ResponseEntity<Object> handleAppException(AppException e, WebRequest request) {
        RequestUtils.setAttribute(RequestLoggingFilter.REQUEST_LOG_LEVEL, "error");
        String code = Optional.ofNullable(e.getErrorCode()).orElse(ApiError.UNKNOWN.getCode());
        String message = e.getErrorMessage();
        int httpStatus = getAppExceptionHttpStatus(code);
        Boolean isProcess = Optional.ofNullable(e.getIsProcess()).orElse(false);
        log.warn("AppException: [{}] {}", code, message);
        log.warn("", e);
        ErrorCode errorCode = ErrorCode.builder()
            .code(code)
            .message(message)
            .httpStatus(httpStatus)
            .isProcess(isProcess)
            .build();
        return handleExceptionInternalValue(errorCode);
    }

    private int getAppExceptionHttpStatus(String code) {
        Integer httpStatus = null;
        if ("0000".equals(code)) {
            httpStatus = HttpStatus.OK.value();
        } else if ("9999".equals(code) || "9000".equals(code)) {
            httpStatus = HttpStatus.INTERNAL_SERVER_ERROR.value();
        } else if (code.indexOf("90") == 0) {
            String httpStatusCode = String.valueOf(HttpStatus.BAD_REQUEST.value());
            httpStatus = getBadRequestHttpStatusCodeValue(httpStatusCode);
        } else if (code.indexOf("91") == 0) {
            String httpStatusCode = String.valueOf(HttpStatus.UNAUTHORIZED.value());
            httpStatus = getBadRequestHttpStatusCodeValue(httpStatusCode);
        } else if (code.indexOf("93") == 0) {
            String httpStatusCode = String.valueOf(HttpStatus.FORBIDDEN.value());
            httpStatus = getBadRequestHttpStatusCodeValue(httpStatusCode);
        } else if (code.indexOf("94") == 0) {
            String httpStatusCode = String.valueOf(HttpStatus.NOT_FOUND.value());
            httpStatus = getBadRequestHttpStatusCodeValue(httpStatusCode);
        } else {
            String httpStatusCodeValue = String.valueOf(HttpStatus.BAD_REQUEST.value());
            httpStatus = getBadRequestHttpStatusCodeValue(httpStatusCodeValue);
        }
        return httpStatus;
    }
}
```

{% endcode %}

각각 API의 ControllerAdvice에서는 @ExceptionHandler(AppException.class)만을 담당하고 있습니다.

그리고 가장 중요한 getAppExceptionHttpStatus 함수에서는 반환할 Httpstatus값을 처리하고 있습니다.

## 프로젝트별 Code값 목록

프로젝트별 ControllerAdvice에서 처리하는 Code값 목록&#x20;

<mark style="color:$danger;">실제 업무단에서는 1000\~8999번대 code만 정의하기 때문에 하단 목록에서 가장 아래 항목인 ‘그외’만 확인하면 됩니다.</mark>

<table><thead><tr><th width="141.2222900390625">Code</th><th width="119.6666259765625">HttpStatus</th><th>설명 (ex)</th></tr></thead><tbody><tr><td>0000</td><td>200</td><td>SUCCESS("0000", "common.message.success", "common.message.success") — 0000인 경우에는 SUCCESS라고 판단하여 200으로 설정</td></tr><tr><td>9999</td><td>500</td><td>FAIL("9999", "common.message.fail", "common.message.fail") — 9999인 경우에는 FAIL라고 판단하여 500으로 설정</td></tr><tr><td>9000</td><td>500</td><td>UNKNOWN("9000", "common.error.unknown", "common.error.unknown") — 9000인 경우에는 UNKNOWN인데 역시나 500으로 설정</td></tr><tr><td>9001 ~ 9099</td><td>9400</td><td>여러 validation/parameter 관련 에러(예: EMPTY_PARAMETER, INVALID_PARAMETER 등). 400번대라고 판단하여 9를 붙여 9400으로 설정</td></tr><tr><td>9100 ~ 9199</td><td>9401</td><td>인증(401) 관련 코드들 — 9를 붙여 9401으로 설정</td></tr><tr><td>9300 ~ 9399</td><td>9403</td><td>권한(403) 관련 코드들 — 9를 붙여 9403으로 설정</td></tr><tr><td>9400 ~ 9499</td><td>9404</td><td>404 관련 코드들 — 9를 붙여 9404으로 설정</td></tr><tr><td>그외</td><td>9400</td><td>그외 모든 코드값들의 경우 현재는 모두 9를 붙여서 9400으로 설정. 실제로 각 업무단에서 1000~8999번대 코드들을 관리하게 됩니다. 해당 코드값들은 모두 http status값을 9400으로 반환합니다.</td></tr></tbody></table>

* **CommonAppError.class**

(Common에 있는 것으로 공통 0000, 9000번대 코드값들을 정의함)\ <mark style="color:$danger;">해당 Class는 공통에서 관리되기 때문에 이러한 Code값들이 관리가 되고 있는 수준만 확인하면 됩니다.</mark>

```
/**
 * CommonAppError
 */
@Getter
@AllArgsConstructor
public enum CommonAppError implements AppError {

	// --------- Common Code
	// OK 200
	SUCCESS("0000", "common.message.success", "common.message.success"),
	// INTERNAL_SERVER_ERROR 500
	FAIL("9999", "common.message.fail", "common.message.fail"),
	// INTERNAL_SERVER_ERROR 500
	UNKNOWN("9000", "common.error.unknown", "common.error.unknown"),

	// BAD_REQUEST 9400
	EMPTY_PARAMETER("9001", "common.error.emptyParameter", "common.error.emptyParameter"),
	INVALID_PARAMETER("9002", "common.error.invalidParameter", "common.error.invalidParameter"),
	INSERT_PARAMETER("9003", "common.error.insertParameter", "common.error.insertParameter"),
	DUPLICATE_DATA("9004", "common.error.duplicateData", "common.error.duplicateData"),
	INVALID_FILE("9005", "common.error.invalidFile", "common.error.invalidFile"),
	UPLOAD_FAIL("9006", "common.error.uploadFail", "common.error.uploadFail"),
	VALIDATION_EXCEPTION("9007", "common.error.validationParameter", "common.error.validationParameter"),
	BINDING_ERROR("9008", "common.error.bindingError", "common.error.bindingError"),
	BINDING_ERROR_NOT_NULL("9009", "common.error.bindingErrorNotNull", "common.error.bindingErrorNotNull"),

	// UNAUTHORIZED 9401
	REQUIRED_LOGIN("9100", "common.error.requiredLogin", "common.error.requiredLogin"),
	NEED_LOGIN("9101", "common.error.needLogin", "common.error.needLogin"), // 로그인 필요
	FAIL_DELETE_TOKEN("9102", "common.error.failDeleteToken", "common.error.failDeleteToken"),

	// FORBIDDEN 9403
	NOT_AUTHORIZED("9300", "common.error.notAuthorized", "common.error.notAuthorized"),
	DISPLAY_LIMIT("9301", "common.error.displayLimit", "common.error.displayLimit"),
	INVALID_TOKEN("9302", "common.error.invalidToken", "common.error.invalidToken"),
	FAIL_TOKEN("9303", "common.error.failToken", "common.error.failToken"),

	// NOT_FOUND 9404
	DATA_NOT_FOUND("9400", "common.error.dataNotFound", "common.error.dataNotFound");
	// Common Code ---------

	private final String code;
	private final String messageKey;
	private final String boMessageKey;

}
```

* **DisplayApiError.class**

(DisplayApiError등등 각 API서버들의 Error Class)

<mark style="color:red;">UI쪽에서 사용하는 isProcess 필드값이 추가가 되었습니다.</mark>

<mark style="color:red;">해당값은 기본값이 false이기 때문에 모든 메시지 값을 false로 쓸 경우, default 메서드가 false로 작동하기 때문에 다음과 같이 작성해주시면 됩니다.</mark>

```
@Getter
@AllArgsConstructor
public enum DisplayApiError2 implements AppError {

	EMPTY_PARAMETER("5000", "display.common.error.emptyParameter", "display.common.error.emptyParameter"),
    INVALID_PARAMETER("5001", "display.common.error.invalidParameter", "display.common.error.invalidParameter"),
    EMPTY_USER_DETAIL("5002", "display.common.error.emptyUserDetail", "display.common.error.emptyUserDetail");

	private final String code;
	private final String messageKey;
	private final String boMessageKey;

}
```

\ <mark style="color:red;">isProcess 필드값을 활용하시는 경우에는 다음과 같이 getIsProcess 함수를 Override하는 부분을 추가 해야 되며, 다음과 같이 마지막 항목에 false, true값 등을 모두 명시해 주셔야 합니다.</mark>

```
@Getter
@AllArgsConstructor
public enum DisplayApiError implements AppError {

	EMPTY_PARAMETER("5000", "display.common.error.emptyParameter", "display.common.error.emptyParameter", false),
    INVALID_PARAMETER("5001", "display.common.error.invalidParameter", "display.common.error.invalidParameter", true),
    EMPTY_USER_DETAIL("5002", "display.common.error.emptyUserDetail", "display.common.error.emptyUserDetail", false);

	private final String code;
	private final String messageKey;
	private final String boMessageKey;
	private final boolean isProcess;

	@Override
	public boolean getIsProcess() {
		return  isProcess;
	}

}
```

이렇게 각 서버 프로젝트들에서는 다음과 같이 사용할 Error값들을 <mark style="color:$danger;">1000 \~ 8999</mark>번대 코드로 정의해 주시면 됩니다.

&#x20;

※ BO프로젝트 같은 경우에는 타임리프와 같은 페이지 호출이 같이 있기 때문에 서버페이지를 호출할 때 Exception이 발생하면 ControllerAdvice Class에서 다음과 같은 분기 로직이 존재합니다.

```
if (isApiRequest(request)) {     
   //API 호출인 경우  ResponseEntity<Object>로 반환함.     
   return handleExceptionInternal(errorCode); 
}
//API 호출이 아닌 경우 error 페이지를 ModelAndView로 반환하여 에러페이지로 리디렉션 됩니다.
 return handleException(request, exception, object);
```

&#x20;

* **GlobalErrorController.java**

(BO같은 경우에는 error페이지로 보내는 경우가 존재함)

<mark style="color:red;">해당 Class파일은 BO 프로젝트에서만 존재합니다.</mark>

<mark style="color:red;">ControllerAdvice에서 api 호출이 아닌 경우에는 GlobalErrorController로 쪽으로 리디렉션 시켜서 error 페이지를 호출하는 정도입니다.</mark>

```
@Controller
@RequestMapping("/error")
@Slf4j
public class GlobalErrorController extends AbstractErrorController {
    public static final String EXCEPTION_KEY = "_ExceptioN_KEY_";

    public GlobalErrorController(ErrorAttributes errorAttributes) {
        super(errorAttributes);
    }

    @RequestMapping(produces = MediaType.TEXT_HTML_VALUE) // 2)
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults();
        Map<String, Object> model = getErrorAttributes(request, options);
        String errorPage = "error/error";
        Exception exception = (Exception) request.getAttribute("jakarta.servlet.error.exception");

        if (exception != null) {
            Throwable throwable = exception.getCause();
            if (throwable instanceof AuthException) {
                errorPage = "error/403";
            } else if (throwable instanceof ValidationException) {
                errorPage = "error/404";
            } else {
                errorPage = "error/500";
            }
        } else {
            errorPage = "error/500";
        }

        ModelAndView modelAndView = new ModelAndView(errorPage, model);
        modelAndView.addObject(EXCEPTION_KEY, exception.getCause());
        return modelAndView;
    }

    @RequestMapping("loginExpired")
    public ModelAndView loginExpired(HttpServletRequest request, HttpServletResponse response) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults();
        Map<String, Object> model = getErrorAttributes(request, options);
        model.put("message", "로그인이 만료되었습니다.");
        ModelAndView modelAndView = new ModelAndView("error/loginExpired", model);
        return modelAndView;
    }

    protected ErrorAttributeOptions getErrorAttributeOptions(HttpServletRequest request, MediaType mediaType) {
        ErrorAttributeOptions options = ErrorAttributeOptions.defaults();
        options = options.including(Include.MESSAGE);
        options = options.including(Include.BINDING_ERRORS);
        return options;
    }
    
    
    @RequestMapping
    public ResponseEntity<Response> error(HttpServletRequest request) {
        Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);

        log.error("status_code: {}", request.getAttribute("jakarta.servlet.error.status_code"));
        log.error("exception_type: {}", request.getAttribute("jakarta.servlet.error.exception_type"));
        log.error("message: {}", request.getAttribute("jakarta.servlet.error.message"));
        log.error("request_uri: {}", request.getAttribute("jakarta.servlet.error.request_uri"));
        log.error("exception: {}", request.getAttribute("jakarta.servlet.error.exception"));

        Exception exception = (Exception) request.getAttribute("jakarta.servlet.error.exception");

        if (exception != null) {
            Throwable throwable = exception.getCause();
            if (throwable instanceof AuthException) {
                return new ResponseEntity<Response>(
                        Response.builder()
                                .code("0403")
                                .message(((AuthException) throwable).getMessage())
                                .error(true)
                                .build(),
                        new HttpHeaders(), HttpStatus.FORBIDDEN);
            } else {
                return new ResponseEntity<Response>(
                        Response.builder()
                                .code("9000")
                                .message(MessageResolver.getMessage("adminCommon.system.error"))
                                .error(true)
                                .build(),
                        new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR);
            }
        } else {
            HttpStatus httpStatus = null;

            if (status != null) {
                try {
                    httpStatus = HttpStatus.resolve(Integer.valueOf(String.valueOf(status)));
                } catch (Exception ex) {
                    httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
                }

                if (httpStatus == null) {
                    httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
                }

                if ("401".equals(status.toString())) {
                    httpStatus = HttpStatus.UNAUTHORIZED;
                    return new ResponseEntity<Response>(
                            Response.builder()
                                    .code("9000")
                                    .message(MessageResolver.getMessage("login.expried"))
                                    .error(true)
                                    .build(),
                            new HttpHeaders(), httpStatus);
                }

            } else {
                httpStatus = HttpStatus.INTERNAL_SERVER_ERROR;
            }

            return new ResponseEntity<Response>(
                    Response.builder()
                            .code("9000")
                            .message(MessageResolver.getMessage("adminCommon.system.error"))
                            .error(true)
                             .build(),
                    new HttpHeaders(), httpStatus);
        }
    }

}
```

## 에러메시지 처리 <a href="#undefined" id="undefined"></a>

에러메시지 처리의 경우 FO, BO Message 처리 부분인 해당 내용을 참고하면 됩니다.

Message값을 처리하기 위해서 공통에서 MessageResolver Class를 제공하고 있습니다.

#### MessageResolver.class <a href="#messageresolver.class" id="messageresolver.class"></a>

<kbd>getLocaleMessage</kbd>함수가 메시지값을 가져오는 주요 함수로서 다음과 같이 작동합니다.

1. messageKey값이 String Key 인자의 함수인 경우에는 그대로 메지시값 반환
2. messageKey값이 Emum Class 인자의 함수인 경우에는 RequestContextHolder 객체의 헤더값에서 호출한 서버명을 인식하여,\
   BO인 경우 2번째 Message 인자값인 boMessageKey의 메시지값을 반환,\
   호출한 서버명이 BO쪽이 아닌 경우 기존 messageKey 그대로 메시지값을 반환

사용법은 다음과 같습니다.

* **ApiError Class 파일 작성**

```
public enum ApiError implements AppError {
	// success
	SUCCESS("0000", "common.message.success", "common.message.success"),
	// app error
	EMPTY_PARAMETER("1001", "common.error.emptyParameter", "common.error.emptyParameter"),
	INVALID_PARAMETER("1002", "common.error.invalidParameter", "common.error.invalidParameter"),
	DATA_NOT_FOUND("1003", "common.error.dataNotFound", "common.error.dataNotFound"),
	DUPLICATE_DATA("1004", "common.error.duplicateData", "common.error.duplicateData"),
	INVALID_FILE("1005", "common.error.invalidFile", "common.error.invalidFile"),
	UPLOAD_FAIL("1100", "common.error.uploadFail", "common.error.uploadFail"),
	MEMBER_API_FAIL("1200", "common.error.memberApi", "common.error.memberApi"),
	
	EVENT_ENTRY_SUCCESS("2000", "event.entry.message.success", "event.entry.message.success"),
	EVENT_ERROR_EVENT_NOT_FOUND("2001", "event.error.eventNotFound", "event.error.eventNotFound"),
	EVENT_ERROR_SBSCCNTLMTCD_NOT_FOUND("2002", "event.error.sbscCntLmtCdNotFound", "event.error.sbscCntLmtCdNotFound"),
	EVENT_ERROR_EVENT_SBSC_IF_NOT("2003", "event.error.eventSbscIfNot", "event.error.eventSbscIfNot"),

	// unknow error
	UNKNOWN("9000", "common.error.unknown", "common.error.unknown"),
	// ValidatioException error
	VALIDATION_EXCEPTION("9100", "common.error.unknown", "common.error.unknown"),
	TEST("9999", "event.aply.simple.member.limit.message", "event.aply.simple.member.limit.message.bo"),
	TEST2("9999", "event.aply.simple.member.limit.message.bo", "event.aply.simple.member.limit.message.bo"),
	TEST3("9999", "event.aply.simple.member.limit.message2", "event.aply.simple.member.limit.message2.bo"),
	TEST4("9999", "event.aply.simple.member.limit.message2.bo", "event.aply.simple.member.limit.message2.bo");

	private final String code;
	private final String messageKey;
	private final String boMessageKey;
}
```

해당 enum class파일에 code값 및 FO message, BO message키값을 정의 합니다.

BO message값이 따로 없을 경우 FO message값을 동일하게 적용합니다.

* **message properties 파일 작성**

event\_ko.properties, event\_en.properties 등등 message properties파일을 정리합니다.

```
event.aply.simple.member.limit.message = 간편회원은 응모하실 수 없습니다.
event.aply.simple.member.limit.message.bo = 간편회원은 응모하실 수 없습니다.(BO)

event.aply.simple.member.limit.message2 = 간편회원은 응모하실 수 없습니다.22
```

해당 message properties파일에 FO 및 BO에서 사용할 메시지값을 정의함.

&#x20;

* **비지니스 로직에서 사용**

```
@GetMapping("/test")
public ResponseEntity<Response> test() throws Exception {
	
	// 메시지를 직접 가져오는 경우. 해당 메시지키값 그대로 반환함.
    String foMsg = MessageResolver.getMessage("event.aply.simple.member.limit.message");

    // 메시지를 직접 가져오는 경우. 해당 메시지키값 그대로 반환함.
	String boMsg = MessageResolver.getMessage("event.aply.simple.member.limit.message.bo");
	
	// 위와 동일하지만 정의한 ApiError enum Class를 활용하는 경우
	// 호출한 서버명에 따라서 messageKey값 또는 boMessageKey값을 반환함.
	String msg = MessageResolver.getMessage(ApiError.TEST);
	
	// AppException을 발생하는 경우
	// 호출한 서버명에 따라서 messageKey값 또는 boMessageKey값을 반환함.
	AppException.exception(ApiError.TEST);

	return ResponseEntity.ok().body(Response.builder().payload("성공").build());
}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://tech.x2bee.com/dev-guide/dev-start/interactive-blocks/undefined.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
