Node后台管理系统服务器搭建

Node后台管理系统服务器搭建

前言

使用express框架结合mongoose搭建后台管理系统服务器。

一、中间件


// server.js

// 声明使用静态中间件
app.use(express.static('public'))
// 声明使用解析post请求的中间件
// 可以使用urlencoded方式来解析表单数据  extended: true  ==>  表示使用第三方模块qs来处理
app.use(express.urlencoded({
    
     extended: true })) // 请求体参数是: name=tom&pwd=123
// 可以使用json格式来处理表单数据
app.use(express.json()) // 请求体参数是json结构: {name: tom, pwd: 123}
// 声明使用解析cookie数据的中间件
const cookieParser = require('cookie-parser')
app.use(cookieParser())
// 声明使用路由器中间件
const indexRouter = require('./routers')
app.use('/', indexRouter) //
  • 当连接到数据库后再启动服务器
// 通过mongoose连接数据库
mongoose.connect('mongodb://localhost/server_db2', {
    
     useNewUrlParser: true })
    .then(() => {
    
    
        console.log('连接数据库成功!!!')
            // 只有当连接上数据库后才去启动服务器
        app.listen('5000', () => {
    
    
            console.log('服务器启动成功, 请访问: http://localhost:5000')
        })
    })
    .catch(error => {
    
    
        console.error('连接数据库失败', error)
    })

二、路由配置

routers/index.js

1.配置路由对象

const router = express.Router()

2.登录

// 登陆
router.post('/login', (req, res) => {
    
    
  const {
    
    username, password} = req.body
  // 根据username和password查询数据库users, 如果没有, 返回提示错误的信息, 如果有, 返回登陆成功信息(包含user)
  UserModel.findOne({
    
    username, password: md5(password)})
    .then(user => {
    
    
      if (user) {
    
     // 登陆成功
        // 生成一个cookie(userid: user._id), 并交给浏览器保存
        res.cookie('userid', user._id, {
    
    maxAge: 1000 * 60 * 60 * 24})
        if (user.role_id) {
    
    
          RoleModel.findOne({
    
    _id: user.role_id})
            .then(role => {
    
    
              user._doc.role = role
              console.log('role user', user)
              res.send({
    
    status: 0, data: user})
            })
        } else {
    
    
          user._doc.role = {
    
    menus: []}
          // 返回登陆成功信息(包含user)
          res.send({
    
    status: 0, data: user})
        }

      } else {
    
    // 登陆失败
        res.send({
    
    status: 1, msg: '用户名或密码不正确!'})
      }
    })
    .catch(error => {
    
    
      console.error('登陆异常', error)
      res.send({
    
    status: 1, msg: '登陆异常, 请重新尝试'})
    })
})

3.添加用户

router.post('/manage/user/add', (req, res) => {
    
    
  // 读取请求参数数据
  const {
    
    username, password} = req.body
  // 处理: 判断用户是否已经存在, 如果存在, 返回提示错误的信息, 如果不存在, 保存
  // 查询(根据username)
  UserModel.findOne({
    
    username})
    .then(user => {
    
    
      // 如果user有值(已存在)
      if (user) {
    
    
        // 返回提示错误的信息
        res.send({
    
    status: 1, msg: '此用户已存在'})
        return new Promise(() => {
    
    
        })
      } else {
    
     // 没值(不存在)
        // 保存
        return UserModel.create({
    
    ...req.body, password: md5(password || 'atguigu')})
      }
    })
    .then(user => {
    
    
      // 返回包含user的json数据
      res.send({
    
    status: 0, data: user})
    })
    .catch(error => {
    
    
      console.error('注册异常', error)
      res.send({
    
    status: 1, msg: '添加用户异常, 请重新尝试'})
    })
})

4.添加角色

// 添加角色
router.post('/manage/role/add', (req, res) => {
    
    
  const {
    
    roleName} = req.body
  RoleModel.create({
    
    name: roleName})
    .then(role => {
    
    
      res.send({
    
    status: 0, data: role})
    })
    .catch(error => {
    
    
      console.error('添加角色异常', error)
      res.send({
    
    status: 1, msg: '添加角色异常, 请重新尝试'})
    })
})

5.获取产品分页列表

