来源:http://t.cn/RW5O9mM

记得第一次听到前后端分离,是在NodeJs崛起之后,通过淘宝中途岛项目的博客开始有所了解的。那一阵,前后端分离的架构变的炙手可热,这里我也转过几篇关于前后端分离不错的内容:

  • 互联网分层架构,为啥要前后端分离?

  • 前后端API交互如何保证数据安全性?

然而有很多团队,尤其是没有对前后端都特别有经验的架构师设计下,实践并不那么顺利,比如,你可能会碰到这些问题:为什么前后端分离了,你比从前更痛苦?

本文将继续分享一则非常不错的,关于前后端分离的实践分享内容!

前言

随着互联网高速发展,公司对项目开发周期不断缩短,我们面对各种需求,使用原有对接方式,各端已经很难快速应对各种需求,更难以提高效率。于是,我们不得不重新制定对接规范、开发逻辑以便快速上线项目。

我们的目标

  1. 尽可能的缩小沟通的成本,开最少的会,确定大部分的事。

  2. 花最少的时间写文档,保证90%的开发人员看懂所有内容。

  3. 哪怕不看文档,也能知道各种接口逻辑。

  4. 不重复写代码

  5. 尽可能的写高可读性的代码

我们做了哪些事

  1. 完成了前后端分离

  2. Android、ios、web共用一套接口

  3. 统一接口规范(post、put、get、patch、delete)

  4. 统一了调试工具

  5. 统一了接口文档

之前的我们

接口是这样子的:

接口地址 含义 请求方式
…/A项目/模块1/getProducts 获得产品 GET
…/A项目/模块1/addProduct 添加产品 POST
…/A项目/模块1/getProductDetail 获得产品详情 GET
…/A项目/模块1/editProduct 修改产品 POST

客户端请求是这样的:

  • …/A项目/模块1/getProducts?id=1&a=2&b=3&c=4&d=5…………

  • A页面=====》B页面(携带n个变量)====》C页面(携带m个变量,包含i个A页面的变量) -------经常n>4

  • 大部分请求是POST,至于put、patch、delete是什么鬼,关我屁事。

  • 关于接口入参使用json,那完全是看开发心情。

出参是这样的:

{"message":"success","code":0,"data":具体内容} 其中data里包含数组可能是 [{"a":"1","b":"1"},{"a":"1","b":"1"},{"a":"1","b":"1"},{"a":"1","b":"1"}] 即使下一个页面用到也不会使用id,而是把所有字段都传进去。 A接口中,返回产品用product;B接口中使用good,多个接口很可能不统一。

客户端对接是这样子的:

  • 安卓、ios一套;部分接口各自用一套;html5端一套。

  • 客户端和后台是不停交流的

接口文档是这样的

  1. Swagger

  2. 阿里的rap

  3. Word文档

  4. 其它

当然了,我觉得swagger和rap神器都是非常强大的,能够实现各种功能逻辑,但是考虑到开发人员掌握程度不通,复杂度较高,难以提高效率,我决定初期并不使用这两样神器。

后端是这样的

…/A项目/模块1/getProducts ----接口 …/A项目/模块1/Products.html ----页面 …/A项目/模块1/Products.js ----静态资源

接口和静态资源缠在一块,毕竟很多页面可能是一位开发人员同时开发前端、后端,这里的弊端是,只需要自己清楚逻辑,很多做法临时应付,方案并不优雅,别人也很难看懂。一旦这位同事离职,很多说不清的逻辑就留给后人采坑了。

等等…………

重构

下面步入正题,面对以上众多问题聊聊我是如何重新制定流程的

数据库约定

约定数据库里所有表必须包含名为id主键字段。 可能有人会说,正常来说不是每张表里都应该有id主键吗?但是,我们项目中由于之前开发不严谨,部分表没有id主键,或者不为id的主键。这里我们采用分布式的全球唯一码来作为id。

api出参约定

约定所有出参里含list,且其他请求会用到这组list,则list里所有对象必须含id唯一标识。

入参约定

约定token身份认证统一传入参数模式,后端采用aop切面编程识别用户身份。其他参数一律为json。

