V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Vimax
V2EX  ›  Java

请教如何有效的使用 ResponseEntity?

  •  
  •   Vimax · 2020-06-24 10:57:35 +08:00 · 3494 次点击
    这是一个创建于 1399 天前的主题,其中的信息可能已经有所发展或是发生改变。

    ResponseEntity 标识整个 http 相应:状态码、头部信息以及相应体内容。因此我们可以使用其对 http 响应实现完整配置。

    目前打算使用 ResponseEntity 替代自定义实体响应对象。请教下如何有效的使用 ResponseEntity,比如@ResponseEntity如何自定义返回业务的错误码?以及推荐使用 ResponseEntity 作为返回对象吗?

    之前都是通过自定义code,msg,data属性对象,通过@ResponseBody返回给前端。

    spring 封装了很多好用的东西,所以打算尝试下@ResponseEntity

     @GetMapping("{id}")
        public ResponseEntity<UserInfo> getUserById(@PathVariable("id") Long id) {
            UserInfo user = userInfoService.getById(id);
            boolean flag = ObjectUtils.isEmpty(user);
            if (flag) {
                return ResponseEntity.notFound().build();
            }
            return ResponseEntity.ok(user);
        }
    

    上面的根据 id 查询用户,查询到内容就返回 200 状态码,查询不到就返回 404 。

    但是有些业务有多个错误类型,这时用 ResponseEntity,只能返回 http 状态码就显得有些不足。

    如果再封装个返回类型,ResponseResult 对象,里面存msg,code,data

    @Data
    @NoArgsConstructor
    public class ResponseResult<T> {
    
        @NonNull
        private Integer code;
        @NonNull
        private String msg;
        private T data;
    }
    

    然后再用ResponseEntity<ResponseResult>封装返回给前端。

       @GetMapping("{id}")
        public ResponseEntity<ResponseResult<UserInfo>> getUserById(@PathVariable("id") Long id) {
            UserInfo user = userInfoService.getById(id);
            boolean flag = ObjectUtils.isEmpty(user);
            if (flag) {
                return ResponseEntity.notFound().build();
            }
            ResponseResult<UserInfo> userResult = new ResponseResult();
            userResult.setData(user);
            return ResponseEntity.ok(userResult);
        }
        
    

    这样会不会多此一举,不如直接用@ResponseBody返回ResponseResult就可以了。

    当然,ResponseEntity 好处是可以返回 404 这些浏览器状态码。

    第 1 条附言  ·  2020-06-24 13:12:33 +08:00
    采纳 3L 的回答。
    4 条回复    2020-06-24 13:11:35 +08:00
    hantsy
        1
    hantsy  
       2020-06-24 11:06:20 +08:00
    这种封装 ResponseResult 是脱了裤子放屁。
    Oktfolio
        2
    Oktfolio  
       2020-06-24 11:11:45 +08:00   ❤️ 1
    package com.oktfolio.tero.common;

    import com.fasterxml.jackson.annotation.JsonFormat;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.google.common.base.Strings;
    import com.oktfolio.tero.common.enums.ResultCode;
    import com.oktfolio.tero.common.enums.ResultCodeEnum;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;

    import javax.annotation.Nonnull;
    import javax.annotation.Nullable;
    import java.time.LocalDateTime;
    import java.util.Objects;

    /**
    * @author oktfolio [email protected]
    * @date 2020/06/08
    */
    @JsonInclude(JsonInclude.Include.NON_NULL)
    public class ResultEntity<T> {
    protected String code;
    protected String message;
    protected T data;
    protected HttpStatus status;
    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
    protected LocalDateTime datetime;

    public String getCode() {
    return code;
    }

    public String getMessage() {
    return message;
    }

    public T getData() {
    return data;
    }

    public HttpStatus getStatus() {
    return status;
    }

    public LocalDateTime getDatetime() {
    return datetime;
    }

    private ResultEntity() {
    }

    public ResultEntity(String code, String message, T data, HttpStatus status, LocalDateTime datetime) {
    this.code = code;
    this.message = message;
    this.data = data;
    this.status = status;
    this.datetime = datetime;
    }

    public static Builder builder() {
    return new Builder();
    }

    public static class Builder {

    protected String code;
    protected String message;
    protected HttpStatus status;
    protected LocalDateTime datetime;

    public Builder code(String code) {
    this.code = code;
    return this;
    }

    public Builder message(String message) {
    this.message = message;
    return this;
    }

    public Builder datetime(LocalDateTime datetime) {
    this.datetime = datetime;
    return this;
    }

    public Builder status(@Nonnull HttpStatus status) {
    this.status = status;
    return this;
    }

    public <T> ResultEntity<T> data(@Nullable T data) {
    return new ResultEntity<>(code, message, data, status, datetime);
    }

    public <T> ResultEntity<T> build() {
    return this.data(null);
    }

    }

    public static <T> ResultEntity<T> ok() {
    return ResultEntity.builder()
    .status(HttpStatus.OK)
    .build();
    }

    public static <T> ResultEntity<T> created() {
    return ResultEntity.builder()
    .status(HttpStatus.CREATED)
    .build();
    }

    public static <T> ResultEntity<T> noContent() {
    return ResultEntity.builder()
    .status(HttpStatus.NO_CONTENT)
    .build();
    }

    public static <T> ResultEntity<T> ok(T data) {
    return ResultEntity.builder()
    .status(HttpStatus.OK)
    .datetime(LocalDateTime.now())
    .data(data);
    }

    public static <T> ResultEntity<T> created(T data) {
    return ResultEntity.builder()
    .status(HttpStatus.CREATED)
    .data(data);
    }

    public static <T> ResultEntity<T> of(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(resultCode.status())
    .code(resultCode.value())
    .message(resultCode.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> error() {
    return ResultEntity.builder()
    .status(ResultCodeEnum.ERROR.status())
    .code(ResultCodeEnum.ERROR.value())
    .message(ResultCodeEnum.ERROR.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> error(@Nonnull HttpStatus status, @Nonnull String message) {
    return ResultEntity.builder()
    .status(status)
    .code(ResultCodeEnum.ERROR.value())
    .message(message)
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> notFound(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.NOT_FOUND)
    .code(resultCode.value())
    .message(resultCode.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> badRequest(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.BAD_REQUEST)
    .code(resultCode.value())
    .message(resultCode.message())
    .build();
    }

    public static <T> ResultEntity<T> unauthorized(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.UNAUTHORIZED)
    .code(resultCode.value())
    .message(resultCode.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> unauthorized(String message) {
    return ResultEntity.builder()
    .status(HttpStatus.UNAUTHORIZED)
    .code(ResultCodeEnum.ERROR.value())
    .message(message)
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> forbidden(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.FORBIDDEN)
    .code(resultCode.value())
    .message(resultCode.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> created(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.CREATED)
    .code(resultCode.value())
    .message(resultCode.message())
    .build();
    }

    public static <T> ResultEntity<T> internalServerError() {
    return ResultEntity.builder()
    .status(ResultCodeEnum.INTERNAL_SERVER_ERROR.status())
    .code(ResultCodeEnum.INTERNAL_SERVER_ERROR.value())
    .message(ResultCodeEnum.INTERNAL_SERVER_ERROR.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public static <T> ResultEntity<T> internalServerError(@Nonnull ResultCode resultCode) {
    return ResultEntity.builder()
    .status(HttpStatus.INTERNAL_SERVER_ERROR)
    .code(resultCode.value())
    .message(resultCode.message())
    .datetime(LocalDateTime.now())
    .build();
    }

    public ResponseEntity<Object> responseEntity() {
    if (Objects.isNull(this.data)
    && Strings.isNullOrEmpty(this.code)
    && Strings.isNullOrEmpty(this.message)
    && !Objects.isNull(this.status)) {
    return new ResponseEntity<>(this.getStatus());
    } else {
    return new ResponseEntity<>(this, this.getStatus());
    }
    }
    }

    我是这么玩的。
    hantsy
        3
    hantsy  
       2020-06-24 11:15:12 +08:00   ❤️ 2
    业务中所有正常路径直接返回,全部需要 Http Status 标志。如 200,201,204 。

    使用 Spring 时,所有的异常路径可以封装成 Exception,集成处理。

    Exception 处理除了要反应正确的 Http Status (常见的,除了一些安全框架 401,403 外,如 404,400,409,422 等),还可以带常见的辅助信息。如果非常要一个所谓的业务异常代码,在异常处理中加入。

    https://github.com/hantsy/spring-microservice-sample/blob/master/post-service/src/main/java/com/hantsylabs/sample/springmicroservice/post/PostExceptionHandler.java#L31
    Vimax
        4
    Vimax  
    OP
       2020-06-24 13:11:35 +08:00
    @hantsy 采纳并学习。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1423 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:28 · PVG 01:28 · LAX 10:28 · JFK 13:28
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.