JS全栈后端Server部分 (1)-初始化及分类接口编写
关于初始化和路径参考JS全栈前端后台管理部分笔记(1)- 初始化及分类CURD.md
切换到server
目录并启动项目
npm run serve
安装主要依赖
npm install express@next mongoose cors
注意,安装express时必须指定next,表示下一个版本,用来支持async和await的ES6新语法。
主程序
//index.js
路由
按照模块来建立路由文件,创建routes/amdin/index.js
//index.js
module.exports = app =>{
const express = require("express");
const router = express.Router();//子路由
router.post("/categories",async(req,res)=>{
......
})
app.use("/admin/api",router)//将子路由挂在到实例上
}
-
文件导出使用一个函数,目的是传入express实例,
-
router.post("/categories"… 表示定义一个categoreis接口,允许的方法是post。
-
app.use("/admin/api",router) 意思是使用express提供的Router函数生成子路由router,最后挂载到app上。 use的第一个参数是定义整个路由文件中请求的前半部分,也就是请求
/amdin/api/categoreis
才能访问到上一个接口。简化接口定义,不用重复写前边一样的路径了。
导入同时传入express实例
//index.js
require("./routes/admin")(app)
数据库
与路由文件相同,单独建立plugins/db.js
文件,
//db.js
module.exports = app => {
const mongoose = require("mongoose");
mongoose.connect("mongodb://127.0.0.1:27017/node-vue-moba", {
useNewUrlParser: true,//连接参数
});
}
导入
//index.js
require("./plugins/db.js")(app)
模型
根目录新建models
文件夹,建立Category.js
//Category.js
const mongoose = require("mongoose");
const schema = new mongoose.Schema({
name:{type:String}
})
module.exports = mongoose.model("Category",schema);
-
schema的意思是模式,我的理解是对数据库的抽象,定义了数据表collecitons要保存的数据格式,如String类型的type字段。
-
最后导出利用了mongoose的model方法定义一个名称为Category,类型为schema的model。
注意,最后导出的model就是对mongoDB中数据表collection的js化,mongoose在中间做了一层映射,我们对model的操作最后会转换为对MongoDB对应collection的操作。
导入并使用
//routes/admin/index.js
const Category = require("../../models/Category.js")
router.post("/categories", async (req, res) => {
const model = await Category.create(req.body)//将提交内容保存到mongoDB中
res.send(model);
})
-
导入后,在接口处理函数中创建记录。
-
新增一条记录document的方法是create,其中req.body是请求内容,由于是post方式提交的,如果要直接使用req.body来提取到提交内容,必须使用express.json()中间件。
//index.js
app.use(express.json())
注意这里使用了await语法,目的是异步实现用同步语法来编写,如果不用的话,上述实现会变为
Category.create(req.body,function(data){
const model = data;
res.send(model)
}){//将提交内容保存到mongoDB中
res.send(model);
},
async和await能减少回调函数编写,避免回调地狱。
跨域
express实例使用cors模块作为中间件实现
//index.js
app.use(require("cors")())//跨域用
编写完成后,利用前端网页想数据库增加分类数据。
其他接口实现
注意:上面内容多为基础配置,下面为具体实现,只记录自己不会或者新学到的知识点。
分类列表接口
增加分类列表请求处理接口
//routes/admin/index.js
router.get("/categories", async (req, res) => {
const items = await Category.find().limit(10);//查询,限制10条
res.send(items);
})
- find() 为查询方法,这里暂时使用limit方法限制结果为前10条。
分类详情接口
//分类详情
router.get("/categories/:id", async (req, res) => {
const model = await Category.findById(req.params.id);
res.send(model);
})
- findById 是mongoose提供的根据id查数据的方法。
- router.get("/categories/:id"…中:id代表匹配的路由,最后一个字符串是id
- get请求方的id具体内容通过req.params.id来得到。
编辑分类接口
//编辑分类
router.put("/categories/:id", async (req, res) => {
const model = await Category.findByIdAndUpdate(req.params.id, req.body);
res.send(model);
})
-
使用put请求方法来更新
-
使用 findByIdAndUpdate 方法来update,第一个参数是url中的id,第二个是更新的内容
子类别(无限极分类)
类别下面有子类别,有些子类别下边有孙子类别,为了实现这样的层次,需要对数据库进行修改。分类无论多少层级,在数据库中都是平行存储的,父子类别的关系就需要想办法来体现。
一般可以用一个类别的属性与另一个类别相关联,子类别与父类别的关系是多对一。
在现有类别模型中新增一个parent属性,这个属性指向(绑定)他的父类别的id。
//models/Category.js
const schema = new mongoose.Schema({
name: { type: String },
parent: { type: mongoose.Types.ObjectId }
})
- parent是新增的属性,用于关联父类别,
- 注意parent的类型,虽然在数据库中_id不是字符串,而是 mongoose.Types.ObjectId
- 关联操作利用ref来实现,ref表示该字段关联的哪个模型,这里是自己本身。关联之后,查询一条记录就可以连带查询出关联记录,类似于MySQL中的外键。
增加父级类别后,为在前端显示,需要修改分类列表接口
const items = await Category.find().populate("parent") .limit(10);//查询,限制10条
- populate是关联查询,参数是关联字段,使用此方法后会把关联的对象也查出来。
以下是不加populate的查询结果,
[
以下是加了populate的查询结果
明显可以看出populate把有关联的类别整体查了出来,这样就能提供给前端显示父级类别的名称了。
无论是多少级,都可以使用这样id绑定的方法来建立关系,而且还能保证数据库存储的平行性。