node+vue3项目流程(1)

184 阅读8分钟

创建node模板

特点:

1.对表单输入前端验证,使用bcrypt中间件进行后端密码加密
2.用户可通过邮箱账号进行匹配,修改密码
3.在编辑公司信息的弹窗中使用[富文本]插件,编辑内容后首页展示数据
4.使用echarts表,动态展示数据

数据大屏
定时获取新数据,进行动态展示
适配scale
countup.js实现数字滚动效果,
柱形图,雷达图,关系图,环形图,词云图,地图展示

使用数据库5.7.26

安装 npm i express -s

npm i nodemon -s 自动更新编写程序
npm install mysql 连接数据库

pnpm i cors   解决跨域请求
body-parser中间件 处理表单数据  pnpm i   body-parser
bcrypt
密码加密(使数据库存的密码不是明文,以随机编码方式存)  pnpm  i  bcryptjs   
例如:明文:yan123, 随机编码:7bccfde7714a1ebadf06c5f4cea752c1

Snipaste_2024-03-10_18-30-13.png

生成token中间件jsonwebtoken   pnpm i jsonwebtoken
解析token中间件 express-jwt    pnpm i express-jwt 
接口数据的验证 pnpm install @escook/express-joi
pnpm i  joi 安装Joi
---上传图像处理
pnpm i multer   此插件,用于上传头像
//1.导入node.js的crypto生成uuid(唯一标识)
const crypto = require('crypto')
//2.导入fs用于处理文件
const fs = require('fs')
  
有很多和上述具有相同功能的库可以选择,

前端

pnpm i vue-router@4 安装router
pnpm i element-plus
pnpm install sass-loader
pnpm install style-loader 
pnpm install mitt  安装全局事件总线
pnpm install echarts
--封装svg图标
pnpm i vite-plugin-svg-icons
pnpm i fast-glob
---
pnpm i pinia
pnpm i pinia-plugin-persistedstate
---富文本
pnpm install @wangeditor/editor --save
pnpm install @wangeditor/editor-for-vue@next --save
---
pnpm install echarts

1.配环境

// 导入express框架
const express=require('express')
//创建express实例
const app=express()
// 导入cors
const cors = require('cors')
// 全局挂载
app.use(cors())

// 绑定和侦听指定的主机和端口
app.listen(3007, () => {
	console.log('http://127.0.0.1:3007')
})

2.body-parser中间件 处理表单数据

// 导入express框架
const express=require('express')
//创建express实例
const app=express()
// 导入cors
const cors = require('cors')
// 全局挂载
app.use(cors())
// 导入body-parser
var bodyParser = require('body-parser')
// parse application/x-www-form-urlencoded
// 当extended为false时,值为数组或者字符串,当为ture时,值可以为任意类型
//-----------------------------------------------------------------------------------
app.use(
  bodyParser.urlencoded({
    extended: false,
  })
)

// parse application/json
app.use(bodyParser.json())
//-----------------------------------------------------------------------------------
// 绑定和侦听指定的主机和端口
app.listen(3007, () => {
	console.log('http://127.0.0.1:3007')
})

3.与数据库连接

创建db文件夹 db/index.js

// 导入mysql数据库
// npm install mysql
const mysql = require('mysql')

// 创建与数据库的连接
const db = mysql.createPool({
	host:'localhost',
	user:'back_system',
	password:'123456',
	database:'back_system'
})

// 对外暴露数据库
module.exports = db

4.路由

创建路由文件router

对路由处理文件router_handle

Snipaste_2023-11-14_17-20-18.png

测试

Snipaste_2023-11-14_17-36-37.png

Snipaste_2023-11-14_17-38-21.png

Snipaste_2023-11-14_17-38-41.png

Snipaste_2023-11-14_17-39-29.png

1.登录注册接口

Snipaste_2023-11-15_14-31-11.png

用户信息相关接口

1.上传头像接口

目录

Snipaste_2023-11-15_18-52-02.png

router/userinfo.js

