1. 程式人生 > 程式設計 >API介面開發(一):介面開發返回結果解決方案

API介面開發(一):介面開發返回結果解決方案

摘要

採用前後端分離的方式進行專案開發,那麼前後端互動比較好的方式是採用HTTP+JSON。如何介面返回結果更加簡潔,更加優雅,也更加合理,並且讓前端開發人員看得明白,後端開發者也並不會因此而增加工作量呢?

正文開始

Hello,各位,好久不見了。一直在籌劃個人網站2020版本改版的事情,所以,本篇文章,也是2019年最後一篇了,當然,也得花一些心思,爭取把我想要說的話,都一一說出來,說明白,說透徹。

採用前後端分離的方式進行專案開發,那麼前後端互動比較好的方式是採用HTTP+JSON。如何介面返回結果更加簡潔,更加優雅,也更加合理,並且讓前端開發人員看得明白,後端開發者也並不會因此而增加工作量呢?

為此,我寫了一套關於API介面開發返回結果解決方案, api-result,已將其開源,並上傳到中央倉庫,歡迎各位批評和指正。

API講解

實體類

提供了滿足各場景使用的實體類,如下:

ResultModel

這個類是基礎實體類,有如下屬性:

success:返回結果標識,是一個布林值,true / false(成功 / 失敗)

message:描述資訊,錯誤時,可以在這裡填寫錯誤的詳細資訊

data:資料,是一個泛型,可以是陣列或者物件等等,成功並且需要返回資料時,才有該引數

ApiResultModel

結構關係如下:

 ResultModel
 └── ApiResultModel
複製程式碼

在這個類裡面增加了 code 屬性,也是一個泛型,你可以自定義你的返回碼型別,可以是整數,或者字串。

PageResultModel

結構關係如下:

 ResultModel
 └── PageResultModel
複製程式碼

這個類主要主要分頁返回結果,所以,增加了以下屬性:

total:資料總條數,Long型

size:每頁條數,整數

pages:總頁數,Long型

current:當前頁,Long型

Helper工具類

幫助我們操作實體類,具體有哪些helper呢?如下:

ResultHelper

ResultHelper是與ResultModel對應的

success(String message)

成功,攜帶描述資訊

success(String message,T data)

成功,攜帶描述資訊和資料

error(String message)

錯誤,攜帶詳細的描述資訊

ApiResultHelper

ApiResultHelper是與ApiResultModel對應的

success(S code,String message)

成功,攜帶返回碼和描述資訊

success(S code,String message,T data)

成功,攜帶返回碼、描述資訊和資料

error(S code,String message)

錯誤,攜帶錯誤碼和詳細描述資訊

PageResultHelper

PageResultHelper是與PageResultModel對應的

success(String message)

成功,攜帶描述資訊

success(String message,T data)

成功,攜帶描述資訊和資料

success(String message,T data,long total,int size,long pages,long current)

成功,攜帶描述資訊、資料、總數、每頁條數、總頁數、當前頁

error(String message)

錯誤,攜帶詳細的描述資訊

快速入門

我們為你提供了三個實體類,以滿足不同場景,ResultModel適用於通常返回結果,ApiResultModel適用於介面開發返回結果,PageResultModel適用於分頁返回結果。也分別為這三個實體類提供了各自的Helper,所以,你可以直接使用這些Helper進行返回。當然,我推薦的使用方式是,先為各Helper編寫工具類,再通過工具類進行返回,這樣可能更加合理定製自己的返回工具類。

利用Helper進行返回

首先我們來看一個簡單的示例程式碼:

/**
 * 新增方法示例
 * @return {@link ResultModel}
 */
@ApiOperation(value = "新增方法示例")
@PostMapping
public ResultModel<?> add() {
  return ResultHelper.success("新增成功");
}
複製程式碼

返回結果:

{
  "success": true,"message": "新增成功"
}
複製程式碼

注:這只是一個介面返回示例,而不是說新增介面應該這樣寫。

編寫返回結果工具類

比如,我們可以寫一個ResultUtils工具類來操作ResultHelper。如下示例:

/**
 * 成功示例
 * @return {@link ResultModel}
 */
public static ResultModel <?> success() {
    return ResultHelper.success("Success");
}
複製程式碼

使用返回結果工具類

我門就可以呼叫ResultUtils類裡面的方法,如下示例:

/**
* 成功示例
* @return {@link ResultModel}
*/
@ApiOperation(value = "成功示例")
@DeleteMapping
public ResultModel<?> success() {
   return ResultUtils.success();
}
複製程式碼

印象結果:

{
 "success": true,"message": "Success"
}
複製程式碼

使用示例

示例圖

測試介面預覽

介面示例

Models

Models

返回成功結果示例

/**
 * 刪除方法示例
 * @return {@link ResultModel}
 */
@ApiOperation(value = "刪除方法示例")
@DeleteMapping
public ResultModel<?> delete() {
    return ResultUtils.success();
}
複製程式碼

響應結果:

{
  "success": true,"message": "Success"
}
複製程式碼

返回失敗結果示例

如果操作出錯了,我們怎麼返回呢?我們來看一下:

/**
 * 修改方法示例
 * @return {@link ResultModel}
 */
@ApiOperation(value = "修改方法示例")
@PutMapping
public ResultModel<?> update() {
    return ResultUtils.error("修改失敗");
}
複製程式碼

返回結果:

{
  "success": false,"message": "修改失敗"
}
複製程式碼

返回查詢結果示例

值得一提的話,就是查詢方法了,我們看一下吧

/**
 * 查詢方法示例
 * @return {@link ResultModel}
 */
@ApiOperation(value = "查詢方法示例")
@GetMapping
public ResultModel<?> get() {
    List<Map<String,String>> list = new ArrayList<>();
    Map<String,String> map1 = new HashMap<>();

    map1.put("name","張飛");
    map1.put("desc","燕人張飛");
    list.add(map1);

    Map<String,String> map2 = new HashMap<>();
    map2.put("name","趙雲");
    map2.put("desc","常山趙子龍");
    list.add(map2);

    Map<String,String> map3 = new HashMap<>();
    map3.put("name","關羽");
    map3.put("desc","溫酒斬華雄");
    list.add(map3);

    return ResultUtils.success(list);
}
複製程式碼

看一下響應結果吧,是否如你所願:

{
  "success": true,"message": "Success","data": [
    {
      "name": "張飛","desc": "燕人張飛"
    },{
      "name": "趙雲","desc": "常山趙子龍"
    },{
      "name": "關羽","desc": "溫酒斬華雄"
    }
  ]
}
複製程式碼

介面返回資料示例

/**
* 介面返回資料示例
* @return {@link ApiResultModel}
*/
@ApiOperation(value = "介面返回資料示例")
@GetMapping("/api-data")
public ApiResultModel<Integer,?> apiData() {
   return ApiResultUtils.success(getData());
}
複製程式碼

響應結果:

{
  "success": true,"desc": "溫酒斬華雄"
    }
  ],"code": 0
}
複製程式碼

介面返回失敗結果示例

/**
 * API介面錯誤返回示例
 * @return {@link ApiResultModel}
 */
@ApiOperation(value = "API介面錯誤返回示例")
@GetMapping("/api-error")
public ApiResultModel<Integer,?> apiError() {
    return ApiResultUtils.error(1101,"API介面錯誤返回示例");
}
複製程式碼

響應結果:

{
  "success": false,"message": "API介面錯誤返回示例","code": 1101
}
複製程式碼

分頁返回資料示例

/**
 * 分頁返回資料示例
 * @return {@link ApiResultModel}
 */
@ApiOperation(value = "分頁返回資料示例")
@GetMapping("/page")
public PageResultModel<?> page() {
    return PageResultUtils.success(getData(),100,10,1);
}
複製程式碼

響應結果:

{
  "success": true,"total": 100,"size": 10,"pages": 10,"current": 1
}
複製程式碼

工具類示例

返回結果工具類

package com.fengwenyi.api_example.util;

import com.fengwenyi.api_result.helper.ResultHelper;
import com.fengwenyi.api_result.model.ResultModel;

/**
 * 返回結果封裝工具類
 * @author Erwin Feng[[email protected]]
 * @since 2019/11/30 13:54
 */
public class ResultUtils {

    /**
     *  成功
     * @return {@link ResultModel}
     */
    public static ResultModel <?> success() {
        return ResultHelper.success("Success");
    }

    /**
     *  成功,攜帶資料
     * @param data 資料
     * @param <T>  資料的型別
     * @return {@link ResultModel}
     */
    public static <T> ResultModel <T> success(T data) {
        return ResultHelper.success("Success",data);
    }

    /**
     *  錯誤,攜帶詳細的錯誤描述資訊
     * @param message 詳細的錯誤描述資訊
     * @return {@link ResultModel}
     */
    public static ResultModel <?> error(String message) {
        return ResultHelper.error(message);
    }

}
複製程式碼

API介面返回結果工具類

package com.fengwenyi.api_example.util;

