代码优雅之道——Springboot统一返回结果

简介: 代码优雅之道 第一集

1、为什么要统一返回结果

从前后端分离模式开始后,后端只返回给前端json数据,在实际开发中,为了降低开发人员之间的沟通成本,一般返回结果会定义成一个统一格式,具体的格式根据实际开发业务不同有所区别。从前端的角度思考,调用后端接口后如果成功了则拿到想要的数据或者对应的信息提示,如果不成功也应该有相应的信息提示。从这个角度出发,我们将返回结果设计为:

  • code:响应状态码,根据状态码判断是否成功
  • msg:提示信息,根据调用的接口自定义
  • data:返回的数据

2、返回结果类

importlombok.Data;
importjava.io.Serializable;
/*** @author LoneWalker*/@DatapublicclassApiResult<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*/@GetterpublicenumResultCodeEnum{
/*** 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;
@RestController@RequestMapping("/contract/")
publicclassContractController {
@AutowiredprivateContractServicecontractService;
@PostMapping("add")
publicApiResultaddContract(@RequestBodyAddContractReqrequest) {
returncontractService.addContract(request);
    }
@PostMapping("list")
publicApiResult<List<Contract>>listContract(@RequestBodyQueryContractReqrequest) {
returncontractService.listContract(request);
    }
}


新增或查询参数类

importlombok.Data;
/*** @author LoneWalker* @date 2022/8/28* @description*/@DatapublicclassAddContractReq {
/*** 合同编号*/privateStringcode;
/*** 合同名称*/privateStringname;
/*** 客户名称*/privateStringcustomer;
}


importlombok.Data;
/*** @author LoneWalker* @date 2022/8/28* @description*/@DatapublicclassQueryContractReq {
/*** 合同名称*/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;
@Service("contractService")
publicclassContractServiceImplimplementsContractService {
@OverridepublicApiResultaddContract(AddContractReqrequest) {
//存入数据库returnApiResult.success();
    }
@OverridepublicApiResult<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、问题

以上都是接口调用成功的情况,当业务出现异常,按照我们的初衷,需要将业务异常结果组装成统一的信息返回给前端进行提示。

下一篇 代码优雅之道——断言 + Springboot统一异常处理

相关文章
|
23天前
|
Java 数据安全/隐私保护 Spring
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
揭秘Spring Boot自定义注解的魔法:三个实用场景让你的代码更加优雅高效
|
20天前
|
前端开发 IDE Java
"揭秘前端转Java的秘径:SpringBoot Web极速入门,掌握分层解耦艺术,让你的后端代码飞起来,你敢来挑战吗?"
【8月更文挑战第19天】面向前端开发者介绍Spring Boot后端开发,通过简化Spring应用搭建,快速实现Web应用。本文以创建“Hello World”应用为例,展示项目基本结构与运行方式。进而深入探讨三层架构(Controller、Service、DAO)下的分层解耦概念,通过员工信息管理示例,演示各层如何协作及依赖注入的使用,以此提升代码灵活性与可维护性。
30 2
|
28天前
|
安全 Java Shell
"SpringBoot防窥秘籍大公开!ProGuard混淆+xjar加密,让你的代码穿上隐形斗篷,黑客也无奈!"
【8月更文挑战第11天】开发SpringBoot应用时,保护代码免遭反编译至关重要。本文介绍如何运用ProGuard和xjar强化安全性。ProGuard能混淆代码,去除未使用的部分,压缩字节码,使反编译困难。需配置ProGuard规则文件并处理jar包。xjar则进一步加密jar包内容,即使被解压也无法直接读取。结合使用这两种工具可显著提高代码安全性,有效保护商业机密及知识产权。
126 3
|
1月前
|
Java API 数据格式
Spring Boot API参数读取秘籍大公开!6大神器助你秒变参数处理大师,让你的代码飞起来!
【8月更文挑战第4天】Spring Boot凭借其便捷的开发和配置特性,成为构建微服务的热门选择。高效处理HTTP请求参数至关重要。本文介绍六种核心方法:查询参数利用`@RequestParam`;路径变量采用`@PathVariable`;请求体通过`@RequestBody`自动绑定;表单数据借助`@ModelAttribute`或`@RequestParam`;请求头使用`@RequestHeader`;Cookie则依靠`@CookieValue`。每种方法针对不同场景,灵活运用可提升应用性能与用户体验。
41 9
|
10天前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
23 0
|
10天前
|
Java 开发者 Spring
Spring Boot大法好:解耦、隔离、异步,让代码‘活’起来,性能飙升的秘密武器!
【8月更文挑战第29天】解耦、隔离与异步是Spring Boot中的关键设计原则,能大幅提升软件的可维护性、扩展性和性能。本文通过示例代码详细探讨了这些原则的应用:依赖注入和面向接口编程实现解耦;模块化设计与配置文件实现隔离;`@Async`注解和`CompletableFuture`实现异步处理。综合运用这些原则,可以显著提升软件质量和性能,使系统更加健壮、灵活和高效。
15 0
|
2月前
|
存储 Java Serverless
Java Spring Boot应用如何实现推送代码到指定仓库并自动部署
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
存储 Java
软件开发常用之SpringBoot文件上传接口编写(中),一本书,代码大全(里面有很多代码重构的方法),屎山代码的原因是不断追加逻辑,在错误代码上堆积新的功能,在写完逻辑之后去思考一下,逻辑合理不
软件开发常用之SpringBoot文件上传接口编写(中),一本书,代码大全(里面有很多代码重构的方法),屎山代码的原因是不断追加逻辑,在错误代码上堆积新的功能,在写完逻辑之后去思考一下,逻辑合理不
|
2月前
|
安全 测试技术 数据库
基于SpringBoot+Vue中小企业人事管理系统代码(源码+部署说明+演示视频+源码介绍)(2)
基于SpringBoot+Vue中小企业人事管理系统代码(源码+部署说明+演示视频+源码介绍)
31 0
|
2月前
|
Java 关系型数据库 MySQL
基于SpringBoot+Vue中小企业人事管理系统代码(源码+部署说明+演示视频+源码介绍)(1)
基于SpringBoot+Vue中小企业人事管理系统代码(源码+部署说明+演示视频+源码介绍)
23 0
下一篇
DDNS