请教如何有效的使用 ResponseEntity?

2020-06-24 10:57:35 +08:00
 Vimax

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 这些浏览器状态码。

3509 次点击
所在节点    Java
4 条回复
hantsy
2020-06-24 11:06:20 +08:00
这种封装 ResponseResult 是脱了裤子放屁。
Oktfolio
2020-06-24 11:11:45 +08:00
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 oktfolio@gmail.com
* @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
2020-06-24 11:15:12 +08:00
业务中所有正常路径直接返回,全部需要 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
2020-06-24 13:11:35 +08:00
@hantsy 采纳并学习。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/684377

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX