> 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/developer-guide-en/dev-start/interactive-blocks/error-messages-and-exception-handling.md).

# Error Messages and Exception Handling

The following explains error messages and exception handling.

***

## Exception Handling

The cases where an Exception occurs on the server and needs to be ‘handled’ are as follows.

* When calling a server page (Next.js) (BO server project)
* When calling a Restful API (API server project)

For typical API servers, exceptions are handled by GlobalControllerAdvice in Common and by each API project’s DisplayControllerAdvice (which extends GlobalControllerAdvice).

* **GlobalControllerAdvice.class&#x20;**<mark style="color:$danger;">**(This file is written in Common, and you can think of it as handling these Exceptions.)**</mark>

The GlobalControllerAdvice class handles the exceptions that need to be handled commonly.

For general Exceptions, the HttpStatus value is returned as 500, and for 400-range errors such as ValidationException, a 9 is prefixed and they are returned as 9400, 9404, 9401, 9403, etc.

Example source (excerpt):

{% 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);
    }

    // ...... other code omitted for brevity.
}
```

{% endcode %}

## Exception Response Values

List of Exceptions handled by GlobalControllerAdvice (most Exceptions have already been added, but if any ‘exception handling’ has been omitted, it may be added.)

| Exception Type                                                                                                                                                                                                                                                                                                                            | Return Response Value                       | Notes                                                                                                                                                                                                                                        |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Exception.class                                                                                                                                                                                                                                                                                                                           | 500                                         | Handled in the handleException function; any exception not caught by ControllerAdvice is handled by this function. Returns the Exception's message value along with an HTTP status of 500.                                                   |
| NullPointerException.class, IOException.class, ArrayIndexOutOfBoundsException.class, EntityNotFoundException.class, StringIndexOutOfBoundsException.class, IndexOutOfBoundsException.class, UnsupportedEncodingException.class                                                                                                            | 500                                         | Handled in the handleErrorException function; Exceptions defined in this category are handled by this function. Returns the Exception's message value along with an HTTP status of 500.                                                      |
| IllegalArgumentException.class, IllegalStateException.class, ConstraintViolationException.class, JsonParseException.class, com.fasterxml.jackson.core.JsonParseException.class, HttpMessageNotReadableException.class, MethodArgumentTypeMismatchException.class, MissingServletRequestParameterException.class, MultipartException.class | 500                                         | Handled in the handleIllegalException function; Exceptions defined in this category are handled by this function. Returns the Exception's message value along with an HTTP status of 500.                                                    |
| HttpInterfaceResponseException.class                                                                                                                                                                                                                                                                                                      | Response value returned by HttpInterface    | Handled in the handleHttpInterfaceException function; when an Exception occurs in the HttpInterface feature, it is handled by this function. Returns the message value and http status returned by the counterpart called via HttpInterface. |
| HttpException.class                                                                                                                                                                                                                                                                                                                       | Response value returned by RestApiInterface | Handled in the handleHttpException function; when an Exception occurs in the RestApiInterface feature, it is handled by this function. Returns the message value and http status returned by the counterpart called via RestApiInterface.    |
| WebClientResponseException.class                                                                                                                                                                                                                                                                                                          | Response value returned by WebClient        | Handled in the handleWebClientResponseException function; when an Exception occurs in the WebClient feature, it is handled by this function. Returns the message value and http status returned by the counterpart called via WebClient.     |
| WebClientRequestException.class                                                                                                                                                                                                                                                                                                           | 500                                         | Handled in the handleWebClientRequestException function; when an Exception occurs during a WebClient request, it is handled by this function. Returns the Exception's message value along with an HTTP status of 500.                        |
| AsyncRequestTimeoutException.class                                                                                                                                                                                                                                                                                                        | 500                                         | Handled in the handleAsyncRequestTimeoutException function; when a Timeout Exception occurs during an asynchronous request, it is handled by this function. Returns the Exception's message value along with an HTTP status of 500.          |
| ValidationException.class                                                                                                                                                                                                                                                                                                                 | Originally 400, but handled as 9400. 9400   | Handled in the handleValidationException function; when a ValidationException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9400.                                               |
| BindException.class                                                                                                                                                                                                                                                                                                                       | Originally 400, but handled as 9400. 9400   | Handled in the handleBindException function; when a BindException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9400.                                                           |
| MethodArgumentNotValidException.class                                                                                                                                                                                                                                                                                                     | Originally 400, but handled as 9400. 9400   | Handled in the handleMethodArgumentNotValidException function; when a MethodArgumentNotValidException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9400.                       |
| HttpRequestMethodNotSupportedException.class                                                                                                                                                                                                                                                                                              | Originally 405, but handled as 9405. 9405   | Handled in the handleNotSupportedException function; when a HttpRequestMethodNotSupportedException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9405.                          |
| NoHandlerFoundException.class                                                                                                                                                                                                                                                                                                             | Originally 404, but handled as 9404. 9404   | Handled in the handleNoHandlerFoundException function; when a NoHandlerFoundException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9404.                                       |
| MaxUploadSizeExceededException.class                                                                                                                                                                                                                                                                                                      | Originally 413, but handled as 9413. 9413   | Handled in the handleMaxSizeException function; when a MaxUploadSizeExceededException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9413.                                       |
| AuthenticationException.class                                                                                                                                                                                                                                                                                                             | Originally 401, but handled as 9401. 9401   | Handled in the handleAuthenticationException function; when an AuthenticationException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9401.                                      |
| JwtException.class                                                                                                                                                                                                                                                                                                                        | Originally 401, but handled as 9401. 9401   | Handled in the handleJwtException function; when a JwtException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9401.                                                             |
| AccessDeniedException.class                                                                                                                                                                                                                                                                                                               | Originally 403, but handled as 9403. 9403   | Handled in the handleAccessDeniedException function; when an AccessDeniedException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9403.                                          |
| ExpiredJwtException.class                                                                                                                                                                                                                                                                                                                 | Originally 403, but handled as 9403. 9403   | Handled in the handleExpiredJwtException function; when an ExpiredJwtException occurs, it is handled by this function. Returns the Exception's message value along with an HTTP status of 9403.                                              |

* **DisplayControllerAdvice.class**

(EventControllerAdvice and other ControllerAdvice classes of each API server)

<mark style="color:$danger;">(This file is written in each project, extends GlobalControllerAdvice, and only adds AppException.class. Unless there is something special to modify in this class as well, you only need to check it.)</mark>

Example source (excerpt):

{% 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 %}

Each API's ControllerAdvice is only responsible for @ExceptionHandler(AppException.class).

And the most important part, the getAppExceptionHttpStatus function, handles the HttpStatus value to be returned.

## List of Code Values by Project

List of Code values handled by each project's ControllerAdvice

<mark style="color:$danger;">In actual business logic, only codes in the 1000–8999 range are defined, so you only need to check the last item in the list below, ‘Other’.</mark>

<table><thead><tr><th width="141.2222900390625">Code</th><th width="119.6666259765625">HttpStatus</th><th>Description (ex)</th></tr></thead><tbody><tr><td>0000</td><td>200</td><td>SUCCESS("0000", "common.message.success", "common.message.success") — for 0000, it is treated as SUCCESS and set to 200</td></tr><tr><td>9999</td><td>500</td><td>FAIL("9999", "common.message.fail", "common.message.fail") — for 9999, it is treated as FAIL and set to 500</td></tr><tr><td>9000</td><td>500</td><td>UNKNOWN("9000", "common.error.unknown", "common.error.unknown") — for 9000, it is UNKNOWN, and is also set to 500</td></tr><tr><td>9001 ~ 9099</td><td>9400</td><td>Various validation/parameter-related errors (e.g., EMPTY_PARAMETER, INVALID_PARAMETER, etc.). Treated as 400-range and set to 9400 by prefixing a 9</td></tr><tr><td>9100 ~ 9199</td><td>9401</td><td>Authentication (401) related codes — set to 9401 by prefixing a 9</td></tr><tr><td>9300 ~ 9399</td><td>9403</td><td>Authorization (403) related codes — set to 9403 by prefixing a 9</td></tr><tr><td>9400 ~ 9499</td><td>9404</td><td>404 related codes — set to 9404 by prefixing a 9</td></tr><tr><td>Other</td><td>9400</td><td>For all other code values, a 9 is currently prefixed and all are set to 9400. In practice, each business unit manages codes in the 1000~8999 range. All such code values return an http status of 9400.</td></tr></tbody></table>

* **CommonAppError.class**

(Located in Common, this defines the common 0000 and 9000-range code values)\ <mark style="color:$danger;">Since this class is managed in Common, you only need to check the level at which these Code values are managed.</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"), // Login required
	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 and other Error classes of each API server)

<mark style="color:red;">The isProcess field value used on the UI side has been added.</mark>

<mark style="color:red;">Since the default value for this field is false, if you want to write all message values as false, you can write it as follows, since the default method operates as 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;">If you want to make use of the isProcess field value, you need to add an override of the getIsProcess function as shown below, and you must explicitly specify the false/true values for the last item as shown below.</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;
	}

}
```

