2014-10-21 3 views
11

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

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

и пользовательские ServiceException:

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" 
} 

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

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

ответ

20

Spring Boot использует реализацию ErrorAttributes для заполнения Map, который отображается как JSON. По умолчанию используется экземпляр DefaultErrorAttributes. Чтобы добавить свой пользовательский номер errorCode, вам необходимо предоставить пользовательскую реализацию ErrorAttributes, которая знает о ServiceException и ее код ошибки. Эта настраиваемая реализация должна быть @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; 
     } 

    }; 
} 
+0

Привет Энди здесь Если пользовательский класс исключение распространяется с Exception или Throwable то ошибка, например будет UnhandledThrowException, почему это происходит. – KSK

+0

@KSK Мне непонятно, как это связано с этим вопросом. Я думаю, вам лучше задавать новый вопрос с некоторыми подробностями. –

+0

отлично, спасибо Andy –

3

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

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

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; 
    } 
    } 
} 
+0

Я думаю, что мне нравится этот подход лучше, чем переопределять 'ErrorAttributes' глобально. Хотя я думаю, что в идеале он должен использовать глобальные атрибуты ErrorAttributes для получения атрибутов по умолчанию, а затем добавлять дополнительные значения. –

+0

@M. Прохоров согласился, что сделает его более мощным подходом –

+0

@ HarpreetSandhu-TheCoder, когда я пытаюсь получить доступ к этому из java-программы, он возвращает код ошибки, но не сообщение об ошибке. т.е. он возвращает код ошибки как 404, но сообщение не встречается нигде в объекте ответа. – KingKari

Смежные вопросы