在 Spring Boot 3 中迁移 HttpStatus 到 HttpStatusCode

1、概览

本文将带你了解如何在 Spring Boot 应用中使用 HttpStatusCode,重点是 3.3.3 版中引入的最新增强功能。通过这些增强功能,HttpStatusCode 已被纳入 HttpStatus 实现,从而简化了我们处理 HTTP 状态码的方式。

这些改进的主要目的是提供一种更灵活、更可靠的方法来处理标准和自定义 HTTP 状态码,使我们在处理 HTTP 响应时具有更高的灵活性和可扩展性,同时保持向后兼容性。

2、HttpStatus 枚举

Spring 3.3.3 之前,HTTP 状态码在 HttpStatus 中表示为枚举。这限制了自定义或非标准 HTTP 状态码的使用,因为枚举是一组固定的预定义值。

尽管 HttpStatus 类尚未被弃用,但一些返回原始 Integer 状态码的枚举和方法(如 getRawStatusCode()rawStatusCode())现已被弃用。

使用 @ResponseStatus 注解来提高代码的可读性仍然是我们推荐的方法

我们可以将 HttpStatusHttpStatusCode 结合使用,以实现更灵活的 HTTP 响应管理:

@GetMapping("/exception")
public ResponseEntity<String> resourceNotFound() {
    HttpStatus statusCode = HttpStatus.NOT_FOUND;
    if (statusCode.is4xxClientError()) {
        return new ResponseEntity<>("Resource not found", HttpStatusCode.valueOf(404));
    }
    return new ResponseEntity<>("Resource found", HttpStatusCode.valueOf(200));
}

3、HttpStatusCode 接口

HttpStatusCode 接口旨在支持 HttpStatus 中预定义状态码之外的自定义状态码。它有 8 个实例方法:

  • is1xxInformational()
  • is2xxSuccessful()
  • is3xxRedirection()
  • is4xxClientError()
  • is5xxServerError()
  • isError()
  • isSameCodeAs(HttpStatusCode other)
  • value()

这些方法不仅提高了处理不同 HTTP 状态的灵活性,还简化了检查响应状态的过程,从而提高了状态码管理的清晰度和效率。

示例如下:

@GetMapping("/resource")
public ResponseEntity successStatusCode() {
    HttpStatusCode statusCode = HttpStatusCode.valueOf(200);
    if (statusCode.is2xxSuccessful()) {
        return new ResponseEntity("Success", statusCode);
    }

    return new ResponseEntity("Moved Permanently", HttpStatusCode.valueOf(301));
}

3.1、valueOf(int) 静态方法

本方法为给定的 int 值返回一个 HttpStatusCode 对象。输入参数必须是三位正数,否则会抛出 IllegalArgumentException 异常。

valueOf() 方法将状态码映射到 HttpStatus 中的相应枚举值。如果没有与所提供状态码匹配的现有条目,该方法默认返回 DefaultHttpStatusCode 的实例。

DefaultHttpStatusCode 类实现了 HttpStatusCode,并直接实现了 value() 方法,该方法返回初始化时使用的原始 Integer 值。这种方法确保了所有 HTTP 状态码,无论是自定义的还是非标准的,都能轻松拿捏:

@GetMapping("/custom-exception")
public ResponseEntity<String> goneStatusCode() {
    throw new ResourceGoneException("Resource Gone", HttpStatusCode.valueOf(410));
}

4、在自定义异常中使用 HttpStatusCode

接下来,看看如何在 ExceptionHandler 中使用带有 HttpStatusCode 的自定义异常。我们使用 @ControllerAdvice 注解在所有 Controller 中全局处理异常,并使用 @ExceptionHandler 注解管理自定义异常的实例。

这种方法将异常处理集中在 Spring MVC 应用中,使代码更简洁、更易维护。

4.1、@ControllerAdvice 和 @ExceptionHandler

@ControllerAdvice 处理全局异常,而 @ExceptionHandler 则管理自定义异常实例,以返回包含异常消息和状态码的一致 HTTP 响应。

来看看如何在实践中使用这两种注解:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(CustomException.class)
    public ResponseEntity<String> handleGoneException(CustomException e) {
        return new ResponseEntity<>(e.getMessage(), e.getStatusCode());
    }
}

4.2、自定义异常

接下来,让我们定义一个 CustomException(自定义异常)类,该类基础了 RuntimeException,并包含一个 HttpStatusCode 字段,可自定义信息和 HTTP 状态码,以便更精确地处理错误:

public class CustomException extends RuntimeException {

    private final HttpStatusCode statusCode;

    public CustomException(String message, HttpStatusCode statusCode) {
        super(message);
        this.statusCode = statusCode;
    }

    public HttpStatusCode getStatusCode() {
        return statusCode;
    }
}

5、总结

HttpStatus 枚举包含一组有限的标准 HTTP 状态码,在旧版本的 Spring 中可以很好地满足大多数用例的要求。不过,它们在定义自定义状态码时缺乏灵活性。

Spring Boot 3.3.3 引入了 HttpStatusCode,允许我们定义自定义状态码,从而解决了这一限制。这提供了一种更灵活的方式来处理 HTTP 状态码,并为常用状态码(如 is2xxSuccessful()is3xxRedirection())提供了实例方法,最终允许对响应处理进行更细粒度的控制。


Ref:https://www.baeldung.com/spring-boot-httpstatuscode