const express = require('express')
const router = express.Router()
//涉及修改密码
// .导入expreJoi接口数据的验证
const expressJoi = require('@escook/express-joi')
// 导入路由处理模块,然后去router_handle写对应处理函数
const userinfoHandler = require('../router_handle/userinfo.js')
//------------------------------------------------------------------------------------
// 路由  上传头像
router.post('/uploadAvatar',userinfoHandler.uploadAvatar)
//3.暴露路由
module.exports=router

router_handle/userinfo.js

const db = require('../db/index.js')
// 导入bcrypt加密中间件
const bcrypt = require('bcryptjs')
//导入node.js的crypto生成uuid(唯一标识)
const crypto = require('crypto')
//导入fs用于处理文件
const fs = require('fs')
exports.uploadAvatar = (req, res) => {
	// res.send(req.files[0])  返回上传图片信息  进行测试
	// 1.生成olnyId随机ID,文件与用户对应
	const onlyId = crypto.randomUUID()
	//保存上传文件时随机生成的文件名filename,后期处理路径
	let oldName = req.files[0].filename;
	//在服务器中的文件名  originalname原生名字   toString('utf8')防止乱码,使用utf8编码
	let newName = Buffer.from(req.files[0].originalname, 'latin1').toString('utf8')
	//文件在服务器的名字进行更换
	fs.renameSync('./public/upload/' + oldName, './public/upload/' + newName)
	//sql语句
	const sql = 'insert into image set ?'
	db.query(sql, {
		image_url: `http://127.0.0.1:3007/upload/${newName}`,
		onlyId
	}, (err, result) => {
		if (err) return res.cc(err)
		res.send({
			onlyId,
			status: 0,
			url: 'http://127.0.0.1:3007/upload/' + newName
		})
	})
}

app.js

// 1.导入express框架
const express=require('express')
//2.创建express实例
const app=express()
//3. 导入cors
const cors = require('cors')
// 4.全局挂载
app.use(cors())
//-----------------------------------------------------------------------------------
// 7.使用multer
// Multer 是一个 node.js 中间件,用于处理 multipart/form-data 类型的表单数据,它主要用于上传文件。
const multer = require("multer");
// 在server服务端下新建一个public文件,在public文件下新建upload文件用于存放图片
const upload = multer({ dest:'./public/upload' })
//使用
app.use(upload.any())
// 静态托管,就没有public名字
app.use(express.static("./public"));
//-----------------------------------------------------------------------------------
// 5.导入body-parser
var bodyParser = require('body-parser')
// parse application/x-www-form-urlencoded
// 当extended为false时,值为数组或者字符串,当为ture时,值可以为任意类型
//-----------------------------------------------------------------------------------
app.use(
  bodyParser.urlencoded({
    extended: false,
  })
)

// parse application/json
app.use(bodyParser.json())
//-----------------------------------------------------------------------------------
// 6.导入jwt配置文件
const jwtconfig = require('./jwt_config/index.js')
//导入jwt
const { expressjwt: jwt } = require('express-jwt')
//使用jwt中间件排除不需要在请求端发送token的接口
// app.use(jwt({
// 	secret:jwtconfig.jwtSecretKey,algorithms:['HS256']  //算法
// }).unless({
// 	path:[/^\/api\//] //注登录不需要携带token
// }))
//-----------------------------------------------------------------------------------
// 处理错误中间件在 router_handle里调用
app.use((req, res, next) => {
  // status=0为成功,=1为失败,默认设为1,方便处理失败的情况
  res.cc = (err, status = 1) => {
    res.send({
      status,
      // 判断这个error是错误对象还是字符串
      message: err instanceof Error ? err.message : err,
    })
  }
  next()
})
//-----------------------------------------------------------------------------------
// 新建错误中间件,对不符合joi验证的账号密码进行报错
app.use((err, req, res, next) => {
  if (err instanceof Joi.ValidationError) {
    res.send({
      status: 1,
      message: '输入的数据不符合验证规则',
    })
  }
})
//-----------------------------------------------------------------------------------
// 绑定和侦听指定的主机和端口
//接口1
const loginRouter=require('./router/login.js')
//需要加前缀,本地路径访问加api前缀
app.use('/api',loginRouter)
//接口2
const userRouter=require('./router/userinfo.js')
// 挂载
app.use('/user',userRouter)
app.listen(3007, () => {
	console.log('http://127.0.0.1:3007')
})

