nodejs操作数据库
以代码说明操作过程;
服务器server
server.js
const express = require('express');
const {
PORT
} = require('./config.json');
const rootRouter = require('./router');
const path = require('path')
//创建一个服务器
const app = express();
// ./ 是当前目录
// / 是根目录
// 启用静态资源服务器
app.use(express.static(path.join(__dirname, './public'), {
// maxAge:60*60*1000*24
}));
// 数据接口
app.use('/api', rootRouter);
app.listen(PORT, () => {
console.log('server is running on port ' + PORT)
router文件
index.js
// const express = require('express')
// const router = express.Router()
// const user = require('./use')
// const goods = require('./goods')
// // 格式化参数
// router.use(express.urlencoded(), express.json());
// 或者直接解构上面代码
const {
Router,
urlencoded,
json
} = require('express');
// express.json===bodyParse.json, ....
const session = require('express-session')
const token = require('../utils/token');
const router = Router();
const userRouter = require('./user');
const goodsRouter = require('./goods');
const regRouter = require('./reg');
const loginRouter = require('./login');
const vcodeRouter = require('./vcode');
const uploadRouter = require('./upload');
const {
formatData
} = require('../utils/tools');
// 数据格式化中间件
router.use(urlencoded({
extended: false
}), json())
// 使用session会话
// 通过req.session获取存入会话的数据
router.use(session({
// 密钥一致
secret: 'fqniu',
resave: false,
saveUninitialized: true,
cookie: {
// 设置cookie有效期
maxAge: 1000 * 60 * 60 * 2
}
}))
// /api/user
router.use('/user', userRouter);
// /api/goods
router.use('/goods', goodsRouter);
// 注册
router.use('/reg', regRouter);
// 登录
router.use('/login', loginRouter);
// 上传
router.use('/upload', uploadRouter);
// 校验token
router.get('/jwtverify', (req, res) => {
const {
authorization
} = req.query;
console.log('test', authorization)
// verify方法校验成功:得到一个对象
// verify方法校验不通过:直接抛出错误
// try{
// var decoded = jwt.verify(authorization, 'laoxie');
// res.send(formatData())
// }catch(err){
// res.send(formatData({code:0}))
// }
if (token.verify(authorization)) {
res.send(formatData())
} else {
res.send(formatData({
code: 0
}))
}
});
// 验证码
router.use('/vcode', vcodeRouter);
module.exports = router;
goods.js
const express = require('express')
const router = express.Router()
const mongo = require('../utils/mongo')
const {
ObjectId
} = require('mongodb')
// console.log(mongo)
/*
{
insert: [AsyncFunction: insert],
remove: [AsyncFunction: remove],
update: [AsyncFunction: update],
find: [AsyncFunction: find]
}
*/
// 1、get 查询所有商品数据 /api/goods
router.get('/', async (req, res) => {
let {
page = 1, size = 2, sort = 'price'
} = req.query
const skip = (page - 1) * size
const limit = size * 1 //这里*1 是为了转为数值型
// 处理排序参数
sort = sort.split(',') //["price"],["price",'-1]
// 查询所有的商品
const result = await mongo.find('goods', {}, {
skip,
limit,
sort
})
res.send(result)
})
// 2、delete 删除数据 单
router.delete('/:id', async (req, res) => {
const {
id
} = req.params
// console.log(id)
try {
const result = await mongo.remove('goods', {
_id: id
})
res.send('success')
} catch (err) {
res.send('fail')
}
})
// 3、post 增加数据 单或多
router.post('/', async (req, res) => {
const good = req.body
// console.log(good)
try {
const result = await mongo.insert('goods', good)
res.send('success')
} catch (err) {
res.send('fail')
}
})
// 4、put 修改数据 单
router.put('/:id', async (req, res) => {
const {
id
} = req.params
// console.log(req.params)
try {
const result = await mongo.update('goods', {
// 匹配id
_id: ObjectId(id)
}, {
$set: {
price: 200
}
})
res.send('success')
} catch (err) {
res.send('fail')
}
})
module.exports = router
user.js
const express = require('express');
const router = express.Router();
// const query = require('../utils/mysql');
const mongo = require('../utils/mongo');
const {formatData,md5} = require('../utils/tools')
// const mysql = require('mysql');
// 配置数据库
// 第一种:使用连接对象
// var connection = mysql.createConnection({
// host : 'localhost',
// user : 'root',
// password : '',
// database : 'jiaoxue'
// });
// 第二种:使用连接池(推荐)
//创建连接池:默认创建10个连接对象放到连接池中
// var pool = mysql.createPool({
// host : 'localhost',
// user : 'root',
// password : '',
// database: 'jiaoxue',
// multipleStatements: true
// });
router.get('/',async (req,res)=>{
// 读取数据库,获取所有用户
// let sql = `select * from user`;
// 1. 连接mySQL数据库
// connection.connect();
// // 2. 查询所有用户
// connection.query(sql, (error, results, fields) => {
// if (error) throw error;
// console.log('results=', results);
// console.log('fields=', fields);
// res.send(results)
// // 关闭连接,释放资源
// connection.end();
// })
// pool.query(sql, (error, results, fields) => {
// if (error) throw error;
// console.log('results=', results);
// console.log('fields=', fields);
// res.send(results)
// })
// query(sql,function(result){
// res.send(reusult)
// })
// const result = await query(sql); // 等效于query(sql).then(result=>{})
// mongo
const result = await mongo.find('user')
res.send(formatData({data:result}));
})
router.delete('/:id',async (req,res)=>{
const {id} = req.params;
// let sql = `delete from user where id=${id}`;
// connection.connect();
// connection.query(sql, (error, results, fields) => {
// if (error) throw error;
// res.send('删除成功')
// connection.end()
// })
// pool.query(sql, (error, results, fields) => {
// if (error) throw error;
// res.send('删除成功')
// })
// try{
// // 尝试执行这里的代码
// const result = await query(sql);
// res.send(result)
// }catch(err){
// // 如果上面的代码有报错,则执行这里的代码
// res.send('删除失败')
// }
try{
await mongo.remove('user',{_id:id});
res.send(formatData())
}catch(err){
res.send(formatData({code:0}))
}
})
// 获取单个用户信息
router.get('/:id',async(req,res)=>{
const {id} = req.params;console.log('id=',id)
const result = await mongo.find('user',{_id:id});
console.log(result)
res.send(formatData({data:result[0]}));
})
// 修改单个用户信息
router.put('/:id',async (req,res)=>{
const {id} = req.params;
let {password,age,gender} = req.body;
console.log()
let newData = {age,gender}
if(password){
password = md5(password);
newData.password = password
}
try{
await mongo.update('user',{_id:id},{$set:newData});
res.send(formatData({data:{_id:id,...newData}}))
}catch(err){
// console.log('err=',err);
res.send(formatData({code:0}))
}
})
module.exports = router;
reg.js
const express = require('express');
const router = express.Router();
const {formatData,md5} = require('../utils/tools');
const mongo = require('../utils/mongo');
// RESTful api规范
// 注册
router.post('/',async (req,res)=>{
let {username,password} = req.body;
console.log('password1=',password)
// 引用模块里面的函数
password = md5(password)
let result
try{
result = await mongo.insert('user',{username,password});
res.send(formatData());
}catch(err){
res.send(forMatData({code:0}))
}
})
// 检查是否用户名重复
router.get('/check',async (req,res)=>{
const {username} = req.query;
const result = await mongo.find('user',{username});
if(result.length>0){
res.send(formatData({code:0}))
}else{
res.send(formatData())
}
})
module.exports = router;
login.js
const express = require('express');
const router = express.Router();
// 引入 封装的 token 模块
const token = require('../utils/token');
const { formatData,md5 } = require('../utils/tools');
const mongo = require('../utils/mongo');
// 登录
router.get('/', async (req, res) => {
let { username, password, vcode, mdl } = req.query;
// 其中vcode是前端输入的验证码
// 从会话中获取验证码
// 校验验证码 这里的req.session 是已经存有vcode的 Session 对象
console.log('login.session=', req.session)
// vcode 是前端输入验证码之后,传过来的参数
// 而 req.session.vcode 是Session中的存的 vcode
if (vcode !== req.session.vcode) {
res.send(formatData({ code: 10 }))
return;
}
// 加密后进行查询
password = md5(password)
let result = await mongo.find('user', { username, password }); //[{}]
// 判断如果 find 找到 有result, 则返回这个数组数据
// 如果find 找不到 ,则result为 空数组
if (result.length > 0) {
// 用户名、密码、验证码都校验通过后,判断是否有免登陆选项
console.log('req.query=', req.query);
let authorization;
if (mdl === 'true') {
// token的操作
// 1. 生成token
// const token = jwt.sign({ username }, 'laoxie' ,{
// // token有效期
// expiresIn: 20//1000 * 60 * 60 * 24 * 7
// });
authorization = token.create({ username }, '7d')
}else{
authorization = token.create({ username })
}
console.log('token=', authorization);
result = result[0];
result.authorization = authorization
res.send(formatData({ data: result }));
} else {
res.send(formatData({ code: 0 }))
}
})
module.exports = router;
vcode.js
验证码制作模块
const express = require('express')
const router = express.Router()
// 导入验证码制作模块
const svgCaptcha = require('svg-captcha')
const {
formatData
} = require('../utils/tools')
// 生成验证码
router.get('/', async (req, res) => {
// 生成图像验证码:svg-captcha 参数
const options = {
noise: 3,
ignoreChars: '0o1il',
background: '#58BC58',
color: true,
fontSize: 50,
height: 38
}
// 验证码生成 create
const captcha = svgCaptcha.create(options)
// console.log(captcha)
// captcha 生成的返回值是 : {text:'abcd',data: '<svg />'}
// console.log(captcha.text)
// 页面刷新就生成一个验证码
// 先打印 查看是否有 session , 打印值:Session { cookie:{} }
// console.log('login.session=', req.session)
// 把验证码存入会话 Session 对象中
req.session.vcode = captcha.text.toLocaleLowerCase()
// 再打印查看是否存入验证码 , 打印值:Session { cookie:{}, vcode:'xxxx' }
// console.log('vcode.session=', req.session)
// 把data 中的 svg 传给前端 渲染 验证码 结构样式
res.send(formatData({
data: captcha.data
}))
})
module.exports = router
upload.js
const express = require('express');
const router = express.Router();
const multer = require('multer');
const path = require('path');
const mongo = require('../utils/mongo');
const { formatData, md5 } = require('../utils/tools')
// 配置上传参数
let storage = multer.diskStorage({
// destination: function (req, file, cb) {
// cb(null, './uploads/');
// },
// 上传文件保存目录,无则自动创建
destination: path.join(__dirname, '../public/uploads/'),
// 格式化文件名:字段名+时间戳+扩展名
// avatar-1597202347355.jpg
filename: function (req, file, cb) {
// 获取文件后缀名
let ext = path.extname(file.originalname);
cb(null, file.fieldname + '-' + Date.now() + ext);
}
})
// 设置中间件
const uploadMiddleware = multer({ storage });
// post /api/upload/avatar
router.post('/avatar', uploadMiddleware.single('avatar'), (req, res) => {
// 中间件会把图片信息格式化到req.file,req.files
console.log('file=', req.file, req.body);
const { _id } = req.body;
// 更新用户信息
const avatarUrl = '/uploads/' + req.file.filename
mongo.update('user', { _id }, { $set: { avatarUrl } })
res.send(formatData({ data: { _id, avatarUrl } }));
})
// 一次性最多传5张图片
router.post('/goods', uploadMiddleware.array('goods', 5), (req, res) => {
})
module.exports = router;
utils文件
mongo.js
/**
*
* mongodb 操作封装
*
*/
// 官网写法如下:
// const MongoClient = require('mongodb').MongoClient;
// // Connection URL
// const url = 'mongodb://localhost:27017';
// // Database Name
// const dbName = 'user';
// // Use connect method to connect to the server
// MongoClient.connect(url, function (err, client) {
// console.log("Connected successfully to server");
// const db = client.db(dbName);
// client.close();
// });
// 引入mongodb模块 并结构需要用到的方法,源码中在lib/bulk/common.js
const {
MongoClient,
ObjectId
} = require('mongodb')
// mongodb 数据库地址
const url = 'mongodb://localhost:27017'
// 数据库名称
const dbName = 'user'
async function connect(){
// return new Promise((resolve,reject)=>{
// MongoClient.connect(url, function (err, client) {
// // client: mongo客户端
// if(err){
// reject(err);
// }
// // 匹配数据库
// const db = client.db(dbName);
// // 导出db和client
// resolve({db,client})
// // 数据库操作
// // 数据库操作完成后关闭连接,释放资源
// // client.close();
// });
// })
const client = await MongoClient.connect(url);
const db = client.db(dbName);
return {client,db}
}
// 增
async function insert(colName,data){
// 1. 连接数据库
const {db,client} = await connect();
// 2. 添加数据
// 根据传入的集合名称获取数据库中的某个集合
const collection = db.collection(colName);
// if(Array.isArray(data)){
// collection.insertMany(data); // collection['inserMany']
// }else{
// collection.insertOne(data)
// }
const result = await collection[Array.isArray(data) ? 'insertMany':'insertOne'](data)
// 3. 关闭连接
client.close()
return result;
}
// 删
async function remove(colName,query){ // query{_id:'5c128cdbd1233ce12c878a32'}
const {db,client} = await connect();
if(query._id && typeof query._id === 'string'){
query._id = ObjectId(query._id);
}
const collection = db.collection(colName);
const result = await collection.deleteMany(query);
client.close();
return result;
}
// 改
async function update(colName,query,newData){ // newData{$set:{price:200,qty:2},$inc:{view:1}}
const {db,client} = await connect();
const collection = db.collection(colName);
if(query._id && typeof query._id === 'string'){
query._id = ObjectId(query._id);
}
const result = await collection.updateMany(query,newData);
return result;
}
// 查
async function find(colName,query={},options={}){ // options={litmit:10,skip:0}
const {client,db} = await connect();
const collection = db.collection(colName);
if(query._id && typeof query._id === 'string'){
query._id = ObjectId(query._id);
}
// 查询到数据集合
let result = collection.find(query); // 50->10
// 判断是否要跳过记录
if(options.skip){
result = result.skip(options.skip)
}
if(options.limit){
result = result.limit(options.limit);
}
// 排序
console.log('sort',options.sort);
if(options.sort){ //['price'],['price','1']
let key,val;
key = options.sort[0];
if(options.sort.length>1){
val = options.sort[1]*1;
}else{
val = -1;
}
result = result.sort({
[key]:val
})
}
result = await result.toArray();
client.close();
return result
}
module.exports = {
insert,
remove,
update,
find
}
mysql.js
/**
*
* 封装mysql数据库操作的方法
*
*/
const mysql = require('mysql')
var pool = mysql.createPool({
host: 'localhost',
user: 'root',
password: 'nfq123456',
database: 'udata',
multipleStatements: true
})
// // 第一种:回调函数 实现数据传递
// function query(sql, callback) {
// pool.query(sql, (err, results, fields) => {
// if (err) throw err
// callback(results)
// })
// }
// 第二种:promise
function query(sql) {
return new Promise((resolve, reject) => {
pool.query(sql, (err, results, fields) => {
if (err) {
reject(err)
}
resolve(results)
})
})
}
module.exports = query
tools.js
const crypto = require('crypto');
// 参数有三个 code 判断输入结果 默认是 success
function formatData({code=1,data=[],msg='success'}={}){
if(code === 0){
msg = 'fail';
}
return {
code,
data,
msg
}
}
// 封装的加密函数
function md5(data,privateKey='laoxie'){
const hash = crypto.createHash('md5');
hash.update(data+privateKey); // 加盐 盐值
const result = hash.digest('hex');
return result;
}
module.exports = {
formatData,
md5
}
token.js
const jwt = require('jsonwebtoken');
const privateKey = 'fqniu';
function create(data = {}, expiresIn = '2h') {
const token = jwt.sign({
...data
}, privateKey, {
// token有效期
expiresIn
});
return token;
}
function verify(token) {
let result;
try {
jwt.verify(token, privateKey);
result = true;
} catch (err) {
result = false
}
return result;
}
module.exports = {
create,
verify
}
public文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
</head>
<body>
<h1>后台管理系统</h1>
<script>
(async () => {
// 获取 localStorage 的值
const authorization = localStorage.getItem('authorization')
// console.log('auth=', authorization)
if (authorization) {
// 校验 token 的有效性
const result = await fetch(`http://localhost:3000/api/jwtverify?authorization=${authorization}`).then(res => res.json())
// console.log(result)
if (result.code === 0) {
localStorage.removeItem('authorization')
location.href = "../login.html"
}
}
})()
</script>
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录</title>
<link rel="stylesheet" href="./assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="reg container-fluid">
<h1>登录获取更多...</h1>
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" class="form-control" id="username" aria-describedby="emailHelp">
<div class="invalid-feedback">
用户或密码错误
</div>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password">
<div class="invalid-feedback">
用户或密码错误
</div>
</div>
<div class="form-group">
<label for="vcode">验证码</label>
<div class="input-group">
<input type="text" class="form-control" id="vcode">
<div class="input-group-append">
<span class="input-group-text" id="svgVcode" style="padding:0">Ad2b</span>
</div>
<div class="invalid-feedback">
验证码错误
</div>
</div>
</div>
<div class="form-group">
<label for="freeLogin">
<input type="checkbox" id="freeLogin" checked>
7天免登陆
</label>
</div>
<button type="submit" class="btn btn-primary btnLogin">登录</button>
</div>
<script>
const username = document.querySelector('#username');
const password = document.querySelector('#password');
const btnLogin = document.querySelector('.btnLogin');
const svgVcode = document.querySelector('#svgVcode')
const vcode = document.querySelector('#vcode')
// 判断用户是否已经登录
const authorization = localStorage.getItem('authorization')
// 如果存在这个authorization 则处于当前页面,否则返回登录页面 超时也一样
if (authorization) {
location.href = 'manage/index.html'
}
// 获取图形验证码
async function getVcode() {
const result = await fetch(`http://localhost:3000/api/vcode?`).then(res => res.json())
//
if (result.code === 1) {
svgVcode.innerHTML = result.data
}
}
getVcode()
// 点击刷新验证码
svgVcode.onclick = getVcode
// 点击发送 登录 请求
btnLogin.onclick = async () => {
const _username = username.value
const _password = password.value
const _vcode = vcode.value
const _freeLogin = freeLogin.checked
// console.log(_vcode)
const result = await fetch(`http://localhost:3000/api/login?username=${_username}&password=${_password}&vcode=${_vcode}&freeLogin=${_freeLogin}`,
{
// 这里的是get请求,可以不用写 fetch请求默认是 get 请求
method: 'get'
// 这里用res.json() 是为了前后端统一传递接口数据格式
}).then(res => res.json())
console.log(result)
if (result.code === 0) {
username.className = password.className = 'form-control is-invalid'
} else if (result.code === 10) {
// 验证码错误的判定
vcode.className = 'form-control is-invalid';
} else {
// 登录成功
// alert('登录成功')
location.href = './manage/index.html'
localStorage.setItem('authorization', result.data)
}
}
</script>
</body>
</html>
reg.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>注册</title>
<link rel="stylesheet" href="./assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="reg container-fluid">
<h1>免费注册</h1>
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" class="form-control" id="username" aria-describedby="emailHelp">
<div class="invalid-feedback">
用户名已存在
</div>
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password">
</div>
<button type="submit" class="btn btn-primary btnReg">注册</button>
</div>
<script>
const username = document.querySelector('#username');
const password = document.querySelector('#password');
const btnReg = document.querySelector('.btnReg');
let canReg = true;
btnReg.onclick = async (e) => {
if (!canReg) return;
const result = await fetch(`http://localhost:3000/api/reg`, {
method: 'post',
body: JSON.stringify({
username: username.value,
password: password.value
}),
headers: {
'Content-Type': 'application/json'
}
// 这里用res.json() 是为了前后端统一传递接口数据格式
}).then(res => res.json());
console.log('result=', result);
if (result.code === 1) {
location.href = 'login.html'
}
}
// 查询用户是否被占用
username.onblur = async () => {
// 判断如果为空 则不发送请求
const _username = username.value.trim()
if (!_username) return
const result = await fetch(`http://localhost:3000/api/reg/check?username=${username.value}`, {
headers: {
'Content-Type': 'application/json'
}
// 这里用res.json() 是为了前后端统一传递接口数据格式
}).then(res => res.json());
console.log('result=', result);
if (result.code === 0) {
username.className = 'form-control is-invalid'
canReg = false;
} else if (result.code === 1) {
username.className = 'form-control is-valid'
canReg = true;
}
}
</script>
</body>
</html>
manage文件夹
goods.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="container-xl">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="index.html">后台管理系统</a>
<!-- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- <ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul> -->
</div>
<div class="navbar-text ml-5">
<span id="userInfo" class="mr-2"></span>
<button class="btn btn-success btn-sm" id="btnLogout">退出</button>
</div>
</nav>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">首页</a></li>
<li class="breadcrumb-item"><a href="#">商品管理</a></li>
<li class="breadcrumb-item active" aria-current="page">添加</li>
</ol>
</nav>
<div class="row">
<!-- <div class="col col-xs-12 col-sm-4 col-lg-3"> -->
<div style="width:200px">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action"><a href="user.html">用户管理</a></li>
<li class="list-group-item list-group-item-action"><a href="goods.html">商品管理</a></li>
<li class="list-group-item list-group-item-action"><a href="order.html">订单管理</a></li>
</ul>
</div>
<!-- <div class="col col-xs-12 col-sm-8 col-lg-9"> -->
<div class="col col-auto">
商品管理
</div>
</div>
</div>
<script src="../js/common.js"></script>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="container-xl">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="index.html">后台管理系统</a>
<!-- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- <ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul> -->
</div>
<div class="navbar-text ml-5">
<span id="userInfo" class="mr-2"></span>
<button class="btn btn-success btn-sm" id="btnLogout">退出</button>
</div>
</nav>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">首页</a></li>
<li class="breadcrumb-item"><a href="#">商品管理</a></li>
<li class="breadcrumb-item active" aria-current="page">添加</li>
</ol>
</nav>
<div class="row">
<!-- <div class="col col-xs-12 col-sm-4 col-lg-3"> -->
<div style="width:200px">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action"><a href="user.html">用户管理</a></li>
<li class="list-group-item list-group-item-action"><a href="goods.html">商品管理</a></li>
<li class="list-group-item list-group-item-action"><a href="order.html">订单管理</a></li>
</ul>
</div>
<!-- <div class="col col-xs-12 col-sm-8 col-lg-9"> -->
<div class="col col-auto">
One of three columns
</div>
</div>
</div>
<script src="../js/common.js"></script>
<script>
</script>
</body>
</html>
order.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="container-xl">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="#">后台管理系统</a>
<!-- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- <ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul> -->
</div>
<div class="navbar-text ml-5">
<span id="userInfo" class="mr-2"></span>
<button class="btn btn-success btn-sm" id="btnLogout">退出</button>
</div>
</nav>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">首页</a></li>
<li class="breadcrumb-item"><a href="#">商品管理</a></li>
<li class="breadcrumb-item active" aria-current="page">添加</li>
</ol>
</nav>
<div class="row">
<!-- <div class="col col-xs-12 col-sm-4 col-lg-3"> -->
<div style="width:200px">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action"><a href="user.html">用户管理</a></li>
<li class="list-group-item list-group-item-action"><a href="goods.html">商品管理</a></li>
<li class="list-group-item list-group-item-action"><a href="order.html">订单管理</a></li>
</ul>
</div>
<!-- <div class="col col-xs-12 col-sm-8 col-lg-9"> -->
<div class="col col-auto">
订单管理
</div>
</div>
</div>
<script src="../js/common.js"></script>
</body>
</html>
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="../assets/bootstrap/css/bootstrap.css">
</head>
<body>
<div class="container-xl">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="index.html">后台管理系统</a>
<!-- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- <ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul> -->
</div>
<div class="navbar-text ml-5">
<span id="userInfo" class="mr-2"></span>
<button class="btn btn-success btn-sm" id="btnLogout">退出</button>
</div>
</nav>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">首页</a></li>
<li class="breadcrumb-item"><a href="#">商品管理</a></li>
<li class="breadcrumb-item active" aria-current="page">添加</li>
</ol>
</nav>
<div class="row">
<!-- <div class="col col-xs-12 col-sm-4 col-lg-3"> -->
<div class="col-sm-3" style="min-width:200px">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action"><a href="user.html">用户管理</a></li>
<li class="list-group-item list-group-item-action"><a href="goods.html">商品管理</a></li>
<li class="list-group-item list-group-item-action"><a href="order.html">订单管理</a></li>
</ul>
</div>
<!-- <div class="col col-xs-12 col-sm-8 col-lg-9"> -->
<div class="col col-sm-9">
<table class="table table-striped table-hover" style="width:100%">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">用户名</th>
<th scope="col">年龄</th>
<th scope="col">性别</th>
<th scope="col">操作</th>
</tr>
</thead>
<tbody id="userlist">
</tbody>
</table>
</div>
</div>
</div>
<script src="../js/common.js"></script>
<script src="../js/tools.js"></script>
<script>
(async () => {
const userlist = document.querySelector("#userlist");
let datalist = await request('/user');
datalist = datalist.data;
render();
function render(){
userlist.innerHTML = datalist.map((item, idx) => {
return `<tr>
<td>${idx + 1}</td>
<td>${item.username}</td>
<td>${item.age===undefined ? 18:item.age}</td>
<td>${item.gender ? item.gender : '未知'}</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-success btnEdit" data-id="${item._id}">编辑</button>
<button class="btn btn-danger btnDel" data-id="${item._id}">删除</button>
</div>
</td>
</tr>`
}).join('')
}
// 删除功能
userlist.onclick = async (e)=>{
const target = e.target;
const {id} = target.dataset
if(target.classList.contains('btnDel')){
if(confirm('are you 确定')){
// 删除
// const result = await request('/user/'+id,{},{method:'delete'});
const result = await request.delete('/user/'+id)
if(result.code === 1){
// [{id:1},{id:2},{id:3}] , 2 => [{id:2},{id:3}]
datalist = datalist.filter(item=>item._id !== id);
render();
}
}
}else if(target.classList.contains('btnEdit')){
// 编辑
// const result = await request('/user/'+id,{age:28,gender:'男'},{method:'put'});
location.href="./user/edit.html?id="+id
}
}
})();
</script>
</body>
</html>
user文件下edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理系统</title>
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.css">
<style>
#avatar {
width: 100%;
}
</style>
</head>
<body>
<div class="container-xl">
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<a class="navbar-brand" href="../index.html">后台管理系统</a>
<!-- <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button> -->
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<!-- <ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul> -->
</div>
<div class="navbar-text ml-5">
<span id="userInfo" class="mr-2"></span>
<button class="btn btn-success btn-sm" id="btnLogout">退出</button>
</div>
</nav>
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">首页</a></li>
<li class="breadcrumb-item"><a href="#">商品管理</a></li>
<li class="breadcrumb-item active" aria-current="page">添加</li>
</ol>
</nav>
<div class="row">
<!-- <div class="col col-xs-12 col-sm-4 col-lg-3"> -->
<div class="col-sm-3" style="min-width:200px">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-action"><a href="../user.html">用户管理</a></li>
<li class="list-group-item list-group-item-action"><a href="../goods.html">商品管理</a></li>
<li class="list-group-item list-group-item-action"><a href="../order.html">订单管理</a></li>
</ul>
</div>
<!-- <div class="col col-xs-12 col-sm-8 col-lg-9"> -->
<div class="col col-sm-9">
<div class="row">
<div class="col col-sm-9">
<div class="form-group">
<label for="username">用户名:</label>
<input type="text" class="form-control" id="username" disabled>
</div>
<div class="form-group">
<label for="password">密码:</label>
<input type="password" class="form-control" id="password">
</div>
<div class="form-group">
<label for="gender">性别</label>
<select class="form-control" id="gender">
<option>男</option>
<option>女</option>
<option>其他</option>
</select>
</div>
<div class="form-group">
<label for="age">年龄</label>
<input type="number" id="age" class="form-control">
</div>
<button type="submit" class="btn btn-success btn-lg mb-2" id="btnSubmit">提交</button>
</div>
<div class="col col-sm-3">
<img src="/img/g3.jpg" id="avatar" />
<!-- <from enctype="multipart/form-data" method="post" action="http://localhost:2003/api/upload/avatar"> -->
<input type="file" class="form-control-file" id="uploadAvatar">
<!-- </from> -->
</div>
</div>
</div>
</div>
</div>
<script src="/js/common.js"></script>
<script src="/js/tools.js"></script>
<script>
(async () => {
const username = document.querySelector('#username')
const password = document.querySelector('#password')
const gender = document.querySelector('#gender')
const age = document.querySelector('#age')
const btnSubmit = document.querySelector('#btnSubmit')
const uploadAvatar = document.querySelector('#uploadAvatar')
// 获取当前用户信息
let currentUser = localStorage.getItem('currentUser');
currentUser = JSON.parse(currentUser);
// 通过用户id获取用户信息
// let _id;
// let params = location.search.slice(1);
// params = params.split('&');
// params.forEach(item=>{
// const arr = item.split('=')
// if(item[0] === 'id'){
// _id = arr[1];
// }
// });
let _id = location.search.match(/id=([\da-z]{24})/)[1];
console.log(_id);
const { data } = await request.get('/user/' + _id);
// 把数据写入表单
username.value = data.username
// password.value = data.password
gender.value = data.gender
age.value = data.age
avatar.src = data.avatarUrl || '/uploads/avatar.jpg'
btnSubmit.onclick = async () => {
const result = await request.put('/user/' + data._id, {
password: password.value,
gender: gender.value,
age: age.value
});
if (result.code === 1) {
alert('更新成功')
// 如果修改的用为为自己
if (_id === currentUser._id) {
Object.assign(currentUser, result.data);
localStorage.setItem('currentUser', JSON.stringify(currentUser));
}
} else {
alert('更新失败')
}
}
// 上传头像
uploadAvatar.onchange = async (e) => {
// html5新特性:FormData
console.log(e);
// 创建一个用户存放数据的容器
const data = new FormData();
data.set('_id', _id);
data.set('avatar', e.target.files[0]);
// 一次性上传多张图片时
// for(let i=0;i<e.target.files.length;i++){
// data.append('goods',e.target.files[i]);
// }
const result = await request.post('/upload/avatar', data, {
contentType: false, // 告诉fetch,不需要自定义content-type
// headers:{
// 'Content-Type':'multipart/form-data'
// }
});
// 更新页面
avatar.src = result.data.avatarUrl;
// 更新本地存储数据
if (_id === currentUser._id) {
currentUser.avatarUrl = result.data.avatarUrl;
localStorage.setItem('currentUser', JSON.stringify(currentUser));
}
}
})();
</script>
</body>
</html>
upload文件放上传的头像
assets文件
bootstrap文件的 css 和 js 文件
package
package.json
{
"name": "mymongodb",
"version": "1.0.0",
"description": "",
"main": "index.js",
"directories": {
"doc": "doc"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"server": "supervisor src/server.js",
"start": "npm run server"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "^4.5.2",
"express": "^4.17.1",
"express-session": "^1.17.1",
"jsonwebtoken": "^8.5.1",
"mongodb": "^3.6.0",
"multer": "^1.4.2",
"mysql": "^2.18.1",
"svg-captcha": "^1.4.0"
}
}
config.json
{
"PORT":3000
}
文件目录
功能说明:
1、登录注册
- 注册 如果勾选7天免登陆,实现7天不用登录用户名和密码
- 注册如果不勾选7天免登陆,默认是2小时内
2、进入后台管理系统,显示登录用户名
3、点击用户管理 ,可以对里面的用户修改密码、年龄、性别、上传头像
4、实现不同管理的跳转页面
5、退出登录