Skip to content

结构及封装

三层结构

image-20230203012230365

  1. 通过前端将数据发送到表现层
js
axios({
	// 设置请求类型
	method: 'post',
	// 设置前后端链接接口
	url: '/users/login',
	// 设置前端发送给后端的数据
	data: {},
})
	.then((response) => {})
	.catch((error) => {})
  1. 配置数据库连接(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 + '数据库连接成功')
})
  1. 配置 app.js
js
// 引入路由
var usersRouter = require('./routes/users')
// 引入第三层(持久层)
require('./dao/database')
// 用于配置 Ajax 请求的一级路径
app.use('/users', usersRouter)
  1. 配置第一层表现层(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
  1. 配置第二层服务层(service)
js
// 引入第三层
const { daoLogin } = require('../dao/usersDao')
// 登录
async function serviceLogin(user) {
	// 调用第三层
	const data = await daoLogin(user)
}
module.exports = { serviceLogin }
  1. 配置第三层持久层(Dao)
js
// 引入模型
const { usersModel } = require('./models/usersModel')
// 登录
async function daoLogin(user) {
	return await usersModel.find(user)
}
module.exports = { daoLogin }
  1. 配置模块(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 }
  1. 端口更改
js
app.listen(3000, () => {
	console.log('服务器开启成功端口号为:http://localhost:3000')
})

express 方法

  1. 深层嵌套
js
 .populate({
    path: 'classId', // 第一层关联路径
    populate: {
         path: 'teacherId' // 第二层关联路径
  	 }
})
  1. 请求限制
js
.limit(请求条数 - 0) // 设置请求条数
  1. 请求跳过
js
.skip((请求页数 - 1) * 请求条数) // 跳过数据的条数
  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,
	}
}

图片上传

  • 图片上传流程

主要流程

  1. 前端部分
    • 页面上设置一个上传文件的 input 标签,并设置 onchange 事件
    • 通过 onchange 事件获取要上传的文件数据并通过 ajax 传给后端
  2. 后端部分
    1. 需要通过 npm 安装图片处理插件multer
    2. 单独新建一个处理图片的路由文件,即routes/upload.js
    3. 在第二步新建 js 中引入文件handlerFile.js,用于在 nodejs 环境下配合 multer 插件完成图片上传
    4. 将图片上传后的服务器地址传回前端。前端就可以获取上传的图片的地址。可以通过 img 标签进行展示

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,
}

前端部分

  1. 页面部分:input 标签,并设置 onchange 事件
html
<input
	type="file"
	id="uploadInput" />
<h1>上传图片展示</h1>
<img
	src=""
	alt=""
	id="uploadImg" />
  1. 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,
	})
})

时间插件

  1. 下载
bash
npm i moment
  1. 引入
js
const moment = require('moment')
  1. 使用格式化时间
js
time: {
    type: String,
    default: moment().format('YYYY-MM-DD HH:mm')
}

后端部分

  1. 安装multer插件
bash
npm i multer
  1. 新建路由并在 app.js 中配置
js
var express = require('express')
var router = express.Router()
module.exports = router
  1. 设置图片处理的相关代码
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
               })
           }
       })
   })
  1. 前端根据返回的地址进行展示