SpringBoot接口 - 如何優雅的對接口返回內容統一封裝?

在以SpringBoot開發Restful接口時,統一返回方便前端進行開發和封裝,以及出現時給出響應編碼和信息。@pdai

RESTful API接口?

  • 什麼是 REST

Representational State Transfer,翻譯是“表現層狀態轉化”。可以總結爲一句話:REST 是所有 Web 應用都應該遵守的架構設計指導原則

面向資源是 REST 最明顯的特徵,對於同一個資源的一組不同的操作。資源是服務器上一個可命名的抽象概念,資源是以名詞爲核心來組織的,首先關注的是名詞。REST 要求,必須通過統一的接口來對資源執行各種操作。對於每個資源只能執行一組有限的操作。

  • 什麼是 RESTful API

符合 REST 設計標準的 API,即 RESTful API。REST 架構設計,遵循的各項標準和準則,就是 HTTP 協議的表現,換句話說,HTTP 協議就是屬於 REST 架構的設計模式。比如,無狀態,請求-響應。

Restful相關文檔可以參考 https://restfulapi.net/

爲什麼要統一封裝接口

現在大多數項目採用前後分離的模式進行開發,統一返回方便前端進行開發和封裝,以及出現時給出響應編碼和信息。

以查詢某個用戶接口而言,如果沒有封裝, 返回結果如下

{
  "userId": 1,
  "userName": "趙一"
}

如果封裝了,返回正常的結果如下:

{
  "timestamp": 11111111111,
  "status": 200,
  "message": "success",
  "data": {
    "userId": 1,
    "userName": "趙一"
  }
}

異常返回結果如下:

{
  "timestamp": 11111111111,
  "status": 10001,
  "message": "User not exist",
  "data": null
}

實現案例

如何實現上面的封裝呢?

狀態碼封裝

這裏以常見的狀態碼爲例,包含responseCode 和 description兩個屬性。

如果還有其它業務狀態碼,也可以放到這個類中。

/**
 * @author pdai
 */
@Getter
@AllArgsConstructor
public enum ResponseStatus {

    SUCCESS("200", "success"),
    FAIL("500", "failed"),

    HTTP_STATUS_200("200", "ok"),
    HTTP_STATUS_400("400", "request error"),
    HTTP_STATUS_401("401", "no authentication"),
    HTTP_STATUS_403("403", "no authorities"),
    HTTP_STATUS_500("500", "server error");

    public static final List<ResponseStatus> HTTP_STATUS_ALL = Collections.unmodifiableList(
            Arrays.asList(HTTP_STATUS_200, HTTP_STATUS_400, HTTP_STATUS_401, HTTP_STATUS_403, HTTP_STATUS_500
            ));

    /**
     * response code
     */
    private final String responseCode;

    /**
     * description.
     */
    private final String description;

}

返回內容封裝

包含公共的接口返回時間,狀態status, 消息message, 以及數據data。

考慮到數據的序列化(比如在網絡上傳輸),這裏data有時候還會extends Serializable。

@Data
@Builder
public class ResponseResult<T> {

    /**
     * response timestamp.
     */
    private long timestamp;

    /**
     * response code, 200 -> OK.
     */
    private String status;

    /**
     * response message.
     */
    private String message;

    /**
     * response data.
     */
    private T data;

    /**
     * response success result wrapper.
     *
     * @param <T> type of data class
     * @return response result
     */
    public static <T> ResponseResult<T> success() {
        return success(null);
    }

    /**
     * response success result wrapper.
     *
     * @param data response data
     * @param <T>  type of data class
     * @return response result
     */
    public static <T> ResponseResult<T> success(T data) {
        return ResponseResult.<T>builder().data(data)
                .message(ResponseStatus.SUCCESS.getDescription())
                .status(ResponseStatus.SUCCESS.getResponseCode())
                .timestamp(System.currentTimeMillis())
                .build();
    }

    /**
     * response error result wrapper.
     *
     * @param message error message
     * @param <T>     type of data class
     * @return response result
     */
    public static <T extends Serializable> ResponseResult<T> fail(String message) {
        return fail(null, message);
    }

    /**
     * response error result wrapper.
     *
     * @param data    response data
     * @param message error message
     * @param <T>     type of data class
     * @return response result
     */
    public static <T> ResponseResult<T> fail(T data, String message) {
        return ResponseResult.<T>builder().data(data)
                .message(message)
                .status(ResponseStatus.FAIL.getResponseCode())
                .timestamp(System.currentTimeMillis())
                .build();
    }

}

接口返回時調用

在接口返回時調用, 以用戶接口爲例

/**
 * @author pdai
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private IUserService userService;

    /**
     * @param user user param
     * @return user
     */
    @ApiOperation("Add/Edit User")
    @PostMapping("add")
    public ResponseResult<User> add(User user) {
        if (user.getId()==null || !userService.exists(user.getId())) {
            user.setCreateTime(LocalDateTime.now());
            user.setUpdateTime(LocalDateTime.now());
            userService.save(user);
        } else {
            user.setUpdateTime(LocalDateTime.now());
            userService.update(user);
        }
        return ResponseResult.success(userService.find(user.getId()));
    }


    /**
     * @return user list
     */
    @ApiOperation("Query User One")
    @GetMapping("edit/{userId}")
    public ResponseResult<User> edit(@PathVariable("userId") Long userId) {
        return ResponseResult.success(userService.find(userId));
    }
}

示例源碼

https://github.com/realpdai/tech-pdai-spring-demos

更多內容

告別碎片化學習,無套路一站式體系化學習後端開發: Java 全棧知識體系(https://pdai.tech)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章