Node.js实现服务器端通用CRUD接口

核心原理:使用动态参数,使得传递任何资源都可以。通过客户端传递过来的动态参数,查找到客户端对应的模型文件。

问题:客户端传递过来的参数是小写复数形式(如categories、items),数据库模型类名是大写单数形式(如Category、Item)。

解决方法:采用中间件,把传递过来的动态参数名称转为数据库模型名称,并找到对应的数据库模型的类,挂载到请求对象上。


一. 安装所需包

# 用于处理单复数转换,单词的格式转换
npm i inflection

二. 项目结构

三. 核心代码

 1. 入口文件 index.js :

const express=require("express")

const app=express()

app.use(express.json())
app.use(require('cors')())
app.use('/uploads',express.static(__dirname+'/uploads')) //静态文件托管

// 路由用module.exports导出一个函数,参数接收函数对象,在里面就可以用最外层的app
require('./routes/admin')(app)
require('./plugins/db')(app)

app.listen(3000,()=>{
    console.log('http://localhost:3000')
})

2. 路由文件 /routes/admin/index.js :

// 通用CRUD接口 - 资源路由

// module.exports导出一个函数,参数接收函数对象,在里面就可以用最外层的app
module.exports=app=>{
    const express=require('express')
    //由于我们是在app.use()里定义的动态参数,又在router里用到动态参数,所以需要合并url参数
    const router=express.Router({
        mergeParams:true
    })

    // 数据库模型
    // const Category=require('../../models/Category') 

    // 通用CRUD接口:动态参数,传递任何资源都可以。通过客户端传递过来的动态参数,查找到客户端对应的模型文件
    // 新建xx列表
    router.post('/',async(req,res)=>{
        const model=await req.Model.create(req.body) //数据来源是客户端提交过来的数据
        res.send(model) //创建完成后,发回给客户端
    })

    // 修改xx详情数据,通过id
    router.put('/:id',async(req,res)=>{
        const model=await req.Model.findByIdAndUpdate(req.params.id,req.body) //数据来源是客户端提交过来的数据
        res.send(model) //创建完成后,发回给客户端
    })

    // 删除xx,通过id
    router.delete('/:id',async(req,res)=>{
        await req.Model.findByIdAndDelete(req.params.id) 
        res.send({
            success:true
        }) 
    })

    // 获取xx列表
    router.get('/',async(req,res)=>{
        const queryOptions = {}
        let items=await req.Model.find().setOptions(queryOptions).limit(10)
        if (req.Model.modelName === 'Category') {
            //关联查询parent,使用populate取出关联字段的完整信息
            //queryOptions.populate = 'parent'
            items=await req.Model.find().populate('parent').limit(10) 
        }
        // setOptions将后面的链式操作转化为对象的形式【不知道为什么操作无法生效???】
        // const items=await req.Model.find().setOptions(queryOptions).limit(10) //xx列表的find,限制10条
        res.send(items) //把数据发回给客户端
    })

    // 获取xx详情数据,通过id
    router.get('/:id',async(req,res)=>{
        const model=await req.Model.findById(req.params.id)
        res.send(model) //把数据发回给客户端
    })
    
    // rest前缀代表restful风格的接口,防止通用CRUD接口和以后写的某个接口有冲突
    // :resource为动态参数
    // 中间件,用于把传递过来的动态参数名称转为数据库模型名称,并找到对应的数据库模型
    app.use('/admin/api/rest/:resource',async(req,res,next)=>{
        //转类名,将小写复数形式转成大写单数形式,例:categories转为Category
        const modelName=require('inflection').classify(req.params.resource)
        req.Model=require(`../../models/${modelName}`)  // 得到数据库模型的类,挂载到请求对象上
        next()
    },router)

    
    //上传文件
    const multer=require('multer')
    const upload=multer({dest:__dirname+'/../../uploads'}) //dest为目标地址
    // single接收单个文件上传
    app.post('/admin/api/upload',upload.single('file'),async(req,res)=>{
        const file=req.file  //multer把上传文件的数据挂载到req上了
        file.url=`http://localhost:3000/uploads/${file.filename}`
        res.send(file)
    })

}

3. 数据库连接文件 /plugins/db.js :

// 数据库
module.exports=app=>{
    const mongoose=require("mongoose")
    mongoose.connect('mongodb://127.0.0.1:27017/node-vue-moba')
}

4. Mongodb数据库模型文件:

        /models/Category.js :

const mongoose=require('mongoose')
// 定义模型的字段
const schema=new mongoose.Schema({
    name:{type:String},
    parent:{type:mongoose.SchemaTypes.ObjectId,ref:'Category'}, //数据类型是数据库中的ObjectId,ref指定要关联的模型
})
// 导出mongoose模型
module.exports=mongoose.model('Category',schema)

        /models/Item.js :

const mongoose=require('mongoose')
// 定义模型的字段
const schema=new mongoose.Schema({
    name:{type:String},
    icon:{type:String},
})
// 导出mongoose模型
module.exports=mongoose.model('Item',schema)

参考资料:

你真的了解mongoose吗?_mb5ff590f157b0e的技术博客_51CTO博客你真的了解mongoose吗?,引言继上篇文章「Koa2+MongoDB+JWT实战--RestfulAPI最佳实践」后,收到许多小伙伴的反馈,表示自己对于mongoose不怎么了解,上手感觉有些难度,看官方文档又基本都是英文(宝宝心里苦,但宝宝不说)。为了让各位小伙伴快速上手,加深对于mongoose的了解,我特地结合之前的项目整理了一下关于mongoose的一些基础知识,这些对于实战都是很有用的。相信看了这篇文章,https://blog.51cto.com/u_15077541/2608049[第一章 + 第二章] NodeJs + VueJs (Express + ElementUI) 全栈开发王者荣耀手机端官网和管理后台_哔哩哔哩_bilibili免费不易,淘宝同名店铺《全栈之巅》求关注QQ2群:839167184,微信加小姐姐732500779拉群Git 源码: https://github.com/wxs77577/node-vue-moba,代码都在各个分支里,持续更新中,欢迎 star;编辑器 vscode,主题 material theme,字体mononoki;请先安装 nodejs 10+ ,mongodb server,nohttps://www.bilibili.com/video/BV1A4411Y7fi?p=14&spm_id_from=333.1007.top_right_bar_window_history.content.clickvscode实用快捷键查找和替换_Angela-的博客-CSDN博客_vscode全局替换快捷键vscode是一款功能十分强大的编辑器,且带有许多插件,利用插件可以让开发速度提升几倍甚至几十倍。vscode快捷键:查找:单文件查找:ctrl + F替换:单文件内替换一处:crtl + shift + 1单文件内替换全部:ctrl + alt + enter也可以用鼠标点击替换,如图查找文件夹下所有文件中是否包含某个关键字:ctrl + shift + F替换全局查找检索到...https://blog.csdn.net/weixin_44135807/article/details/102513935

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值