// 获取产品分页列表
router.get('/manage/product/list', (req, res) => {
    
    
  const {
    
    pageNum, pageSize} = req.query
  ProductModel.find({
    
    })
    .then(products => {
    
    
      res.send({
    
    status: 0, data: pageFilter(products, pageNum, pageSize)})
    })
    .catch(error => {
    
    
      console.error('获取商品列表异常', error)
      res.send({
    
    status: 1, msg: '获取商品列表异常, 请重新尝试'})
    })
})

6.获取所有用户列表

// 获取所有用户列表
router.get('/manage/user/list', (req, res) => {
    
    
  UserModel.find({
    
    username: {
    
    '$ne': 'admin'}})
    .then(users => {
    
    
      RoleModel.find().then(roles => {
    
    
        res.send({
    
    status: 0, data: {
    
    users, roles}})
      })
    })
    .catch(error => {
    
    
      console.error('获取用户列表异常', error)
      res.send({
    
    status: 1, msg: '获取用户列表异常, 请重新尝试'})
    })
})

7.添加分类

// 添加分类
router.post('/manage/category/add', (req, res) => {
    
    
  const {
    
    categoryName, parentId} = req.body
  CategoryModel.create({
    
    name: categoryName, parentId: parentId || '0'})
    .then(category => {
    
    
      res.send({
    
    status: 0, data: category})
    })
    .catch(error => {
    
    
      console.error('添加分类异常', error)
      res.send({
    
    status: 1, msg: '添加分类异常, 请重新尝试'})
    })
})

8.分页

/*
得到指定数组的分页信息对象
 */
function pageFilter(arr, pageNum, pageSize) {
    
    
  pageNum = pageNum * 1
  pageSize = pageSize * 1
  const total = arr.length
  const pages = Math.floor((total + pageSize - 1) / pageSize)
  const start = pageSize * (pageNum - 1)
  const end = start + pageSize <= total ? start + pageSize : total
  const list = []
  for (var i = start; i < end; i++) {
    
    
    list.push(arr[i])
  }

  return {
    
    
    pageNum,
    total,
    pages,
    pageSize,
    list
  }
}

7.处理上传文件的路由

使用中间件multer来处理上传图片

  1. 创建storage配置对象
const upload = multer({
    
    storage})
  1. 创建上传图片的函数
const uploadSingle = upload.single('image')
/*
处理文件上传的路由
 */
const multer = require('multer')
const path = require('path')
const fs = require('fs')

const dirPath = path.join(__dirname, '..', 'public/upload')

const storage = multer.diskStorage({
    
    
  // destination: 'upload', //string时,服务启动将会自动创建文件夹
  destination: function (req, file, cb) {
    
     //函数需手动创建文件夹
    // console.log('destination()', file)
    if (!fs.existsSync(dirPath)) {
    
    
      fs.mkdir(dirPath, function (err) {
    
    
        if (err) {
    
    
          console.log(err)
        } else {
    
    
          cb(null, dirPath)
        }
      })
    } else {
    
    
      cb(null, dirPath)
    }
  },
  filename: function (req, file, cb) {
    
    
    // console.log('filename()', file)
    var ext = path.extname(file.originalname)
    cb(null, file.fieldname + '-' + Date.now() + ext)
  }
})
const upload = multer({
    
    storage})
const uploadSingle = upload.single('image')

module.exports = function fileUpload(router) {
    
    

  // 上传图片
  router.post('/manage/img/upload', (req, res) => {
    
    
    uploadSingle(req, res, function (err) {
    
     //错误处理
      if (err) {
    
    
        return res.send({
    
    
          status: 1,
          msg: '上传文件失败'
        })
      }
      var file = req.file
      res.send({
    
    
        status: 0,
        data: {
    
    
          name: file.filename,
          url: 'http://localhost:5000/upload/' + file.filename
        }
      })

    })
  })

  // 删除图片
  router.post('/manage/img/delete', (req, res) => {
    
    
    const {
    
    name} = req.body
    fs.unlink(path.join(dirPath, name), (err) => {
    
    
      if (err) {
    
    
        console.log(err)
        res.send({
    
    
          status: 1,
          msg: '删除文件失败'
        })
      } else {
    
    
        res.send({
    
    
          status: 0
        })
      }
    })
  })
}

三、MongoDB数据库模块配置

