java api接口怎么写_Java 如何设计 API 接口,实现统一格式返回?

来源:老顾聊技术

  • 前言

  • 接口交互

  • 返回格式

  • 控制层Controller

  • 美观美化

  • 优雅优化

  • 实现方案


前言

在移动互联网,分布式、微服务盛行的今天,现在项目绝大部分都采用的微服务框架,前后端分离方式,(题外话:前后端的工作职责越来越明确,现在的前端都称之为大前端,技术栈以及生态圈都已经非常成熟;以前后端人员瞧不起前端人员,那现在后端人员要重新认识一下前端,前端已经很成体系了)。

一般系统的大致整体架构图如下:

971e172b6e7eb7c2c77b039d76fb0052.png

需要说明的是,有些小伙伴会回复说,这个架构太简单了吧,太low了,什么网关啊,缓存啊,消息中间件啊,都没有。因为老顾这篇主要介绍的是API接口,所以我们聚焦点,其他的模块小伙伴们自行去补充。

接口交互

前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端。

针对URL路径的restful风格,以及传入参数的公共请求头的要求(如:app_version,api_version,device等),老顾这里就不介绍了,小伙伴们可以自行去了解,也比较简单。

后端服务器如何实现把数据返回给前端?

返回格式

后端返回给前端我们一般用JSON体方式,定义如下:

{
  #返回状态码
  code:integer,
  #返回信息描述
  message:string,
  #返回值
  data:object
}

CODE状态码

code返回状态码,一般小伙伴们是在开发的时候需要什么,就添加什么。

如接口要返回用户权限异常,我们加一个状态码为101吧,下一次又要加一个数据参数异常,就加一个102的状态码。这样虽然能够照常满足业务,但状态码太凌乱了

我们应该可以参考HTTP请求返回的状态码

:下面是常见的HTTP状态码:
200 - 请求成功
301 - 资源(网页等)被永久转移到其它URL
404 - 请求的资源(网页等)不存在
500 - 内部服务器错误
e11fbc11e7052f08a766e678d08c7a5f.png

我们可以参考这样的设计,这样的好处就把错误类型归类到某个区间内,如果区间不够,可以设计成4位数。

#1000~1999 区间表示参数错误
#2000~2999 区间表示用户错误
#3000~3999 区间表示接口异常

这样前端开发人员在得到返回值后,根据状态码就可以知道,大概什么错误,再根据message相关的信息描述,可以快速定位。

Message

这个字段相对理解比较简单,就是发生错误时,如何友好的进行提示。一般的设计是和code状态码一起设计,如

b929200e5d670abf63d0b63fbf013417.png

再在枚举中定义,状态码

32a7fa34e203544eb929c21a7ac45fb0.png

状态码和信息就会一一对应,比较好维护。

Data

返回数据体,JSON格式,根据不同的业务又不同的JSON体。

我们要设计一个返回体类Result

5d64e6947aa70505581e92fc686f57b0.png

控制层Controller

我们会在controller层处理业务请求,并返回给前端,以order订单为例

767c16fd747b38e9faba24c958de469e.png

我们看到在获得order对象之后,我们是用的Result构造方法进行包装赋值,然后进行返回。小伙伴们有没有发现,构造方法这样的包装是不是很麻烦,我们可以优化一下。

美观美化

我们可以在Result类中,加入静态方法,一看就懂

be17badc95e34faf5edee9d93712a19e.png

那我们来改造一下Controller

abcd866875fab2b0f798ab89bdbcc20c.png

代码是不是比较简洁了,也美观了。

优雅优化

上面我们看到在Result类中增加了静态方法,使得业务处理代码简洁了。但小伙伴们有没有发现这样有几个问题:

1、每个方法的返回都是Result封装对象,没有业务含义

2、在业务代码中,成功的时候我们调用Result.success,异常错误调用Result.failure。是不是很多余

3、上面的代码,判断id是否为null,其实我们可以使用hibernate validate做校验,没有必要在方法体中做判断。

我们最好的方式直接返回真实业务对象,最好不要改变之前的业务方式,如下图

55784a6c5893d9c5b094895cb37839a2.png

这个和我们平时的代码是一样的,非常直观,直接返回order对象,这样是不是很完美。那实现方案是什么呢?

实现方案

小伙伴们怎么去实现是不是有点思路,在这个过程中,我们需要做几个事情

1、定义一个注解@ResponseResult,表示这个接口返回的值需要包装一下

2、拦截请求,判断此请求是否需要被@ResponseResult注解

