> 文档中心 > 大聪明教你学Java | 如何写出优雅的接口

大聪明教你学Java | 如何写出优雅的接口


前言

在日常开发中,我们总会写各种各样的接口,尤其是在移动互联网,分布式、微服务盛行的当下,绝大部分项目都采用的微服务框架和前后端分离方式来开发,后端工程师能写出优雅接口代码无疑是前端工程师的一个福音,一个优雅的接口可以拥有良好的可读性,而且在接口出现问题时也可以及时的排查错误原因。那么今天就给大家分享一下大聪明在开发接口时的一些心得😊。

接口开发

接口规范定义

协议规范

为了确保不同系统/模块间的数据交互,需要事先约定好通讯协议,如:TCP、HTTP、HTTPS协议。为了确保数据交互安全,建议使用HTTPS协议。

接口路径规范

作为接口路径,为了方便清晰的区分来自不同的系统,可以采用不同系统/模块名作为接口路径前缀,咱们举个例子👇:

  • 支付模块接口路径:/pay/xx
  • 订单模块接口路径:/order/xx

版本控制规范

为了便于后期接口的升级和维护,我们可以在接口路径中加入版本号,便于我们区分和管理接口,从而提升多版本接口的可维护性。不知各位小伙伴有没有留意过,很多框架(比如:Eureka)对外提供的 API 接口中都带有版本号(接口路径中添加类似"v1"、"v2"等版本号)。所以我们在开发接口的时候也可以在接口路径中增加版本号标识,例如 /xx/v1/xx、/xx/v2/xx。

接口命名规范

接口命名和 Java 命名规范一样,遵守一个优雅的接口命名规范,不仅可以增强接口的可读性,而且还会让开发人员之间减少很多不必要的口舌之争(要是接口写的太烂导致开发人员看不懂,备不住就直接爆粗口了😂)。
我们可以结合上文中写到的【接口路径规范】和【版本控制规范】,外加具体接口命名的方式来编写接口的请求路径。这里建议各位小伙伴在给接口命名的时候也要规范一些,这里我们可以使用“驼峰命名法”按照实现接口的业务类型、业务场景等命名(有必要时可采取多级目录命名,但目录不宜过长,两级目录较为适宜),比如:/user/v1/sys/login,代表的就是版本号为v1的用户服务模块的系统登录接口。在具体接口命名,我们通常会使用以下两种方式👇

  • 接口名称动词前(后)缀化: 接口名称以接口数据操作的动词为前(后)缀,我们常用的动词有:add、delete、update、query、get、send、save、detail、list等,那么在接口命名的时候就可以写成这样:新建用户 addUser 、查询订单详情 queryOrderDetail。
  • 接口名称动词+请求方式: 接口路径中包含具体接口名称的名词,接口数据操作动作以HTTP请求方式来区分。常用的HTTP请求方式有:GET(从服务器取出资源)、POST(在服务器新建一个资源)、PUT(在服务器更新资源)、DELETE(从服务器删除资源),那么在接口命名的时候我们就可以写成这样:GET /order/v1/orders:列出所有订单、POST /order/v1/orders:新建一个订单。

请求参数规范

  • 请求方式: 按照GET、POST、PUT等含义定义,避免出现不一致现象,防止造成误解。
  • 请求头: 请求头根据项目需求添加配置参数。如:请求数据格式,accept="application/json"等。如有需要,请求头可根据项目需求要求传入用户token、唯一验签码等加密数据。
  • 请求参数/请求体: 请求参数字段,尽可能与数据库表字段、对象属性名等保持一致,因为保持一致最省事,最舒服的一件事。

返回数据规范

统一规范返回数据的格式,对己对彼都有好处,此处以json格式为例。返回数据应包含:返回状态码、返回状态信息、具体数据。格式如下👇

