2014-10-21 4 views
11

Ho definito una gestione globale eccezione nel mio servizio Resto basato Primavera Boot:Primavera Boot eccezione personalizzata all'interno di un servizio 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; 
    } 
} 

e un ServiceException personalizzato:

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 
} 

finora tutto bene, quando un'eccezione viene attivata, il controller funziona come dovrebbe e risponde con:

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

ma th Il campo errorCode non viene mostrato nella risposta JSON.

Quindi, come è possibile definire una risposta alle eccezioni personalizzata nella mia applicazione.

risposta

20

Spring Boot utilizza un'implementazione di ErrorAttributes per popolare lo Map che viene visualizzato come JSON. Per impostazione predefinita, viene utilizzata un'istanza di DefaultErrorAttributes. Per includere la tua errorCode personalizzata dovrai fornire un'implementazione personalizzata ErrorAttributes che conosca ServiceException e il suo codice di errore. Questa implementazione personalizzata dovrebbe essere un @Bean nella configurazione.

Un approccio potrebbe essere quello di sottoclasse 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

Ciao Andy, qui Se la classe eccezione personalizzata estende con l'eccezione o Throwable allora errore esempio sarebbe UnhandledThrowException perché sta accadendo. – KSK

+0

@KSK Non mi è chiaro come sia correlata a questa domanda una risposta. Penso che sarebbe meglio fare una nuova domanda con qualche altro dettaglio –

+0

ottimo, grazie Andy –

3

@alex È possibile utilizzare l'annotazione @ExceptionHandler (YourExceptionClass.class) per gestire l'eccezione specifica in specifici RestController. Penso che sia un modo migliore per gestire scenari complicati nelle applicazioni aziendali. Inoltre ti suggerirò di utilizzare il traduttore di eccezioni personalizzate per gestire diversi tipi di eccezioni. È possibile considerare spring oauth2 exception translator come codice di riferimento per il traduttore di eccezioni.

Nota: il seguente codice serve solo a comprendere il concetto di questa soluzione. Non è un codice pronto per la produzione. Sentiti libero di discuterne di più.

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

Penso che questo approccio mi piaccia meglio della ridefinizione di "ErrorAttributes" a livello globale. Anche se penso che idealmente dovrebbe ancora utilizzare il globale 'ErrorAttributes' per ottenere gli attributi predefiniti e quindi inserire valori extra in. –

+0

@M. Prokhorov ha accettato, che renderà più potente l'approccio –

+0

@ HarpreetSandhu-TheCoder quando provo ad accedere a questo da un programma java, restituisce il codice di errore, ma non il messaggio di errore. cioè, restituisce il codice di errore come 404, ma il messaggio non viene trovato da nessuna parte nell'oggetto risposta. – KingKari