RESTful接口约定

首先我们选择一个名词复数,比如产品

post方法

新增一条XXX 比如 ……/products 则代表新增一条产品 入参json如下:

  1. {

  2.    "name":"我是一款新产品",

  3.    "price":100,

  4.    "kind":"我的分类",

  5.    "pic":[一组图片],

  6.    等等还有很多

  7. }

java 代码control层

  1. @ResponseBody

  2. @RequestMapping(value = "/A项目/B模块/products", method = {RequestMethod.POST})

  3. public ResultObject getProducts() {

  4.    //具体逻辑。

  5. }

put方法

新增某条XXX记录 比如 ……/products/1111111111 入参json如下:

  1. {

  2.    "name":"我是一款新产品",

  3.    "price":100,

  4.    "kind":"我的分类",

  5.    "pic":[一组图片],

  6.    等等还有很多

  7. }

表示增加一条1111111111id的记录 java代码control层

  1. @ResponseBody

  2. @RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.PUT})

  3. public ResultObject putProducts(@PathVariable(value = "id") String id) {

  4.    //具体逻辑。

  5. }

get方法

获得所有XXX ……/products 则代表获取所有产品 因为有分页,所以我们后面加了?page=1&pageSize=50

我们约定了所有名词复数,都会返回list,且list每个对象都有字段为id的唯一id。 比如

  1. {

  2.    "data":{"list":[{"id":"唯一id","其他很多字段":""},{"id":"唯一id","其他很多字段":""}],"page":1,其他字段},

  3.    "code":0,

  4.    "message":"成功"

  5. }

……/products/{id} 获取某个具体产品(一定比列表更详细)

比如某个具体产品里还包含一个list,如该产品推荐列表,则: ……/products/{id}/recommendations

假设它包含的不是一个list,而是对象,比如产品佣金信息,则: ……/products/{id}/Commission

这里我们以是否名词复数来判断是对象还是list.

java代码control层

  1. @ResponseBody

  2. @RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.GET})

  3. public ResultObject putProducts(@PathVariable(value = "id") String id) {

  4.    //具体逻辑。

  5. }

patch 方法

更新局部XXX产品YYY信息 入参是post方法时入参的子集,所有支持更新的参数会说明,并不是支持所有变量 ……/products/{id}

  1. {

  2.    "name":"我是一款新产品",

  3.    "price":100,

  4.    部分变量

  5. }

java代码control层

  1. @ResponseBody

  2. @RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.PATCH})

  3. public ResultObject putProducts(@PathVariable(value = "id") String id) {

  4.    //具体逻辑。

  5. }

delete方法

删除XXX记录 ……/products/11111

删除11111产品。 java代码control层

  1. @ResponseBody

  2. @RequestMapping(value = "/A项目/B模块/products/{id}", method = {RequestMethod.DELETE})

  3. public ResultObject putProducts(@PathVariable(value = "id") String id) {

  4.    //具体逻辑。

  5. }

其他说明

我们尽可能少的使用动词,但有一些行为需要使用动词,比如登录等。 关于版本号,我们打算在模块后增加 /v1/等标识。

权限约定

服务端要对用户角色进行判断,是否有权限执行某个逻辑。

前后端分离约定

后端以开发接口为主,不再参与页面开发,或者混合式jsp页面开发,统一以接口形式返回,前端通过js渲染数据以及处理逻辑。

共用接口

web、Android、ios使用统一接口,不在因为哪方特殊要求额外开放接口。

使用统一dao层生成工具

基于mybatis-generator改造成适合我们项目的dao层以及部分service层,内部共同维护共同使用。

使用postman最为接口文档、调试工具

虽然有上文中介绍的rap和swagger都是特别牛的接口神器,但是我们还是选择了postman,开发人员将接口名称、说明、入参、出参,以及各种出参示例都存储,这样开发直接可以看得清接口含义。

我们建议使用浏览器插件,这里以360极速浏览器为例。

打开360浏览器扩展中心,然后勾选开发者模式,再点击加载已解压的扩展程序,选中压缩包解压后的目录,最后点击运行即可。

