SpringBoot定義優(yōu)雅全局統(tǒng)一Restful API 響應(yīng)框架

假如現(xiàn)在有一個(gè)Java項(xiàng)目,老板讓你做項(xiàng)目組長(zhǎng),定義項(xiàng)目基礎(chǔ)框架,系統(tǒng)技術(shù)架構(gòu)選型, 你應(yīng)該如何設(shè)計(jì)一個(gè)規(guī)范的統(tǒng)一的Restful API 響應(yīng)框架呢

思考

目前項(xiàng)目開(kāi)發(fā),都是基于前后端分離模式開(kāi)發(fā)的,基于后端模板引擎那一套,可能已經(jīng)不適用一些項(xiàng)目開(kāi)發(fā)流程,和當(dāng)下開(kāi)發(fā)模式了,尤其在要寫(xiě)比較大型項(xiàng)目,前后端項(xiàng)目拆分,團(tuán)隊(duì)共同開(kāi)發(fā)那是必不可少的

目前的前后端開(kāi)發(fā)大部分?jǐn)?shù)據(jù)的傳輸格式都是json,因此定義一個(gè)統(tǒng)一規(guī)范的數(shù)據(jù)格式有利于前后端的交互與UI的展示凫碌。

返回的統(tǒng)一接口形式應(yīng)該包含這些內(nèi)容

  1. 是否響應(yīng)成功
  2. 響應(yīng)狀態(tài)碼
  3. 狀態(tài)碼描述
  4. 響應(yīng)數(shù)據(jù)
  5. 接口調(diào)用時(shí)間
  6. 其他標(biāo)識(shí)符

按照這些我們可以定義統(tǒng)一的標(biāo)準(zhǔn)結(jié)果返回

響應(yīng)枚舉

前三者可以定義為 success,code,message

package cn.soboys.springbootrestfulapi.common.resp;

import lombok.Data;
import lombok.Getter;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author 公眾號(hào) 程序員三時(shí)
 * @version 1.0
 * @date 2023/4/28 22:39
 * @webSite https://github.com/coder-amiao
 * 響應(yīng)結(jié)果枚舉
 */
@Getter
public enum ResultCodeEnum{
    SUCCESS(true, 200, "成功"),
    FAIL(false, 400, "請(qǐng)求失敗"),

    NOT_FOUND(false, 404, "接口不存在"),
    FORBIDDEN(false, 403, "資源拒絕訪問(wèn)"),
    UNAUTHORIZED(false, 401, "未認(rèn)證(簽名錯(cuò)誤)"),

    INTERNAL_SERVER_ERROR(false, 500, "服務(wù)器內(nèi)部錯(cuò)誤"),


    NULL_POINT(false, 200002, "空指針異常"),
    PARAM_ERROR(false, 200001, "參數(shù)錯(cuò)誤");

    /**
     * 響應(yīng)是否成功
     */
    private Boolean success;
    /**
     * 響應(yīng)狀態(tài)碼
     */
    private Integer code;
    /**
     * 響應(yīng)信息
     */
    private String message;


    ResultCodeEnum(Boolean success, Integer code, String message) {
        this.success = success;
        this.code = code;
        this.message = message;
    }
}

統(tǒng)一結(jié)果類(lèi)

  • 外部返回調(diào)用類(lèi)統(tǒng)一的結(jié)果方法 success,failure 因此構(gòu)造器私有
  • 內(nèi)置靜態(tài)方法凤价,直接返回對(duì)象
  • 便于自定義統(tǒng)一結(jié)果信息,使用鏈?zhǔn)骄幊潭栏蹋祷貙?duì)象類(lèi)本身 return this
  • 響應(yīng)數(shù)據(jù)為json格式茵乱,可定義為JsonObject或Map形式
package cn.soboys.springbootrestfulapi.common.resp;

import lombok.Data;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 公眾號(hào) 程序員三時(shí)
 * @version 1.0
 * @date 2023/4/28 22:47
 * @webSite https://github.com/coder-amiao
 * 統(tǒng)一響應(yīng)結(jié)果處理  使用鏈?zhǔn)骄幊?返回類(lèi)本身
 */
@Data
public class R {

    private Boolean success;

    private Integer code;

    private String message;

    /**
     * 接口請(qǐng)求時(shí)間戳
     */
    private Long timestamp;

    private Map<String, Object> data = new HashMap<>();


    private R setSuccess(Boolean success) {
        this.success = success;
        return this;
    }


    private R setMessage(String message) {
        this.message = message;
        return this;
    }

    private R setData(Map<String, Object> data) {
        this.data = data;
        return this;
    }

    private R setCode(Integer code) {
        this.code = code;
        return this;
    }

