1、为什么要统一返回结果
从前后端分离模式开始后,后端只返回给前端json数据,在实际开发中,为了降低开发人员之间的沟通成本,一般返回结果会定义成一个统一格式,具体的格式根据实际开发业务不同有所区别。从前端的角度思考,调用后端接口后如果成功了则拿到想要的数据或者对应的信息提示,如果不成功也应该有相应的信息提示。从这个角度出发,我们将返回结果设计为:
- code:响应状态码,根据状态码判断是否成功
- msg:提示信息,根据调用的接口自定义
- data:返回的数据
2、返回结果类
importlombok.Data; importjava.io.Serializable; /*** @author LoneWalker*/publicclassApiResult<T>implementsSerializable { privatestaticfinallongserialVersionUID=411731814484355577L; /*** 状态码*/privateintcode; /*** 提示信息*/privateStringmsg; /*** 相关数据*/privateTdata; publicStringtoString() { return"ApiResult(code="+this.getCode() +", msg="+this.getMsg() +", data="+this.getData() +")"; } /*** 构造器 自定义响应码与提示信息* @param code 响应码* @param message 提示信息*/privateApiResult(intcode,Stringmessage){ this.code=code; this.msg=message; } /*** 构造器 自定义响应码、提示信息、数据* @param code 响应码* @param message 提示信息* @param data 返回数据*/privateApiResult(intcode,Stringmessage,Tdata){ this(code,message); this.data=data; } /*** 成功构造器 无返回数据*/publicstatic<T>ApiResult<T>success(){ returnnewApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage()); } /*** 成功构造器 自定义提示信息 无返回数据* @param message 提示信息*/publicstatic<T>ApiResult<T>success(Stringmessage){ returnnewApiResult<>(ResultCodeEnum.SUCCESS.getCode(), message); } /*** 成功构造器 有返回数据*/publicstatic<T>ApiResult<T>success(Tdata){ returnnewApiResult<>(ResultCodeEnum.SUCCESS.getCode(), ResultCodeEnum.SUCCESS.getMessage(),data); } /*** 失败构造器 无返回数据*/publicstatic<T>ApiResult<T>fail(){ returnnewApiResult<>(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getMessage()); } /*** 失败构造器 自定义提示信息 无返回数据* @param message 提示信息*/publicstatic<T>ApiResult<T>fail(Stringmessage){ returnnewApiResult<>(ResultCodeEnum.FAIL.getCode(), message); } /*** 失败构造器 有返回数据*/publicstatic<T>ApiResult<T>fail(Tdata){ returnnewApiResult<>(ResultCodeEnum.FAIL.getCode(), ResultCodeEnum.FAIL.getMessage(),data); } }
3、状态码及提示信息枚举
除去基础的操作成功或失败,可以将状态码归类,例如请求参数问题归纳到1001-1999之间。
importlombok.Getter; /*** @author LoneWalker*/publicenumResultCodeEnum{ /*** success*/SUCCESS(0,"操作成功"), /*** fail*/FAIL(-1,"操作失败"), /*** 参数错误:1001-1999*/PARAM_IS_INVALID(1001,"参数无效"), PARAM_TYPE_ERROR(1002,"参数类型错误"), ; /*** 状态码*/privatefinalintcode; /*** 提示信息*/privatefinalStringmessage; ResultCodeEnum(Integercode, Stringmessage){ this.code=code; this.message=message; } }
4、使用与测试
controller
importcom.example.assertdemo.common.ApiResult; importcom.example.assertdemo.entity.Contract; importcom.example.assertdemo.req.AddContractReq; importcom.example.assertdemo.req.QueryContractReq; importcom.example.assertdemo.service.ContractService; importorg.springframework.beans.factory.annotation.Autowired; importorg.springframework.web.bind.annotation.PostMapping; importorg.springframework.web.bind.annotation.RequestBody; importorg.springframework.web.bind.annotation.RequestMapping; importorg.springframework.web.bind.annotation.RestController; importjava.util.List; "/contract/") (publicclassContractController { privateContractServicecontractService; "add") (publicApiResultaddContract(AddContractReqrequest) { returncontractService.addContract(request); } "list") (publicApiResult<List<Contract>>listContract(QueryContractReqrequest) { returncontractService.listContract(request); } }
新增或查询参数类
importlombok.Data; /*** @author LoneWalker* @date 2022/8/28* @description*/publicclassAddContractReq { /*** 合同编号*/privateStringcode; /*** 合同名称*/privateStringname; /*** 客户名称*/privateStringcustomer; }
importlombok.Data; /*** @author LoneWalker* @date 2022/8/28* @description*/publicclassQueryContractReq { /*** 合同名称*/privateStringcontractName; /*** 客户名称*/privateStringcustomer; }
Service
importcom.example.assertdemo.common.ApiResult; importcom.example.assertdemo.entity.Contract; importcom.example.assertdemo.req.AddContractReq; importcom.example.assertdemo.req.QueryContractReq; importjava.util.List; publicinterfaceContractService { /*** 添加合同信息* @param request* @return*/ApiResultaddContract(AddContractReqrequest); /*** 合同列表数据* @param request 查询参数* @return*/ApiResult<List<Contract>>listContract(QueryContractReqrequest); }
impl
importcom.example.assertdemo.common.ApiResult; importcom.example.assertdemo.entity.Contract; importcom.example.assertdemo.req.AddContractReq; importcom.example.assertdemo.req.QueryContractReq; importcom.example.assertdemo.service.ContractService; importorg.springframework.stereotype.Service; importjava.util.ArrayList; importjava.util.List; "contractService") (publicclassContractServiceImplimplementsContractService { publicApiResultaddContract(AddContractReqrequest) { //存入数据库returnApiResult.success(); } publicApiResult<List<Contract>>listContract(QueryContractReqrequest) { //模拟数据List<Contract>list=newArrayList<>(); ContractcontractOne=newContract(1L, "HT082801", "临床试验一期合同", "省立医院"); ContractcontractTwo=newContract(2L, "HT082802", "临床试验二期合同", "省立医院"); ContractcontractThree=newContract(3L, "HT082803", "临床试验三期合同", "省立医院"); list.add(contractOne); list.add(contractTwo); list.add(contractThree); returnApiResult.success(list); } }
启动项目,新增一条数据
查询数据
5、问题
以上都是接口调用成功的情况,当业务出现异常,按照我们的初衷,需要将业务异常结果组装成统一的信息返回给前端进行提示。