{    "status":"xxx",    "msg":"xxx",    "data": { //json格式的具体数据    }}

上面我们提到了状态码,那么我们再具体的谈一谈关于状态码的规范。一个优雅的接口,给我们提供了简洁明了的状态码,根据状态码就可以让我们快速的定位问题根源所在。我们采用 Http 的状态码进行数据封装,其中状态码为 200 就表示请求成功,状态码为 4xx 就表示客户端错误,状态码为 5xx 就表示服务器内部发生错误。状态码设计参考如下:

public enum CodeEnum {    // 根据具体业务需求进行添加    SUCCESS(200,"请求成功"),    ERROR_PATH(404,"请求地址未找到"),    ERROR_SERVER(500,"服务器内部发生错误"); private int code;    private String message; CodeEnum(int code, String message) { this.code = code; this.message = message;    }    public int getCode() { return code;    }    public void setCode(int code) { this.code = code;    }    public String getMessage() { return message;    }    public void setMessage(String message) { this.message = message;    }}

我们刚刚也提到了“返回数据应包含:返回状态码、返回状态信息、具体数据”,那么在这里也给大家贴上一个本人常用的返回结果类及其常用方法👇

public class AjaxResult extends HashMap<String, Object>{    private static final long serialVersionUID = 1L;    /** 状态码 */    public static final String CODE_TAG = "code";    /** 返回内容 */    public static final String MSG_TAG = "msg";    /** 数据对象 */    public static final String DATA_TAG = "data";    /**     * 状态类型     */    public enum Type    { /** 成功 */ SUCCESS(0), /** 警告 */ WARN(301), /** 错误 */ ERROR(500); private final int value; Type(int value) {     this.value = value; } public int value() {     return this.value; }    }    /**     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。     */    public AjaxResult()    {    }    /**     * 初始化一个新创建的 AjaxResult 对象     *     * @param type 状态类型     * @param msg 返回内容     */    public AjaxResult(Type type, String msg)    { super.put(CODE_TAG, type.value); super.put(MSG_TAG, msg);    }    /**     * 初始化一个新创建的 AjaxResult 对象     *     * @param type 状态类型     * @param msg 返回内容     * @param data 数据对象     */    public AjaxResult(Type type, String msg, Object data)    { super.put(CODE_TAG, type.value); super.put(MSG_TAG, msg); if (StringUtils.isNotNull(data)) {     super.put(DATA_TAG, data); }    }    /**     * 方便链式调用     *     * @param key 键     * @param value 值     * @return 数据对象     */    @Override    public AjaxResult put(String key, Object value)    { super.put(key, value); return this;    }    /**     * 返回成功消息     *     * @return 成功消息     */    public static AjaxResult success()    { return AjaxResult.success("操作成功");    }    /**     * 返回成功数据     *     * @return 成功消息     */    public static AjaxResult success(Object data)    { return AjaxResult.success("操作成功", data);    }    /**     * 返回成功消息     *     * @param msg 返回内容     * @return 成功消息     */    public static AjaxResult success(String msg)    { return AjaxResult.success(msg, null);    }    /**     * 返回成功消息     *     * @param msg 返回内容     * @param data 数据对象     * @return 成功消息     */    public static AjaxResult success(String msg, Object data)    { return new AjaxResult(Type.SUCCESS, msg, data);    }    /**     * 返回警告消息     *     * @param msg 返回内容     * @return 警告消息     */    public static AjaxResult warn(String msg)    { return AjaxResult.warn(msg, null);    }    /**     * 返回警告消息     *     * @param msg 返回内容     * @param data 数据对象     * @return 警告消息     */    public static AjaxResult warn(String msg, Object data)    { return new AjaxResult(Type.WARN, msg, data);    }    /**     * 返回错误消息     *     * @return     */    public static AjaxResult error()    { return AjaxResult.error("操作失败");    }    /**     * 返回错误消息     *     * @param msg 返回内容     * @return 警告消息     */    public static AjaxResult error(String msg)    { return AjaxResult.error(msg, null);    }    /**     * 返回错误消息     *     * @param msg 返回内容     * @param data 数据对象     * @return 警告消息     */    public static AjaxResult error(String msg, Object data)    { return new AjaxResult(Type.ERROR, msg, data);    }}

小结

本人经验有限,有些地方可能讲的没有特别到位,如果您在阅读的时候想到了什么问题,欢迎在评论区留言,我们后续再一一探讨🙇‍

希望各位小伙伴动动自己可爱的小手,来一波点赞+关注 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●’◡’●)

如果文章中有错误,欢迎大家留言指正;若您有更好、更独到的理解,欢迎您在留言区留下您的宝贵想法。

你在被打击时,记起你的珍贵,抵抗恶意;
你在迷茫时,坚信你的珍贵,抛开蜚语;
爱你所爱 行你所行 听从你心 无问东西