3、核心步骤就是实现接口ResponseBodyAdvice和@ControllerAdvice,判断是否需要包装返回值,如果需要,就把Controller接口的返回值进行重写。

注解类

用来标记方法的返回值,是否需要包装

af12bd5ab23c54b5005c3c1ff7562682.png

拦截器

拦截请求,是否此请求返回的值需要包装,其实就是运行的时候,解析@ResponseResult注解

82557869c41782b76573d7261acd96a0.png

此代码核心思想,就是获取此请求,是否需要返回值包装,设置一个属性标记。

重写返回体

1f29394017036edffa7fd5e582badf07.png

上面代码就是判断是否需要返回值包装,如果需要就直接包装。这里我们只处理了正常成功的包装,如果方法体报异常怎么办?处理异常也比较简单,只要判断body是否为异常类。

b20f41942097d276f23a4c8d44423a86.png

怎么做全局的异常处理,篇幅原因,老顾这里就不做介绍了,只要思路理清楚了,自行改造就行。

重写Controller

f8a76b7102c05d884c3bbaca21651396.png

在控制器类上或者方法体上加上@ResponseResult注解,这样就ok了,简单吧。到此返回的设计思路完成,是不是又简洁,又优雅。

这个方案还有没有别的优化空间,当然是有的。如:每次请求都要反射一下,获取请求的方法是否需要包装,其实可以做个缓存,不需要每次都需要解析。当然整体思路了解,小伙伴们就可以在此基础上面自行扩展,

程序汪往期精彩文章

程序汪最近整理的BAT大小厂面试题(面试题目录推荐)

目录:我把精华文章都整理出来了

Java硕士京东工作1年,跳槽后他期望薪资26K,大家感觉他可以吗

经验分享:一本学历大三Java粉丝顺利拿下实习offer,他放弃了考研

经验分享:Java1年经验16K外派支付宝,你们说香吗

面经分享:毕业西电Java工作3年拿到了30Koffer

经验分享:36000元培训1年半Java,一个培训踩坑经历

090564a78db41ca6daa0e538f94a1398.png

给个[在看],是对程序汪最大的支持

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 输出学生成绩和成绩等级

题目 从键盘读入学生成绩,找出最高分,并输出学生成绩等级。成绩>最高分-10 等级为’A’成绩>最高分-20 等级为’B’成绩>最高分-30 等级为’C’其余 等级为’D’提示:先读入学生人数,根据人数创建int数组&#…

STL源码剖析 multiset 和 multimap

multiset和set完全相同,唯一的差别在于允许键值的重复,因此底层操作使用的是红黑树的insert_equal() 而不是insert_unique()multimap和map完全相同,唯一的差别在于允许键值的重复,因此底层操作使用的是红黑树的insert_equal() 而不…

java 二维数组

声明和初始化 静态初始化 // 静态初始化: // 一维数组int[] arr1_1 {1, 2, 4};System.out.println(Arrays.toString(arr1_1)); // 二维数组int[][] arr1_2 {{1, 2}, {4, 5}, {9, 10}};for (int[] i :arr1_2) {System.out.print(Arrays.toS…

STL源码剖析 hashtable

二叉搜索树具有对数平均时间的表现,但是这个需要满足的假设前提是输入的数据需要具备随机性hashtable 散列表这种结构在插入、删除、搜寻等操作层面上也具有常数平均时间的表现。而且不需要依赖元素的随机性,这种表现是以统计为基础的 hashtable的概述 …

append在python里是什么意思_“一棵绿萝七个鬼”是什么意思?卧室里到底能不能养绿萝!...

很多人都喜欢在家里养盆绿萝,一是能净化室内空气,让家里绿意浓浓,更有生机一些;二是绿萝好养,水培土培都行,养着也省心。在养花界有一句俗语:“一棵绿萝七个鬼”,这句话是什么意思呢…

java 二分查找