    private R() {
    }

    private R(Long timestamp) {
        this.timestamp = timestamp;
    }


    /**
     * 通用返回成功
     *
     * @return
     */
    public static R success() {
        return new R(System.currentTimeMillis())
                .setSuccess(ResultCodeEnum.SUCCESS.getSuccess())
                .setCode(ResultCodeEnum.SUCCESS.getCode())
                .setMessage(ResultCodeEnum.SUCCESS.getMessage());

    }

    /**
     * 通用返回失敗
     *
     * @return
     */
    public static R failure() {
        return new R(System.currentTimeMillis())
                .setSuccess(ResultCodeEnum.FAIL.getSuccess())
                .setCode(ResultCodeEnum.FAIL.getCode())
                .setMessage(ResultCodeEnum.FAIL.getMessage());

    }

    /**
     * 設(shè)置結(jié)果桨吊,形參為結(jié)果枚舉
     *
     * @param result
     * @return
     */
    public static R setResult(ResultCodeEnum result) {
        return new R(System.currentTimeMillis())
                .setSuccess(result.getSuccess())
                .setCode(result.getCode())
                .setMessage(result.getMessage());

    }


    // 自定義返回?cái)?shù)據(jù)
    public R data(Map<String, Object> map) {
        return this.setData(map);

    }

    // 通用設(shè)置data
    public R data(String key, Object value) {
        this.data.put(key, value);
        return this;
    }

    // 自定義狀態(tài)信息
    public R message(String message) {
        return this.setMessage(message);

    }

    // 自定義狀態(tài)碼
    public R code(Integer code) {
        return this.setCode(code);

    }

    // 自定義返回結(jié)果
    public R success(Boolean success) {
        return this.setSuccess(success);

    }

}

控制層調(diào)用返回

package cn.soboys.springbootrestfulapi.controller;


import cn.soboys.springbootrestfulapi.common.resp.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

/**
 * @author 公眾號(hào) 程序員三時(shí)
 * @version 1.0
 * @date 2023/4/28 23:58
 * @webSite https://github.com/coder-amiao
 */
@RestController
public class IndexController {

    @GetMapping("/index")
    public R index() {
        Map m = new HashMap();
        m.put("name", "Tom");
        m.put("age", 25);
        m.put("sex", "男");
        return R.success().data(m);
    }

    @GetMapping("/home")
    public R home() {

        Student s = new Student();
        s.setUserName("Tom");
        s.setBalance(2229891.0892);
        return R.success().data("user", s).message("查詢用戶詳情信息");
    }

    /**
     * 異常返回模擬
     *
     * @return
     */
    @GetMapping("/exception")
    public R exception() {
        Map m = null;
        m.put("name", "Jack");
        return R.success().data("user", m).message("查詢用戶詳情信息");
    }
}

統(tǒng)一結(jié)果類(lèi)的使用參考了mybatis-plus中R對(duì)象的設(shè)計(jì)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末缅茉,一起剝皮案震驚了整個(gè)濱河市嘴脾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔬墩,老刑警劉巖译打,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異拇颅,居然都是意外死亡奏司,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)樟插,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)韵洋,“玉大人,你說(shuō)我怎么就攤上這事黄锤√掠В” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵鸵熟,是天一觀的道長(zhǎng)副编。 經(jīng)常有香客問(wèn)我,道長(zhǎng)流强,這世上最難降的妖魔是什么痹届? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任呻待,我火速辦了婚禮,結(jié)果婚禮上队腐,老公的妹妹穿的比我還像新娘带污。我一直安慰自己,他們只是感情好香到,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著报破,像睡著了一般悠就。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上充易,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天梗脾,我揣著相機(jī)與錄音,去河邊找鬼盹靴。 笑死炸茧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的稿静。 我是一名探鬼主播梭冠,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼改备!你這毒婦竟也來(lái)了控漠?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤悬钳,失蹤者是張志新(化名)和其女友劉穎盐捷,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體默勾,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碉渡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了母剥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滞诺。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖环疼,靈堂內(nèi)的尸體忽然破棺而出铭段,到底是詐尸還是另有隱情,我是刑警寧澤秦爆,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布序愚,位于F島的核電站,受9級(jí)特大地震影響等限,放射性物質(zhì)發(fā)生泄漏爸吮。R本人自食惡果不足惜芬膝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望形娇。 院中可真熱鬧锰霜,春花似錦、人聲如沸桐早。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)哄酝。三九已至友存,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間陶衅,已是汗流浹背屡立。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搀军,地道東北人膨俐。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像罩句,于是被迫代替她去往敵國(guó)和親焚刺。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容