我在基于Spring Boot的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"
}
但是字段 errorCode 未显示在JSON响应中。
那么如何在我的应用程序中定义自定义异常响应。
答案 0 :(得分:21)
Spring Boot使用ErrorAttributes
的实现来填充呈现为JSON的Map
。默认情况下,使用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;
}
};
}
答案 1 :(得分: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;
}
}
}