注意 二分查找要求原数组为有序序列,从小到大 递归解法 public class problem9 {public static void main(String[] args) {int[] arr {1,2,3,4,6,7};int left 0;int right arr.length - 1;int value 2;System.out.println(Arrays.toString(arr));int index …

C++for_each| bind1st | ptr_fun | std::function的用法

c for_each 用法_小键233-CSDN博客 传入参数 要传入参数给global function ,需要使用 ptr_fun() 这个 function adapter 将global function 转成function object , 然后再用bind2nd() 将参数bind成一个function object。(这句话好拗口) void fun(int i…

java三个柱子汉诺塔问题

题目 移动盘子,每一次只能移动一个,小盘子在大盘子上。 打印1 from A to B过程 注意 1)盘子编号的变化和辅助柱子的变化 2)当盘子编号为1时,结束递归,此时移动结束 代码 package p2;/*** Illustratio…

python遍历txt每一行_python – 计算(和写入)文本文件中每一行的...

第一次在堆栈中发布 – 总是发现以前的问题足以解决我的问题!我遇到的主要问题是逻辑……即使是伪代码答案也会很棒. 我正在使用python从文本文件的每一行读取数据,格式如下: This is a tweet captured from the twitter api #hashtag http://url.com/si…

java杨辉三角形

题目 代码1 public class YangHuiTriangle {public static void main(String[] args) {print(10);}public static void print(int num) {int[][] arr new int[num][];for (int i 0; i < num; i) { // 第一行有 1 个元素, 第 n 行有 n 个元素arr[i] new int[i…

python子类继承父类属性实例_python – 从子类内的父类访问属性

在类定义期间,没有任何继承的属性可用&#xff1a; >>> class Super(object): class_attribute None def instance_method(self): pass >>> class Sub(Super): foo class_attribute Traceback (most recent call last): File "", line 1, in cl…

STL源码剖析 算法开篇

STL源码剖析 算法章节 算法总览_CHYabc123456hh的博客-CSDN博客 质变算法 质变算法 - 会改变操作对象的数值&#xff0c;比如互换、替换、填写、删除、排列组合、分隔、随机重排、排序等 #include <iostream> #include <vector>int main(){int ia[] {22,30,20,34…

java 随机数一维数组

题目1 创建一个长度为6的int型数组&#xff0c;要求数组元素的值都在1-30之间&#xff0c;且是随机赋值。同时&#xff0c;要求元素的值各不相同 代码1 public class ArrayTest2 {public static void main(String[] args) {generateArray(6);}public static void generateAr…

STL源码剖析 数值算法 accumulate | adjacent_difference | inner_product | partial_sum | power | itoa

//版本1 template <class InputIterator,class T> T accumulate(InputIterator first,InputIterator last,T init){for(;first ! last; first){init *first; //将每个元素数值累加到init身上}return init; }//版本2 template <class InputIterator,class T,class Bin…

python官网网址是什么意思_大家都是怎么部署python网站的?

flaskgunicornnginx 作者&#xff1a;Python小白 链接&#xff1a;centos下通过gunicorn和nginx部署Flask项目 - Python小白的文章 - 知乎专栏 来源&#xff1a;知乎 著作权归作者所有。商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处。 之前用Flask写了个解析Tu…

java回形数矩阵

题目 从键盘输入一个整数&#xff08;1~20&#xff09; 则以该数字为矩阵的大小&#xff0c;把1,2,3…n*n 的数字按照顺时针螺旋的形式填入其中。例如&#xff1a; 输入数字2&#xff0c;则程序输出&#xff1a; 1 2 4 3 输入数字3&#xff0c;则程序输出&#xff1a; 1 2 3 8…

STL源码剖析 基本算法 equal | fill | iter_awap | lexicographical_compare | max | min | swap |mismatch

Equal 两个序列在[first,last)区间内相等&#xff0c;equal()返回true。以第一个序列作为基准&#xff0c;如果第二序列元素多不予考虑&#xff0c;如果要保证两个序列完全相等需要比较元素的个数 if(vec1.size() vec2.size() && equal(vec1.begin(),vec1.end(),vec2…

svm分类器训练详细步骤_「五分钟机器学习」向量支持机SVM——学霸中的战斗机...

大家好&#xff0c;我是爱讲故事的某某某。 欢迎来到今天的【五分钟机器学习】专栏内容 --《向量支持机SVM》 今天的内容将详细介绍SVM这个算法的训练过程以及他的主要优缺点&#xff0c;还没有看过的小伙伴欢迎去补番&#xff1a;【五分钟机器学习】向量支持机SVM——学霸中的…

java一维数组的复制

题目 使用简单数组(1)创建一个名为ArrayTest的类&#xff0c;在main()方法中声明array1和array2两个变量&#xff0c;他们是int[]类型的数组。(2)使用大括号{}&#xff0c;把array1初始化为8个素数&#xff1a;2,3,5,7,11,13,17,19。(3)显示array1的内容。(4)赋值array2变量等…

STL源码剖析 数值算法 copy 算法

copy复制操作&#xff0c;其操作通过使用assignment operator 。针对使用trivial assignment operator的元素型别可以直接使用内存直接复制行为(使用C函数 memove或者memcpy)节约时间。还可以通过函数重载(function overloading)、型别特性(type traits)、偏特化(partial speci…