import com.fengwenyi.api_result.helper.ApiResultHelper;
import com.fengwenyi.api_result.model.ApiResultModel;

/**
 * API介面返回結果工具類
 * @author Erwin Feng[[email protected]]
 * @since 2019/12/1 20:10
 */
public class ApiResultUtils {

    /**
     * 成功,攜帶返回碼和描述資訊
     * @return {@link ApiResultModel}
     */
    public static ApiResultModel<Integer,?> success() {
        return ApiResultHelper.success(0,"Success");
    }

    /**
     * 成功,攜帶返回碼、描述資訊和資料
     * @param data 資料
     * @param <T>  資料的型別
     * @return {@link ApiResultModel}
     */
    public static <T> ApiResultModel<Integer,T> success(T data) {
        return ApiResultHelper.success(0,"Success",data);
    }

    /**
     * 出錯,攜帶錯誤嗎和詳細描述資訊
     * @param code 返回碼
     * @param message 相信描述資訊
     * @return {@link ApiResultModel}
     */
    public static ApiResultModel<Integer,?> error(int code,String message) {
        return ApiResultHelper.error(code,message);
    }
}
複製程式碼

分頁返回結果工具類

package com.fengwenyi.api_example.util;

import com.fengwenyi.api_result.helper.PageResultHelper;
import com.fengwenyi.api_result.model.PageResultModel;

/**
 * 分頁返回結果工具類
 * @author Erwin Feng[[email protected]]
 * @since 2019/12/1 20:32
 */
public class PageResultUtils {

    /**
     * 成功,攜帶分頁相關資料以及資訊
     * @param data     資料
     * @param total    資料總條數
     * @param size     每頁條數
     * @param pages    總頁數
     * @param current  當前頁
     * @param <T>      資料型別
     * @return {@link PageResultModel}
     */
    public static <T> PageResultModel<T> success(T data,long total,int size,long pages,long current) {
        return PageResultHelper.success("Success",data,total,size,pages,current);
    }

}
複製程式碼

解析返回結果示例

這裡補充一下,關於如何解析返回的json字串,談談我的看法吧。返回的是一個json格式的字串,這裡我用fastjson來寫解析示例。我們通常會將請求資料封裝為一個通用方法或者工具類,只需要返回資料,當然,如果失敗,或者出現異常,都在這裡處理。

常用返回結果解析示例

/**
 * 解析常用返回結果示例
 * @return 資料
 */
public Object parseResult() {
    String result = "";
    ResultModel<?> resultModel = JSON.parseObject(result,ResultModel.class);
    Boolean success = resultModel.getSuccess();
    if (success != null && success) {
        return resultModel.getData();
    } else {
        // 異常資訊
        String message = resultModel.getMessage();
        // 異常處理
        throw new DataParseException(message);
    }
}
複製程式碼

介面返回結果解析示例

/**
 * 解析介面返回結果示例
 * @return 資料
 */
public Object parseApiResult() {
    String apiResult = "";
    ApiResultModel<?,?> apiResultModel = JSON.parseObject(apiResult,ApiResultModel.class);
    Boolean success = apiResultModel.getSuccess();
    if (success != null && success) {
        return apiResultModel.getData();
    } else {
        Object code = apiResultModel.getCode();
        String message = apiResultModel.getMessage();
        // 根據介面錯誤碼分別進行處理
        // ...
        return null;
    }
}
複製程式碼

分頁返回結果解析示例

這裡與上面略有不同,因為,增加了一些欄位,所以,我們可以藉助bean來返回。

/**
 * 解析分頁返回結果示例
 * @return {@link PageResultDataBean}
 */
public PageResultDataBean parsePageResult() {
    String pageResult = "";
    PageResultModel<List<?>> pageResultModel = JSON.parseObject(pageResult,PageResultModel.class);
    Boolean success = pageResultModel.getSuccess();
    if (success != null && success) {
        List<?> data = pageResultModel.getData();
        Long total = pageResultModel.getTotal();
        Integer size = pageResultModel.getSize();
        Long pages = pageResultModel.getPages();
        Long current = pageResultModel.getCurrent();
        return new PageResultDataBean()
                .setTotal(total)
                .setSize(size)
                .setPages(pages)
                .setCurrent(current)
                .setData(data);
    } else {
        // 異常資訊
        String message = pageResultModel.getMessage();
        // 異常處理
        throw new DataParseException(message);
    }
}
複製程式碼

以上,這一切都是否如你所願呢?歡迎評論留言告訴我。

連結

[1] api-result原始碼 | github

[2] api-result原始碼 | 碼雲

[3] api-result中央倉庫

[4] 測試示例程式碼