其中出参注释、及接口说明,写在tests里:

  1. /*

  2. 这里是接口说明,和每个出参、入参的意思。

  3. */复制代码

接口按模块划分为文件夹:

入参:

出参示例:

正常请求:

开发人员即可直接看到接口示例进行开发,而开发人员开发的时候,自己调用一次即可保存为postman文件,为了加快上线,我们允许将java中实体类变量定义的代码(含注释)直接复制粘贴出来。

js等静态资源缓存问题

从短期角度上讲,我的要求是减少js文件的变更,如果有变更,务必更改版本号。那么如何减少修改,我们的做法是将一部分js写在html内,反正前后端分离,大不了刷新一下cdn的节点缓存,毕竟大部分浏览器也不会主动缓存html文件(大部分浏览器会缓存js等文件)。

统一js请求框架

这里我们使用angular js的请求框架,因为我们内部对angularjs使用较多,比较熟悉,封装后的请求,可以自动弹窗错误请求,可复写错误回调。

目前效果

目前,我们客户端看到接口,大概能说出其意思,也能猜出一连串接口的含义,比如 ……/classes 可以看出它是获取班级列表接口,猜到

……/classes/id get获取id为id的班级详情 ……/classes/id patch 修改班级信息 ……/classes/id delete 删除班级信息

至于入参,patch是post的子集、put=patch、delete无入参。

而入参含义,直接打开postman可以直接查看每个字段的含义,并且,可以实时调取开发环境数据(非开发人员电脑),这里我们使用了多环境,详情可了解我之前写的一篇我是如何重构整个研发项目,促进自动化运维DevOps的落地?

前端使用统一封装后的js请求框架也加快了开发进度,不用造轮子。

开发人员,一般代码开发写好,使用postman自我测试,测试完成后,接口文档也就写好了。

测试人员想了解接口文档的也可以直接使用postman进行导入查看。

至此,我们交流成本下降了一大半,剩下开会的内容就是按ui分解需求或者按ui施工了。

总结

经过一番的折腾,开发进度总算快了点,也一定程度上达到了快速上线项目的效果。关于restful风格api,每个人都有自己的见解,只要内部约定清楚,能尽可能少的减少沟通,我觉得就是好的理解。至于接口工具,可能很多人会说为什么不用之前的,我觉得以后还是会用的,最好能做到插件自动化生成api,但是对java开发注释要求比较严格,随意慢慢来吧,毕竟后面我们还有很多路要走。

资本寒冬,该如何面对:BAT招聘岗位100%都考的知识,你精通了吗?

课程推荐:搞了那么久的后端,不会点缺点总觉得缺了点什么?

号外:最近整理了一下以前编写的一系列Spring Boot内容,整了个《Spring Boot基础教程》的PDF,关注我,回复:001,快来领取吧~!更多内容持续整理中,帮助大家更好的学习Spring相关的系列内容!

·END·

 近期热文:

  • Spring Cloud Stream 学习小清单

  • 中台是个什么鬼?

  • 从业务到平台的思维转变

  • 是什么使你留在你的公司

  • 重磅!Github 开放无数量限制的免费私有仓库!

  • 百度面试题:求数组最大值

  • 我说分布式事务之消息最终一致性事务(一):原理及实现

  • 我说分布式事务之消息最终一致性事务(二):RocketMQ的实现

  • 疑案追踪:Spring Boot内存泄露排查记

  • 了解Java中的内存泄漏

看完,赶紧点个“好看”鸭

点鸭点鸭

↓↓↓↓