在这里插入图片描述
mysql采用table和结构化的sql语句来处理数据,在mysql中需要预先定义数据结构schema,并定义table中数据字段的关系。

mongoDB采用类JSON的documents来存储数据。

1.UserModel

  1. 定义Schema(描述文档结构)
const roleSchema = new mongoose.Schema({
    
    
  name: {
    
    type: String, required: true}, // 角色名称
  auth_name: String, // 授权人
  auth_time: Number, // 授权时间
  create_time: {
    
    type: Number, default: Date.now}, // 创建时间
  menus: Array // 所有有权限操作的菜单path的数组
})
  1. 定义Model(与集合对应, 可以操作集合)
const UserModel = mongoose.model('users', userSchema)
  1. 初始化默认超级管理员用户: admin/admin
UserModel.findOne({
    
    username: 'admin'}).then(user => {
    
    
  if(!user) {
    
    
    UserModel.create({
    
    username: 'admin', password: md5('admin')})
            .then(user => {
    
    
              console.log('初始化用户: 用户名: admin 密码为: admin')
            })
  }
})

2.RoleModle

// 1.引入mongoose
const mongoose = require('mongoose')

// 2.字义Schema(描述文档结构)
const roleSchema = new mongoose.Schema({
    
    
  name: {
    
    type: String, required: true}, // 角色名称
  auth_name: String, // 授权人
  auth_time: Number, // 授权时间
  create_time: {
    
    type: Number, default: Date.now}, // 创建时间
  menus: Array // 所有有权限操作的菜单path的数组
})

// 3. 定义Model(与集合对应, 可以操作集合)
const RoleModel = mongoose.model('roles', roleSchema)

// 4. 向外暴露Model
module.exports = RoleModel

3.ProductModel

// 1.引入mongoose
const mongoose = require('mongoose')

// 2.字义Schema(描述文档结构)
const productSchema = new mongoose.Schema({
    
    
  categoryId: {
    
    type: String, required: true}, // 所属分类的id
  pCategoryId: {
    
    type: String, required: true}, // 所属分类的父分类id
  name: {
    
    type: String, required: true}, // 名称
  price: {
    
    type: Number, required: true}, // 价格
  desc: {
    
    type: String},
  status: {
    
    type: Number, default: 1}, // 商品状态: 1:在售, 2: 下架了
  imgs: {
    
    type: Array, default: []}, // n个图片文件名的json字符串
  detail: {
    
    type: String}
})


// 3. 定义Model(与集合对应, 可以操作集合)
const ProductModel = mongoose.model('products', productSchema)

// 4. 向外暴露Model
module.exports = ProductModel

4.CategoryModel

// 1.引入mongoose
const mongoose = require('mongoose')

// 2.字义Schema(描述文档结构)
const categorySchema = new mongoose.Schema({
    
    
  name: {
    
    type: String, required: true},
  parentId: {
    
    type: String, required: true, default: '0'}
})

// 3. 定义Model(与集合对应, 可以操作集合)
const CategoryModel = mongoose.model('categorys', categorySchema)

// 4. 向外暴露Model
module.exports = CategoryModel

解决前端BrowserRouter问题

该APP使用前端路由,因此当访问服务器时,服务器中没有响应路由就会报404错误。
解决办法:当服务器没有相对应的路由时,就返回index.html让前端进行路由匹配。

app.use((req, res) => {
    
    
    fs.readFile(__dirname + '/public/index.html', (err, data) => {
    
    
        if (err) {
    
    
            console.log(err)
            res.send('后台错误')
        } else {
    
    
            res.writeHead(200, {
    
    
                'Content-Type': 'text/html; charset=utf-8',
            });
            res.end(data)
        }
    })
})

四、MongoDB和关系型数据库有什么区别?

MongoDB不是关系型数据库,没有"表"的概念,没有"字段"的概念,没有"行"的概念。

在这里插入图片描述
MongoDB 没有 Schema(模式、数据模型),就不需要改动数据库,只需要在应用层做必要的改动。

MongoDB 通过键值对的方式来存储数据而不是基于行的表格型存储。

与传统关系数据库有统一的SQL语言操作接口不同,MongoDB 系统通常有自己特有的API接口

猜你喜欢

转载自blog.csdn.net/wdhxs/article/details/111144263