Snipaste_2023-11-15_18-54-31.png

Snipaste_2023-11-15_18-54-59.png

测试

Snipaste_2023-11-15_18-32-24.png

真实返回

Snipaste_2023-11-15_18-47-10.png

数据库里也有了

Snipaste_2023-11-15_18-56-58.png

2. 绑定账号接口

onlyId与对应用户绑定头像,修改account表的image_url image表的account

router/userinfo.js

const express = require('express')
const router = express.Router()
//涉及修改密码
// .导入expreJoi接口数据的验证
const expressJoi = require('@escook/express-joi')
// 导入路由处理模块,然后去router_handle写对应处理函数
const userinfoHandler = require('../router_handle/userinfo.js')
//------------------------------------------------------------------------------------
// 路由  上传头像
router.post('/uploadAvatar',userinfoHandler.uploadAvatar)
//绑定账号
router.post('/bindAccount',userinfoHandler.bindAccount)

//3.暴露路由
module.exports=router

router_handle/userinfo.js

exports.bindAccount = (req, res) => {
	const {
		account,
		onlyId,
		url
	} = req.body
	const sql = 'update image set account = ? where onlyId = ?'
	db.query(sql, [account, onlyId], (err, result) => {
		if (err) return res.cc(err)
		if (result.affectedRows == 1) {
			const sql1 = 'update users set image_url = ? where account = ?'
			db.query(sql1, [url, account], (err, result) => {
				if (err) return res.cc(err)
				res.send({
					status: 0,
					message: '修改成功'
				})
			})
		}
	})
}

需要三个字段 uuid由随机生成,来和账号对应,匹配对应头像,防止头像地址相同而匹配混乱

Snipaste_2023-11-15_20-00-01.png

数据库

Snipaste_2023-11-15_20-04-18.png

Snipaste_2023-11-15_20-04-40.png

3. 获取用户信息接口

第一 当登陆成功会返回账号所有信息,把信息保存到localstorage里就可以渲染账户信息 第二 根据账号ID去数据库里查找信息(这里用第二种写的) router/userinfo.js

const express = require('express')
const router = express.Router()
//涉及修改密码
// .导入expreJoi接口数据的验证
const expressJoi = require('@escook/express-joi')
// 导入路由处理模块,然后去router_handle写对应处理函数
const userinfoHandler = require('../router_handle/userinfo.js')
//------------------------------------------------------------------------------------
// 路由  上传头像
router.post('/uploadAvatar',userinfoHandler.uploadAvatar)
//绑定账号
router.post('/bindAccount',userinfoHandler.bindAccount)
router.post('/getUserInfo',userinfoHandler.getUserInfo)
//3.暴露路由
module.exports=router

router_handle/userinfo.js

// 获取用户信息 接收参数 id
exports.getUserInfo = (req, res) => {
	const sql = 'select * from users where id = ?'
	db.query(sql, req.body.id, (err, result) => {
		if (err) return res.cc(err)
		result[0].password = ''
		res.send(result[0])
	})
}

查询的信息

Snipaste_2023-11-15_20-17-16.png

4. 修改姓名接口

router/userinfo.js

//同上添加接口路由
router.post('/changeName',userinfoHandler.changeName)

router_handle/userinfo.js

// 修改姓名 接收参数 id name
exports.changeName = (req, res) => {
	const {
		id,
		name
	} = req.body
	//根据id去users表更改name
	const sql = 'update users set name = ? where id = ?'
	db.query(sql, [name, id], (err, result) => {
		if (err) return res.cc(err)
		res.send({
			status: 0,
			message: '修改成功'
		})
	})
}

Snipaste_2023-11-15_20-25-08.png 数据库

Snipaste_2023-11-15_20-24-58.png

5. 修改姓名接口

router/userinfo.js

//同上添加接口路由
router.post('/changeSex',userinfoHandler.changeSex)

router_handle/userinfo.js

//5.修改性别接口
exports.changeSex = (req, res) => {
	const {
		id,
		sex
	} = req.body
	//注意 参数 要与sql语句位置对应[sex,id],不能写乱了
	const sql = 'update users set sex = ? where id = ?'
	db.query(sql, [sex,id], (err, result) => {
		if (err) return res.cc(err)
		res.send({
			status: 0,
			message: '修改成功'
		})
	})

}

