技术栈:node + express + mongoose
git地址,可直接使用。
nodemon 热更新
使用nodemon启动项目,可以在修改代码时不用重新启动。
// 安装
npm i nodemon
安装之后,修改启动命令,
// package.json
{
"scripts": {
"start": "nodemon index.js"
}
}
中间件
body-parser
body-parser解析请求参数,使我们可以通过req.body.xx访问参数。
// index.js
var bodyParser = require('body-parser');
app.use(bodyParser.json());
cookie-parser
cookie-parser解析请求携带的cookie,使我们可以通过req.cookies访问cookie。
const email = JSON.parse(req.cookies[config.cookieName]).email;
// index.js
var cookieParser = require('cookie-parser');
app.use(cookieParser());
路由中间件
借助路由中间件,我们可以格式化接口返回值。
// routers/index.js
var express = require('express');
var router = express.Router();
router.use((req, res, next) => {
res.jsonSuccess = (data) => {
res.json({
code: 200,
message: 'success',
result: data,
});
};
res.jsonFail = (message) => {
res.json({
code: 500,
message: message.message || '服务器出了点问题',
});
};
next();
});
module.exports = router;
mongoose指令
查
find查找所有符合条件的数据;
findOne查找第一个符合条件的数据;
findById查找符合条件的数据,查询条件为id;
Model.find(conditions, [projection], [options], [callback])
model.find(
{age:{$gte:18,$lte:80}}, // age字段大于等于18且小于等于80 的数据
{_id:0,__v:0}, // 数据文档不返回_id和__v字段
{sort:{age:-1}} // 根据age字段以大到小顺序返回数据文档
)
$gte是操作符,类似的操作符还有不少:
$eq相等$ne不相等$gt大于$gte大于等于$lt小于$lte小于等于$in与数组中任意一个匹配$nin与数组中每一个都不匹配$and满足数组中所有条件$nor所有条件都不满足$or满足数组的其中一个条件$not不满足条件$exists存在指定字段$type属于指定类型$all匹配包含查询数组所有条件的数组字段$elemMatch匹配数组字段中的某个值满足指定的所有条件$size匹配数组字段的length与查询条件相同 Same as querySame as query conditions
projection指定查询结果包含或不包含哪些字段,也可以写成字符串:"-_id -__v",不能包含不包含同时使用。
findOne和findById的区别在于id为undefined的情况,findOne({ _id: undefined })返回任意一条数据,findById(undefined)返回null。
增
save([options], [options.safe], [options.validateBeforeSave], [fn])增加一条,需要写实例化;
Model.create(doc(s), [callback])增加一条或多条;
Model.insertMany(doc(s), [options], [callback])增加多条;
save()的示例如下:
// models/user.js
var mongoose = require('./index');
var UserSchema = mongoose.Schema({
email: {
type: String,
unique: true,
},
});
var UserModel = mongoose.model('User', UserSchema);
module.exports = UserModel;
// routers/user.js
var router = require('./index.js');
var User = require('../models/user');
// 新增项目
router.post('/user/add', async function (req, res) {
try {
const user = new User(req.body);
await user.save(); // save
res.jsonSuccess();
} catch (error) {
res.jsonFail(error);
}
});
module.exports = router;
删
findOneAndDelete找到第一个符合条件的并删除;
findByIdAndDelete查询条件为id;
deleteMany删除所有符合条件的;
Model.findOneAndDelete(filter, options, callback)
改
findOneAndUpdate和findByIdAndUpdate都是先查找然后再修改;
updateOne也是查找符合条件的第一条数据并修改;
updateMany是批量修改数据;
Model.findOneAndUpdate(filter, update, [options], [callback])
举个例子:
const info = await User.findByIdAndUpdate(
{
_id: req.body.id
},
{
$set: {
pass: true
}
},
{}
)
解析excel文件
使用multer解析form-data数据,npm地址。
使用node-xlsx解析excel,npm地址。
const multer = require('multer');
const upload = multer();
const xlsx = require('node-xlsx');
router.post('/upload', upload.single('file'), async function (req, res) {
const sheets = xlsx.parse(path.resolve(__dirname, '../test.xlsx'));
const data = sheets[0].data; // 二维数组
});
使用req.file.mimetype可以获取文件的MIME type,可以以此来判断文件类型,excel文件的MIME type是application/vnd.openxmlformats-officedocument.spreadsheetml.sheet或application/vnd.ms-excel。
下载文件接口
使用sendFile可以直接返回文件类型数据。
router.get('/download', async function (req, res) {
try {
const filePath = path.resolve(__dirname, '../test.xlsx');
res.sendFile(filePath);
} catch (error) {
res.jsonFail(error);
}
});
const handleDownload = async () => {
const response = await fetch('/api/download');
const blob = await response.blob();
saveAs(blob, 'test.xlsx');
};
docker部署配置
# Dockefile文件
# 使用Node.js的官方镜像作为基础
FROM node:14
# 在容器中创建一个工作目录
WORKDIR /app
# 复制应用程序文件到容器中
COPY package*.json ./
# 安装依赖项
RUN npm install
# 复制应用程序代码到容器中
COPY . .
# 暴露容器的端口
EXPOSE 3000
# 定义容器启动时运行的命令
CMD ["npm", "start"]