假如現(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)容
- 是否響應(yīng)成功
- 響應(yīng)狀態(tài)碼
- 狀態(tài)碼描述
- 響應(yīng)數(shù)據(jù)
- 接口調(diào)用時(shí)間
- 其他標(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ì)。