译:在Spring Boot中定制HTTP 错误返回 | Spring For All

211 阅读3分钟
原文链接: www.spring4all.com

在Spring Boot中定制HTTP 错误返回

原文链接:dzone.com/articles/cu…

作者:Jesus J. Puente

译者:沈歌

这篇文章中,我将介绍在Spring Boot中如何返回定制化HTTP错误。当我们发起HTTP请求时,都要考虑有可能返回错误。

典型的示例是我们使用RESTful请求查询一个记录,但是记录不存在。在这个示例中,你通常需要返回HTTP码404(找不到),使用以下代码,你也可以返回一个Spring Boot定制的JSON格式对象:

{
    "timestamp": "2018-11-20T11:46:10.255+0000",
    "status": 404,
    "error": "Not Found",
    "message": "bean: 8 not Found",
    "path": "/get/8"
}

但是如果你想输出一点有效信息,比如:

{
    "timestamp": "2018-11-20T12:51:42.699+0000",
    "mensaje": "bean: 8 not Found",
    "detalles": "uri=/get/8",
    "httpCodeMessage": "Not Found"
}

我们必须在项目中放一些类。

GitHub 上有我的源代码。

创建一个基础的Spring Boot,只有一个简单的对象叫做MiBean,有两个变量,codevalue。 通过/get请求资源,返回这个对象: 请求 http://localhost: 8080/get /1 ,返回一个这样的JSON对象:

{
    "codigo": 1,
    "valor": "valor uno"
}

如果你想要获取id大于3的MiBean,会抛出异常,因为我们只有三条记录。

这个类ErrorResource,对于请求 /get 进行处理。

public class ErrorResource {  
    @Autowired  
    MiBeanService service;  
    @GetMapping("/get/{id}")  
    public MiBean getBean(@PathVariable int id) {  
        MiBean bean = null;  
 try  {  
            bean = service.getBean(id);  
  } catch (NoSuchElementException k)  
        {  
            throw new BeanNotFoundException("bean: "+id+ " not Found" );  
  }  
        return bean;  
  }  
}

正如getBean()方法所示,我们请求MiBeanService对象的getBean(int id)方法。 这是MiBeanService的源代码。

@Component  
public class MiBeanService {  
    private static List<MiBean> miBeans = new ArrayList<>();  
 static {  
        miBeans.add(new MiBean(1, "valor uno"));  
  miBeans.add(new MiBean(2, "valor dos"));  
  miBeans.add(new MiBean(3, "valor tres"));  
  }  
    public MiBean getBean(int id) {  
        MiBean miBean =  
                miBeans.stream()  
                        .filter(t -> t.getCodigo()==id)  
                        .findFirst()  
                        .get();  
 return miBean;  
  }  
}

如果方法getBean(int id) 在ListmiBeans中找不到值时,会抛出NoSuchElementException。这个异常会被controller捕获并抛出一个BeanNotFoundException

BeanNotFoundException如下所示:

@ResponseStatus(HttpStatus.NOT_FOUND)  
public class BeanNotFoundException  extends RuntimeException {  
    public BeanNotFoundException(String message) {  
        super(message);  
  }  
}

这个简单的类继承RuntimeException并且被@ResponseStatus(HttpStatus.NOT_FOUND) 注解,将返回一个404码给客户端。

现在如果我们发起大于3的请求,将会接收到这样一个返回:

https://dzone.com/storage/temp/10729663-captura1.png

但是正如我们所说,我们想要定制错误信息。创建一个新类用于定义错误信息。这个类是ExceptionResponse,代码如下:

public class ExceptionResponse {  
    private Date timestamp;  
 private String mensaje;  
 private String detalles;  
 private String httpCodeMessage;  
 public ExceptionResponse(Date timestamp, String message, String details,String httpCodeMessage) {  
        super();  
 this.timestamp = timestamp;  
 this.mensaje = message;  
 this.detalles = details;  
 this.httpCodeMessage=httpCodeMessage;  
  }  
    public String getHttpCodeMessage() {  
        return httpCodeMessage;  
  }  
    public Date getTimestamp() {  
        return timestamp;  
  }  
    public String getMensaje() {  
        return mensaje;  
  }  
    public String getDetalles() {  
        return detalles;  
  }  
}

这个类表明BeanNotFoundException抛出时应该返回的JSON对象。现在我们写配置Spring抛出JSON对象的代码。

@ControllerAdvice  
@RestController  
public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {  
    @ExceptionHandler(BeanNotFoundException.class)  
    public final ResponseEntity<ExceptionResponse> handleNotFoundException(BeanNotFoundException ex, WebRequest request) {  
        ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), ex.getMessage(),  
  request.getDescription(false),HttpStatus.NOT_ACCEPTABLE.getReasonPhrase());  
 return new ResponseEntity<ExceptionResponse>(exceptionResponse, HttpStatus.NOT_ACCEPTABLE);  
  }  
}

这个类必须继承处理公共异常的ResponseEntityExceptionHandler类。

我们使用@ControllerAdvice@RestController 进行注解。

@ControllerAdvice是从@Component中来的,用于处理异常的类。作为被@RestController标记的类,它只处理REST controller抛出的异常。

handleNotFoundException方法中,我们定义当BeanNotFoundException 异常被抛出时,我们必须返回ExceptionResponse对象。通过创建一个ResponseEntity对象,我们可以方便的初始化。

注意它定义了HTTP返回码,在这个示例中,我们返回406,而不是404。事实上,在我们的例子中,我们可以移除BeanNotFoundException@ResponseStatus(HttpStatus.NOT_FOUND) 注解,有没有这个注解没啥区别。

这样,我们就定制了输出,如下图:

https://dzone.com/storage/temp/10729701-captura2.png