在前后端分离的路上承受了多少痛?看看这篇是否能帮到你?相关推荐

  1. 从壹开始前后端分离 [ vue + .netcore 补程 ] 三十一║ Nuxt终篇:基于Vuex的权限验证探究...

    缘起 哈喽大家好,今天周四啦,楼主明天要正式放假了,这里先祝大家节日快乐咯,希望在家里能继续研究点儿东西吧,今天呢是 nuxt 的最后一篇,主要是对权限登陆进行研究,这一块咱们之前在说第一个项目的时候 ...

  2. 七个开源的 SpringBoot 前后端分离项目,Star过千,快去收藏夹吃灰吧!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 微信公众号:江南一点雨 前后端分离已经在慢慢走进各公司的技 ...

  3. 前后端分离项目_七个开源的 Spring Boot 前后端分离项目,一定要收藏

    来自公众号:江南一点雨 前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开 ...

  4. 我们为什么要尝试前后端分离

    这不是一篇纯技术文章,而是一篇分享我个人在前后端分离路上收获的点点滴滴的文章,以此来为准备尝试前后端分离或者想了解前后端分离的童鞋做一个大体的讲解. 尝试与改变 如果你没有尝试过前后端分离的工作流程, ...

  5. crm开源系统 tp框架_八个开源的 Spring Boot 前后端分离项目,一定要收藏!

    点击蓝色字关注我们 前后端分离已经在慢慢走进各公司的技术栈,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,也非常建议大家学习一下前后端分离开发,以免在公司干了两三年,SS ...

  6. servlet里面为什么有时候覆_为什么新来的经理强烈推荐?前后端分离知识,学到了...

    引言 前后端分离这个词相信大家都听过,不知道大家是怎么理解的呢.前阵子看项目的时候,有一段实现硬是没看懂,下面来给大家说一下一段愚蠢的经历哈. (我没正正式式写过前端,所以如果文章有错的地方希望可以在 ...

  7. springboot jwt token前后端分离_7个开源的 Spring Boot 前后端分离项目,一定要收藏!...

    前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开发,以免在公司干了两三年 ...

  8. c2c旅游springboot开源_7个开源的 Spring Boot 前后端分离项目,一定要收藏!

    前后端分离已经在慢慢走进各公司的技术栈,根据松哥了解到的消息,不少公司都已经切换到这个技术栈上面了.即使贵司目前没有切换到这个技术栈上面,松哥也非常建议大家学习一下前后端分离开发,以免在公司干了两三年 ...

  9. Nginx学习总结(10)——Nginx前后端分离将多个请求转发到多个Tomcat,负载均衡反向代理

    一.谈谈"渲染" 相信好多人都挺听过"渲染"这个词,但不清楚它是什么意思?前端开发以为这是后端的活儿,后端开发以为是前端的事儿,推着推着就不了了之.其实渲染很简 ...

最新文章

  1. 代码段、数据段、bss段
  2. POJ 1904 King's Quest(强连通分量)
  3. Linux主机通过直连线直连,【IT基础】网线的直连线与交叉线之间的区别
  4. 增量式pid调节方式有何优点_PID控制算法
  5. 【学习笔记】HTML基础:使用html制作网页
  6. 已知起点坐标、角度、长度求终点坐标
  7. php资源文件html,nginx 同一域名下分目录配置显示php,html,资源文件
  8. WPF版的权限管理系统
  9. poj 1860 bellman 求正环
  10. 挑战性题目DSCT601:背包问题
  11. 小米手机助手linux,小米手机助手
  12. 跨浏览器书签导入实例演示,更好的管理书签!
  13. echarts scatter3D 图标陷进地图
  14. 删除MacOS的升级文件
  15. Codeforces Round #783 (Div. 2) A-F
  16. VR在国内越做越“廉价”,到底需要反思什么?
  17. 细胞穿膜肽IAWVKAFIRKLRKGPLG
  18. 逆战班学习之javascript内置对象之–数组
  19. 2.4g和5g要不要合并_路由器WiFi 2.4G和5G要不要合并?双频合一的缺点分析
  20. 数据采集卡 DAQmx

热门文章

  1. java反序列化漏洞的一些gadget
  2. ysoserial java 反序列化 Groovy1
  3. btc比特币 钱包简介
  4. linux sudo命令错误 is not in the sudoers file
  5. Linux国内源介绍
  6. WinInet编程详解
  7. 什么是ATL? (与COM的关系,及MFC与COM的关系)
  8. Android开发精要2--Android组件模型解析
  9. C++中智能指针的设计和使用
  10. Design Pattern Template Method C