Snipaste_2023-11-15_20-38-46.png 数据库

Snipaste_2023-11-15_20-39-12.png

6. 修改邮箱接口

router_handle/userinfo.js

// 修改邮箱 接收参数 id email
exports.changeEmail = (req, res) => {
	const {
		id,
		email
	} = req.body
	const sql = 'update users set email = ? where id = ?'
	db.query(sql, [email, id], (err, result) => {
		if (err) return res.cc(err)
		res.send({
			status: 0,
			message: '修改成功'
		})
	})
}

Snipaste_2023-11-15_20-43-58.png 数据库

Snipaste_2023-11-15_20-43-46.png

有一些要做输入前校验

Snipaste_2023-11-15_20-55-02.png

Snipaste_2023-11-15_20-54-16.png 错误示例

Snipaste_2023-11-15_20-52-17.png

7. 修改用户密码接口

router/userinfo.js

Snipaste_2023-11-15_21-37-44.png router_handle/userinfo.js

// 7. 修改用户密码接口
 // 先输入旧密码 oldPassword 新密码 newPassword id 
 exports.changePassword = (req, res) => {
	 //通过id寻找旧密码
 	const sql = 'select password from users where id = ?'
 	db.query(sql, req.body.id, (err, result) => {
 		if (err) return res.cc(err)
 		// bcrypt
		//使用加密中间件的compareSync解密方法    hashSync加密方法
		//第一个参数req.body.oldPassword 前端传来的旧密码
		//第二个参数result[0].password 数据库查找到的密码
 		const compareResult = bcrypt.compareSync(req.body.oldPassword, result[0].password)
		//结果不相等
 		if (!compareResult) {
 			return res.send({
 				status: 1,
 				message: '原密码错误'
 			})
 		}
		//操作成功,把新密码做加密
 		req.body.newPassword = bcrypt.hashSync(req.body.newPassword, 10)
		//更新旧密码
 		const sql1 = 'update users set password = ? where id = ?'
 		db.query(sql1, [req.body.newPassword, req.body.id], (err, result) => {
 			if (err) return res.cc(err)
 			res.send({
 				status: 0,
 				message: '修改成功'
 			})
 		})
 	})
 }

8. 验证账户和与邮箱是否一致接口 email account 返回对应id

Snipaste_2023-11-15_21-46-12.png

router_handle/userinfo.js ``

 //忘记密码-------------------------------------------------------------------------------------------根据以下接口找回
exports.verifyAccountAndEmail = (req, res) => {
	const {
		account,
		email
	} = req.body
	//根据账号找邮箱 返回对应ID
	const sql = 'select * from users where account = ?'
	db.query(sql, account, (err, result) => {
		if (err) return res.cc(err)
		// res.send(result[0].email)   返回数据库中的邮箱
		//对比数据库中的邮箱与前端传来的邮箱是否一直
		if (email == result[0].email) {
			res.send({
				status: 0,
				message: '查询成功',
				id: result[0].id
			})
		} else {
			res.send({
				status: 1,
				message: '查询失败'
			})
		}
	})
}
 

9.登录页面修改密码接口 参数 newPassword id

Snipaste_2023-11-15_21-46-20.png

 // 9.登录页面修改密码 参数 newPassword id,在前端完成判断两次密码是否一致
exports.changePasswordInLogin = (req, res) => {
	// req.body.newPassword
	const user = req.body
	//对传来的密码进行加密
	user.newPassword = bcrypt.hashSync(user.newPassword, 10)
	const sql = 'update users set password = ? where id = ?'
	db.query(sql, [user.newPassword, user.id], (err, result) => {
		if (err) return res.cc(err)
		res.send({
			status: 0,
			message: '更新密码成功'
		})
	})
}

调用接口,前端传数据,后端去数据库查是否满足条件

Snipaste_2023-11-15_22-03-03.png 查询成功返回id,进入下一步,把id携带,修改id对应的账号

Snipaste_2023-11-15_22-18-32.png


首页需要的接口

轮播图及公司介绍

...................