结构及封装
三层结构
- 通过前端将数据发送到表现层
js
axios({
// 设置请求类型
method: 'post',
// 设置前后端链接接口
url: '/users/login',
// 设置前端发送给后端的数据
data: {},
})
.then((response) => {})
.catch((error) => {})
- 配置数据库连接(database)
js
// 连接 MongoDB
const mongoose = require('mongoose')
// 项目需要连接的数据库地址
const dbURI = 'mongodb://localhost:27017/xiaobin'
// 关闭警告
mongoose.set('strictQuery', true)
// 连接数据库
mongoose.connect(dbURI)
// 当数据库连接成功时触发下面事件
mongoose.connection.on('connected', function () {
console.log(dbURI + '数据库连接成功')
})
- 配置 app.js
js
// 引入路由
var usersRouter = require('./routes/users')
// 引入第三层(持久层)
require('./dao/database')
// 用于配置 Ajax 请求的一级路径
app.use('/users', usersRouter)
- 配置第一层表现层(routes)
js
var express = require('express')
var router = express.Router()
// 二级路径
router.get('/login', function (req, res, next) {
// req.body: 获取 get 请求数据
// req.query: 获取 post 请求数据
res.send()
})
module.exports = router
- 配置第二层服务层(service)
js
// 引入第三层
const { daoLogin } = require('../dao/usersDao')
// 登录
async function serviceLogin(user) {
// 调用第三层
const data = await daoLogin(user)
}
module.exports = { serviceLogin }
- 配置第三层持久层(Dao)
js
// 引入模型
const { usersModel } = require('./models/usersModel')
// 登录
async function daoLogin(user) {
return await usersModel.find(user)
}
module.exports = { daoLogin }
- 配置模块(models)
js
// 1.定义数据集合的结构:定义集合中数据有哪些属性,属性的值类型是什么类型
const { Schema, model } = require('mongoose')
const usersSchema = new Schema({
userName: String,
password: String,
})
// 2.定义数据集合的模型:将 schema 和数据库中的数据关联起来
// model('模型名称','schema名称','数据库中的集合名称')
const usersModel = model('usersModel', usersSchema, 'users')
module.exports = { usersModel }
- 端口更改
js
app.listen(3000, () => {
console.log('服务器开启成功端口号为:http://localhost:3000')
})
express 方法
- 深层嵌套
js
.populate({
path: 'classId', // 第一层关联路径
populate: {
path: 'teacherId' // 第二层关联路径
}
})
- 请求限制
js
.limit(请求条数 - 0) // 设置请求条数
- 请求跳过
js
.skip((请求页数 - 1) * 请求条数) // 跳过数据的条数
- 关联集合
js
const studentsSchema = new Schema({
// 用于关联classes集合
classId: {
type: Schema.Types.ObjectId, // id
// ref 用于设置要关联的集合模型名称
ref: 'classesModel',
},
})
查询
- 全部查询,带数据劫持
js
// 获取学生数据
async function daoGetStudents({ pageSize(条), currentPage(页) }) {
// 获取数据的总条数
const total = await studentsModel.countDocuments()
// 计算总页数
const pages = Math.ceil(total / pageSize)
const students = await studentsModel
.find()
// 关联.populate('classId')
.populate({
path: 'classId',
populate: {
path: 'teacherId'
}
})
.limit(pageSize - 0) // 设置请求条数
.skip((currentPage - 1) * pageSize) // 跳过数据的条数
return {
total, pages, students
}
}
- 添加查询不带数据劫持
js
// 条件渲染
async function searchStudents(params) {
const students = await studentsModel
.find({
// 键 值,不区分大小写
[params.selectValue]: { $regex: params.searchValue, $options: 'i' },
})
.populate({
path: 'classId',
populate: {
path: 'teacherId',
},
})
return {
students,
}
}
图片上传
- 图片上传流程
主要流程
- 前端部分
- 页面上设置一个上传文件的 input 标签,并设置 onchange 事件
- 通过 onchange 事件获取要上传的文件数据并通过 ajax 传给后端
- 后端部分
- 需要通过 npm 安装图片处理插件
multer
- 单独新建一个处理图片的路由文件,即
routes/upload.js
- 在第二步新建 js 中引入文件
handlerFile.js
,用于在 nodejs 环境下配合 multer 插件完成图片上传 - 将图片上传后的服务器地址传回前端。前端就可以获取上传的图片的地址。可以通过 img 标签进行展示
- 需要通过 npm 安装图片处理插件
handleFile 封装工具
js
const multer = require('multer')
const fs = require('fs')
const path = require('path')
/**
* 文件上传
* 参数说明:接收一个 options 对象作为参数,该对象包含两个属性
* - path: 图片上传路径
* - key:与前端 formData 对象的 fieldname 相匹配(即: formData.append()方法的第一个参数)
* - size:设置图片大小
*/
function uploadFiles(options = {}) {
// 1.对参数 options 进行结垢并设置默认值
let { path = './public/temp', key = 'file', size = 1000 } = options
// 2.设置 multer 的参数,配置 diskstorage 来控制文件存储的位置及文件名
let storage = multer.diskStorage({
// 2.1 确定图片位置
destination: function (req, res, cb) {
try {
fs.accessSync(path)
} catch (error) {
fs.mkdirSync(path)
}
cb(null, path)
},
// 2.2 确定图片存储时的名字(注意:如果使用原名,可能会造成再次上传同一张图片)
filename: function (req, file, cb) {
let changedName = new Date().getTime() + '-' + file.originalname
cb(null, changedName)
},
})
// 3. 配置图片限制
let limits = {
// 限制文件大小
fileSize: 1024 * size,
// 限制文件数量
files: 5,
}
// 4.生成的专门处理上传的一个工具,可以传入 storage。limits等配置
let upload = multer({ storage, limits })
// 5.返回多文件上传设置信息(同样可以上传单文件)
return upload.array(key)
}
/**
* 文件复制
* fromPath:源文件路径
* - toPath:要复制过去的新文件
* - filename:文件名
*/
function copyFiles(options = {}) {
let {
fromPath = './public.temp/',
toPath = './public/images/',
filename,
} = options
let sourceFile = path.join(fromPath, filename)
let destPath = path.join(toPath, filename)
try {
fs.accessSync(toPath)
} catch (error) {
fs.mkdirSync(toPath)
}
let readStream = fs.createReadStream(sourceFile)
let writeStream = fs.createWriteStream(destPath)
readStream.pipe(writeStream)
}
/**
* 文件移动
* - fromPath:源文件路径
* - toPath:要复制过去的新文件
* - filename:文件名
*/
function moveFiles(options = {}) {
let {
fromPath = './public/temp/',
toPath = './public/images/',
filename,
} = options
let sourceFile = path.join(fromPath, filename)
let destPath = path.join(toPath, filename)
try {
fs.accessSync(toPath)
} catch (error) {
fs.mkdirSync(toPath)
}
fs.renameSync(sourceFile, destPath)
}
/**
* 删除文件
* - filePath:文件路径
*/
function removeFiles(filePath = './public/temp') {
let stats = fs.statSync(filePath)
if (stats.isFile()) {
// 删除文件
fs.unlinkSync(filePath)
} else if (stats.isDirectory()) {
let filesArr = fs.readdirSync(filePath)
filesArr.forEach((file) => {
removeFiles(path.resolve(filePath, file))
})
}
fs.rmdirSync(filePath)
}
module.exports = {
uploadFiles,
copyFiles,
moveFiles,
removeFiles,
}
前端部分
- 页面部分:input 标签,并设置 onchange 事件
html
<input
type="file"
id="uploadInput" />
<h1>上传图片展示</h1>
<img
src=""
alt=""
id="uploadImg" />
- ajax 部分:获取图片数据,并包装为 formData 格式,并通过 ajax 发送到后端。需要注意的是,为了防止 jQuery 自动处理,需要传递两个参数来取消 jQuery 的表单自动处理
js
$('body').on('change', '#uploadInput', function () {
//获取文件数据
let file = this.files[0]
//以表单数据方式将文件发送到后端
let fd = new FormData()
fd.append('file', file)
//通过ajax发送到后端
$.ajax({
url: '/upload/image',
success: function (data) {
console.log(data)
},
data: fd,
//设置参数,防止jQuery自动处理,以便将文件数据原封不动的传给后端处理
contentType: false,
processData: false,
cache: false,
})
})
时间插件
- 下载
bash
npm i moment
- 引入
js
const moment = require('moment')
- 使用格式化时间
js
time: {
type: String,
default: moment().format('YYYY-MM-DD HH:mm')
}
后端部分
- 安装
multer
插件
bash
npm i multer
- 新建路由并在 app.js 中配置
js
var express = require('express')
var router = express.Router()
module.exports = router
- 设置图片处理的相关代码
js
// 引入handlerFile.jsconst
{ uploadFiles } = require('./../util/handleFiles');
router.post('/image', function (req, res, next) {
//会针对传入的图片生成一个专门上传的图片函数
let path = 'assets';
//自定义保存图片的文件夹,会直接放在/public下
const uploadImages = uploadFiles({
path: `./public/${path}`,
//formdata.append()的第一个参数
key: 'file',
//图片的大小限制,1mb以内
size: 1024
});
//上传函数
uploadImages(req, res, (err) => {
//图片上传失败或成功都会调用的回调函数
if (err) {
//上传失败
console.log(err);
res.send({ message: "上传失败", code: -1 })
} else {
//上传成功
//将上传成功之后图片的路径发送给前端
res.send({
message: '上传成功',
data: `../${path}/${req.files[0].filename}`,
code: 200
})
}
})
})
- 前端根据返回的地址进行展示