Spring Исходное исключение загрузки в службе отдыха

Я определил глобальную обработку исключений в моей службе загрузки Spring с загрузкой:

@ControllerAdvice
public class GlobalExceptionController {

    private final Logger LOG = LoggerFactory.getLogger(getClass());

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Internal application error")
    @ExceptionHandler({ServiceException.class})
    @ResponseBody
    public ServiceException serviceError(ServiceException e) {
        LOG.error("{}: {}", e.getErrorCode(), e.getMessage());
        return e;
    }
}

и пользовательское исключение службы:

public class ServiceException extends RuntimeException {

    private static final long serialVersionUID = -6502596312985405760L;

    private String errorCode;

    public ServiceException(String message, String errorCode, Throwable cause) {
        super(message, cause);
        this.errorCode = errorCode;
    }

    // other constructors, getter and setters omitted
}

настолько хорошо, что при запуске исключения контроллер работает так, как должен, и отвечает:

{
   "timestamp": 1413883870237,
   "status": 500,
   "error": "Internal Server Error",
   "exception": "org.example.ServiceException",
   "message": "somthing goes wrong",
   "path": "/index"
}

но поле errorCode не отображается в ответе JSON.

Итак, как я могу определить настраиваемый ответ исключения в своем приложении.

Ответ 1

Spring Boot использует реализацию ErrorAttributes для заполнения Map, который отображается как JSON. По умолчанию используется экземпляр DefaultErrorAttributes. Чтобы добавить свой собственный errorCode, вам нужно предоставить пользовательскую реализацию ErrorAttributes, которая знает о ServiceException и ее код ошибки. Эта настраиваемая реализация должна быть a @Bean в вашей конфигурации.

Один подход будет заключаться в подклассе DefaultErrorAttributes:

@Bean
public ErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes() {

        @Override
        public Map<String, Object> getErrorAttributes(
                RequestAttributes requestAttributes,
                boolean includeStackTrace) {
            Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
            Throwable error = getError(requestAttributes);
            if (error instanceof ServiceException) {
                errorAttributes.put("errorCode", ((ServiceException)error).getErrorCode());
            }
            return errorAttributes;
        }

    };
}

Ответ 2

@Alex Вы можете использовать аннотацию @ExceptionHandler (YourExceptionClass.class), чтобы обрабатывать конкретное исключение в определенном RestController. Я считаю, что это лучший способ обработки сложных сценариев в бизнес-приложениях. Более того, я предлагаю вам использовать собственный переводчик исключений для обработки различных типов исключений. Вы можете рассматривать spring переводчик исключений oauth2 как ссылочный код для транслятора исключений.

Примечание. Следующий код предназначен только для понимания концепции этого решения. Это не готовый готовый код. Не стесняйтесь больше обсуждать это.

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

/**
* @author Harpreet
* @since 16-Aug-17.
*/
@RestController
public class RestTestController {

@RequestMapping(value = "name", method = RequestMethod.GET,
        produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseObject name(@RequestParam(value="name") String value){
    //your custom logic 
    if (value == null || value.length() < 2) {
        //throwing exception to invoke customExceptionHandler
        throw new NullPointerException("value of request_param:name is invalid");
    }
    ResponseObject responseObject = new ResponseObject();
    responseObject.setMessage(value)
            .setErrorCode(1);
    return responseObject;
}

// to handle null pointer exception
@ExceptionHandler(NullPointerException.class)
public ResponseObject customExceptionHandler
        (NullPointerException e) {
    ResponseObject responseObject = new ResponseObject();
    responseObject.setMessage(e.getMessage())
            .setErrorCode(-1);
    return responseObject;
}

// response data transfer class
static class ResponseObject{
    String message;
    Integer errorCode;

    public String getMessage() {
        return message;
    }

    public ResponseObject setMessage(String message) {
        this.message = message;
        return this;
    }

    public Integer getErrorCode() {
        return errorCode;
    }

    public ResponseObject setErrorCode(Integer errorCode) {
        this.errorCode = errorCode;
        return this;
    }
  }
 }