多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
1.什么是CRUD CRUD是指在做计算处理时的增加(Create)、检索(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写。CRUD主要被用在描述软件系统中数据库或者持久层的基本操作功能。 目的是我们将常用的增、删、改、查操作封装在一套接口组件中,在多个功能中重复调用这一套接口组件,从而使代码更精简,同时提升开发效率。 2.在本项目中的接口优化实现方法说明 我们根据已经写好的单个功能接口进行改动讲解。 首先,我们再次深度理解server端接口页面: ![](https://img.kancloud.cn/ba/a3/baa3cd65aa8b3939d9ff12eb8e15fded_1218x1347.png) (1)项目中,我们以node.js作为后端进行服务器的开发。就像PHP后端的ThinkPHP框架一样,在node中我们使用express框架,所以接口页面我们要首先引入express。 (2)该路由文件指向admin端,需要使用express框架的路由进行接口的调用。 (3)引用定义好的数据库模型,一切数据通过模型定义的字段和类型进行判断与上传。 (4)编写接口。 第二步,我们要找出在不同功能模块中调用接口时需要变化的地方,此时我们用分类功能和文章功能的两套接口做比较。 ![](https://img.kancloud.cn/ce/d8/ced8624a6dff13624bf56b4d73a903df_1428x982.png) 在图中我们可以看出,接口方法基本相同,不同的地方就是接口路由地址和数据库表的模型名。所以要想使用通用CRUD接口,只需要将接口路由地址和模型名做成从前端接收数据的变量即可。 第三步,更改接口路由地址。 我们需要修改代码参照RESTful风格,rest是一种接口设计风格,大家感兴趣的百度查一查。下面我们直接代码讲解。 ``` // 定义“admin/api”路由方法,挂载存入到router // RESTful风格接口,在api后加一个rest前缀,与程序员编写代码原则类似,避免以后与其他接口冲突。 // 动态resours资源,用来存放接口路由地址(原categories、articles)。这里写成这样之后,上边的接口地址名就以“/”表示。 app.use('/admin/api/rest/:resourse', router) ``` 将动态resourse添加到路由方法中之后,这个“:resourse”就代表了之前地址中的categories。所以在上边的接口函数中将categories去掉,用“/”替换。 修改前: ``` // 上传数据(增) router.post('/categories', async(req, res) => { // 在里边放该接口的具体操作,所有操作同级放置 // 数据来源是接受到的req中的body // 为避免阻塞,要用异步操作,故加入await const model = await Category.create(req.body) // 接收返回值 res.send(model) }) ``` 修改后: ``` // 上传数据(增) router.post('/', async(req, res) => { // 在里边放该接口的具体操作,所有操作同级放置 // 数据来源是接受到的req中的body // 为避免阻塞,要用异步操作,故加入await const model = await Category.create(req.body) // 接收返回值 res.send(model) }) ``` 除地址以外都无需变化。 第四步,更改模型的引入。 接口地址修改完成后,同样需要修改模型的引入方法。之前的全局引入方式就不能用了。 ![](https://img.kancloud.cn/d8/07/d8079d066c99f17a339cd027032eac9a_491x321.png) 要在接口内部引入,并且使用: ``` // 查询数据(查) router.get('/', async(req, res) => { const Model = require('../../models/' + req.params.resourse) const items = await Model.find().populate('parent').limit(10) res.send(items) }) ``` 第五步,接收接口地址并将接口名传值给模型,用来当作模型名。 先把admin端axios接口地址改一下,改成rest/categories,方便之后分类列表刷新的测试。 ![](https://img.kancloud.cn/1a/09/1a0908b751ebf7058eb4ce1890a2e035_1218x1347.png) 接口传值在req.params.resourse找到,并将该值放置在模型处,用来当作模型名。 此时找到分类列表页面测试,network中找到错误,显示未定义模型名: ![](https://img.kancloud.cn/a6/13/a6130b3bf947aad5823b9273fb637429_1275x396.png) 因为我们在文件全局使用resourse接收,但在接口内部使用传来的值,所以必须在router中合并接收的参数:![](https://img.kancloud.cn/1b/98/1b98d4f83dbf3a0c8847c8239a8c11fb_1218x1347.png) 修改router后,找到了模型名,但因为接口地址为分类的复数形式,所以模型名接收到的也是复数,所以此时模型名因格式不对同样无法调用模型: ![](https://img.kancloud.cn/29/3e/293e9c69221f900b9d4a8b8ebc2575b6_1055x384.png) 我们此时要把接收到的模型名转化成单数,这里用到一个类包“inflection”,专门用来操作单复数的转换。 `cd admin` ``` npm i inflection ``` ![](https://img.kancloud.cn/19/c4/19c4c4fdfdc764fcf9909c621acc837d_522x77.png) 第六步,使用inflection类包将模型名转化为单数形式。 ``` // 查询数据(查) router.get('/', async(req, res) => { // 将接收的复数地址名转化为单数模型名 const modelName = require('inflection').classify(req.params.resourse) const Model = require('../../model/' + modelName) const items = await Model.find().populate('parent').limit(10) res.send(items) }) ``` 测试,没问题: ![](https://img.kancloud.cn/17/8f/178facbbea2edcb5b156585da7f62a6f_1665x1040.png) 到这里,一个通用CRUD接口就实现了。但是所有接口在模型名进行转化时的操作都相同,所以我们可以在路由方法处加一个中间件的处理函数,不用每次都对model名的转换写一遍: ``` app.use('/admin/api/rest/:resourse', async (req, res, next) => { // 从resourse获取路由地址名,并使用inflection的classify转换为单数形式 const modelName = require('inflection').classify(req.params.resourse) // 为请求数据挂载一个model,方便接口使用此模型名变量 req.Model = require('../../models/' + modelName) next() }, router) ``` 上边的模型名就使用中间件函数中挂载到req的model名,把接口中模型的地方全部改成req.model就可以了。 ![](https://img.kancloud.cn/fa/de/fade88f86c80e1df338608a059f8200c_592x771.png) admin端所有接口地址前加一个“rest/” ![](https://img.kancloud.cn/9f/b0/9fb06fe6b94ee79389002eea8a12d46c_1218x1325.png) 测试所有功能,没问题,包括分类或文章的增删改查、层级关联。 最后上一遍接口文件代码: ``` module.exports = app => { const express = require('express') const router = express.Router({ // 合并参数 mergeParams: true }) // 新建数据(增) router.post('/', async(req, res) => { // const Model = require('../../model/' + req.params.resourse) const model = await req.Model.create(req.body) res.send(model) }) // 查询数据(查) router.get('/', async(req, res) => { const items = await req.Model.find().populate('parent').limit(10) res.send(items) }) // 根据id查询数据(查) router.get('/:id', async(req, res) => { const model = await req.Model.findById(req.params.id) res.send(model) }) // 编辑数据(改) router.put('/:id', async(req, res) => { const model = await req.Model.findByIdAndUpdate(req.params.id, req.body) res.send(model) }) // 删除数据(删) router.delete('/:id', async(req, res) => { await req.Model.findByIdAndDelete(req.params.id, req.body) res.send({ success: true }) }) // 定义“admin/api”路由方法,挂载存入到router // RESTful风格接口,在api后加一个rest前缀,与程序员编写代码原则类似 // 动态resours资源,用来存放接口路由地址(原categories、articles)。这里写成这样之后,上边的接口地址名就以“/”表示 app.use('/admin/api/rest/:resourse', async (req, res, next) => { // 从resourse获取路由地址名,并使用inflection的classify转换为单数形式 const modelName = require('inflection').classify(req.params.resourse) // 为请求数据挂载一个model,方便接口使用此模型名变量 req.Model = require('../../models/' + modelName) next() }, router) } ``` 注意,如有错误的地方,要检查admin端组件中axios发送接口请求时的接口地址是否正确,并检查NetWork中的报错信息。实在不行文章评论,或公众号截图给我。