In this way, each server project should define the Error values to be used with codes in the <mark style="color:$danger;">1000 \~ 8999</mark> range.

※ For a BO project, since it also calls server pages such as Thymeleaf pages, when an Exception occurs while calling a server page, the ControllerAdvice class has the following branching logic.

```
if (isApiRequest(request)) {     
   // For API calls, returns as ResponseEntity<Object>.     
   return handleExceptionInternal(errorCode); 
}
// For non-API calls, returns an error page as a ModelAndView, redirecting to the error page.
 return handleException(request, exception, object);
```

* **GlobalErrorController.java**

(For BO, there are cases where the request is sent to an error page)

<mark style="color:red;">This class file only exists in the BO project.</mark>

<mark style="color:red;">When ControllerAdvice is not an api call, it simply redirects to GlobalErrorController to call the error page.</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);
        }
    }

}
```

## Error Message Handling <a href="#undefined" id="undefined"></a>

For error message handling, please refer to the FO/BO Message handling section.

A common MessageResolver class is provided to handle message values.

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

The <kbd>getLocaleMessage</kbd> function is the main function that retrieves message values, and works as follows.

1. If the messageKey value is a function argument of type String Key, the message value is returned as is
2. If the messageKey value is a function argument of type Enum Class, the server name that made the call is recognized from the header value of the RequestContextHolder object,\
   and if it is BO, the message value of the second Message argument, boMessageKey, is returned,\
   and if the calling server name is not on the BO side, the message value is returned as the original messageKey

The usage is as follows.

* **Writing the ApiError Class file**

```
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;
}
```

In this enum class file, define the code value as well as the FO message and BO message key values.

If there is no separate BO message value, the FO message value is applied identically.

* **Writing the message properties file**

Organize message properties files such as event\_ko.properties, event\_en.properties, etc.

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

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

Define in this message properties file the message values to be used by FO and BO.

* **Usage in business logic**

```
@GetMapping("/test")
public ResponseEntity<Response> test() throws Exception {
	
	// When retrieving the message directly. Returns the message key value as is.
    String foMsg = MessageResolver.getMessage("event.aply.simple.member.limit.message");

    // When retrieving the message directly. Returns the message key value as is.
	String boMsg = MessageResolver.getMessage("event.aply.simple.member.limit.message.bo");
	
	// Same as above, but using the defined ApiError enum Class
	// Returns either the messageKey value or the boMessageKey value depending on the calling server name.
	String msg = MessageResolver.getMessage(ApiError.TEST);
	
	// When throwing an AppException
	// Returns either the messageKey value or the boMessageKey value depending on the calling server name.
	AppException.exception(ApiError.TEST);

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