商品分类模块

分类model

const mongoose = require('mongoose')
const schema = new mongoose.Schema({
name: {
type: String,
required: [true, "分类名称不能少"],
unique: true
},
created:{
type:Date,
default: Date.now()
}
}); module.exports = mongoose.model('category', schema);

分类service

const Category = require('../model/category')
const config = require('../config')
async function getCategorysByPage(page=0) {
let categorys = await Category.find().limit(config.PageCount).skip(config.PageCount*page).sort("-created").select("-__v")
return categorys
} async function addCategory(category) {
category.created = Date.now()
await Category.create(category)
} async function deleteCategory(id) {
let res = await Category.deleteOne({_id: id})
if(!res || res.n===0){
throw Error("删除分类失败")
}
} async function updateCategory(id, update) {
let res = await Category.updateOne({_id: id}, update)
if(!res || res.n===0){
throw Error("更新分类失败")
}
} module.exports = {
getCategorysByPage, addCategory, deleteCategory, updateCategory
}

分类router

let router = require('express').Router()
let categoryService = require('../service/category') router.get("/", async (req,res, next)=>{
let page = req.query.page || 0
let categorys = await categoryService.getCategorysByPage(page)
res.success(categorys)
}); router.post("/", async (req,res, next)=>{
await categoryService.addCategory(req.body)
res.success()
}) router.delete("/:id", async (req,res, next)=>{
await categoryService.deleteCategory(req.params.id)
res.success()
}) router.put("/:id", async (req,res, next)=>{
await categoryService.updateCategory(req.params.id, req.body)
res.success()
}) module.exports = router

商品模块

商品model

const mongoose = require('mongoose')
const schema = new mongoose.Schema({
name: {
type: String,
required:[true, "商品名字不能少"],
unique: true
},
price: {
type: String,
required:[true, "商品价格不能少"]
},
stock: {
type: Number,
default: 0,
},
category:{
type: mongoose.Schema.Types.ObjectId,
required: [true, "分类id不能为空"]
},
description:{
type: String,
},
isOnSale:{ //是否上架
type: Boolean,
default: true
},
created:{
type: Date,
default: Date.now()
}
}); module.exports = mongoose.model('product', schema)

商品service

const Product = require('../model/product')
const config = require('../config') async function getProductsByPage(page=0) {
if(page<0){
throw Error("page不能小于0")
} let products = await Product.find({}).limit(config.PageCount).skip(config.PageCount*page).sort("-created").select("-__v");
return products
} async function getProductById(id) {
let res = await Product.findOne({_id: id});
return res
} async function updateProductById(id, update) {
let res = await Product.updateOne({_id: id}, update);
if(!res || res.n ===0){
throw Error("更新失败")
}
} async function deleteProduct(id) {
let res = await Product.deleteOne({_id: id})
if(!res || res.n ===0){
throw Error("删除失败")
}
} async function addProduct(product) {
product.created = Date.now()
let res = await Product.create(product)
}
module.exports = {
getProductsByPage, getProductById, updateProductById, deleteProduct, addProduct
}

商品router

let router = require('express').Router()
let productService = require('../service/product') router.get("/", async (req, res, next)=>{
let page = req.query.page
let products = await productService.getProductsByPage(page);
res.success(products)
}); router.post("/", async (req,res,next)=>{
await productService.addProduct(req.body)
res.success()
}); router.put("/:id", async (req,res,next)=>{
await productService.updateProductById(req.params.id, req.body)
res.success()
}); router.delete("/:id", async (req,res,next)=>{
await productService.deleteProduct(req.params.id)
res.success()
}); module.exports = router;

订单模块

订单model

const mongoose = require('mongoose')
const schema = new mongoose.Schema({
productId: {
type: mongoose.Schema.Types.ObjectId,
required: [true, "商品id不能为空"]
},
productName:{
type: String,
required:[true, "商品名字不能缺少"]
},
productPrice: {
type: String,
required: [true, "商品价格不能缺少"]
},
count: {
type: Number,
required: [true, "商品数量不能为空"],
min:[1, "商品数量不能小于1"]
},
total:{
type: String
},
status: {
type: String, // 订单状态: unpay success cancel
default:"unpay"
},
created: {
type:Date,
default: Date.now(),
},
payTime: {
type: Date
},
cancelTime: Date
}); module.exports = mongoose.model('order', schema);

订单service

'use strict'

const Order = require('../model/order')
const config = require('../config');
const productService = require('./product')
const Big = require('big.js'); async function getOrdersByPage(page = 0) {
return await Order.find().limit(config.PageCount).skip(page*config.PageCount).sort("-created").select("-__v")
} async function getOrderById(id) {
return await Order.findOne({_id: id})
} async function addOrder(order) {
//1. 根据商品id查询出商品
let product = await productService.getProductById(order.productId);
if(!product){
throw Error("未找到商品")
}
//判断库存够不够
if(product.stock < order.count){
throw Error("商品库存不够")
} order.productName = product.name;
order.productPrice = product.price;
order.total = Big(order.productPrice).times(order.count);
order.created = Date.now();
let res = await Order.create(order) //2. 减去库存
let update = {
stock: product.stock - order.count
};
await productService.updateProduct(order.productId, update)
return res
} module.exports = {
getOrdersByPage, getOrderById,
setOrderSuccess, setOrderCancel,
addOrder
};

订单router

const router = require('express').Router()
const orderService = require('../service/order') router.get("/", async (req, res, next) => {
let page = req.query.page || 0
let orders = await orderService.getOrdersByPage(page)
res.success(orders)
}); router.get("/:id", async (req,res,next)=>{
res.success(await orderService.getOrderDetail(req.params.id))
}); router.post("/", async (req,res,next)=>{
let order = await orderService.addOrder(req.body)
res.success(order)
}); module.exports = router;

权限管理模块

主要分2个部分,一个是登录token认证,一个是权限管理。

  1. token认证,就是指有的接口需要token才能访问,有的不需要。比如:登录和注册接口不需要token,但是商品的增删改查必须要token。
  2. 权限管理是指,有的接口指定角色的用户才能调用,不是该角色的人应该直接报错。比如:用户信息获取和删除用户只能管理员角色操作,商家用户则没有这个权限。

这2个部分显然需要在每次请求前进行处理,所以应该用中间件实现。

我们编写2个中间件,token_md.jspermission_md.js

token中间件

let crypto = require('lxj-crypto');
let config = require('../config')
let accountService = require('../service/accout')
let isExcludeUrl = require('../util/token_util'); /**
* 判断req是否是排除检查token的请求
* @param req
*/
function isExcludeCheckReq(req) {
// 不需要token的url
let urls = [
/.*\/user\/login/,
/.*\/user\/register/
];
let result = false;
for (let i = 0; i < urls.length; i++) {
let urlReg = urls[i];
if(urlReg.test(req.url)){
result = true;
break;
}
} return result
} module.exports = async function (req, res, next) {
if (!isExcludeCheckReq(req.url)) { //检查有没有token
let token = req.get('token') || null;
if (!token) {
throw Error("缺少token")
} let tokenData = null;
try {
//解码token, 检查token是否过期
tokenData = JSON.parse(crypto.aesDecrypt(token, config.TokenKey))
// console.log(tokenData.toString() + " now: " + Date.now());
} catch (e) {
// 说明解码失败,需要抛出一个明确的异常
throw Error("token不合法")
}
// 由于tokenData中包含过期时间和username
//1. 检查是否过期
if (tokenData.expire < Date.now()) {
throw Error("token已过期")
}
//2. 检查username是否存在,以防止非法用户
let user = await accountService.getUserByUsername(tokenData.username);
if (!user) {
throw Error("token不合法")
}
// 说明username合法,将user信息赋予req上下文对象,这样后续的每个中间件和处理函数都能直接从req中取出user使用
req.user = user;
}
// 最后不要忘了放行
next()
};

permission中间件

'use strict'
// 负责检查某个接口是否对当前用户的role能否调用
// 具体如下:
// 1. 管理员所有接口都可以调用
// 2. 商家用户能全部调用:商品相关,订单相关,商品分类相关,
// 账户相关:只能调用登录和注册 // 将角色和它对应的权限组成一个映射,然后根据当前用户的role去判断是否符合它对应的权限即可 const role_permissions = [
// 商家角色,和它对应的权限正则
{
role: 0,
permission: [
/.*\/product.*/,
/.*\/order.*/,
/.*\/category.*/
]
},
// 管理员角色,和它对应的权限正则
{
role: 100,
permission: [
/.*/
]
}
]; module.exports = function (req, res, next) {
// 如果是验证过的用户才去判断
// console.log("user:"+JSON.stringify(req.user));
if(req.user){
let isGo = false;
role_permissions.forEach(el => {
if(el.role === req.user.role){
el.permission.forEach(p=>{
if(p.test(req.url)){
isGo = true;
}
});
}
}); if (!isGo) {
throw Error("当前用户权限不够")
}
} next()
};

PM2集群搭建

由于NodeJs是单线程,无法利用多核CPU的优势。想要利用多核CPU,就要进行多进程。NodeJs的cluster模块提供了多进程的支持,PM2又进一步增强了该模块的功能。

PM2能实现单机内的多进程集群,充分利用多核CPU的性能,提高网站的性能。如果是多机器的集群,需要使用nginx来搭建。

编写PM2配置文件:

apps:
- script : app.js
name: xxx
instances: max
exec_mode: cluster
watch : true
env:
NODE_ENV: production

然后指定这个配置文件来运行:

pm2 start xxxx.yml

线上部署

云主机选择

  • 注册阿里云主机,最低配置
  • 可以多人合买

部署工作流

以ubuntu环境为例:

  • 使用xshell客户端进行远程登录

  • 安装nodejs和mongodb

  • Server端安装Git,用来同步代码

  • 工作流:本地代码更新->提交到远程git仓库->登录远程服务器更新代码,PM2会自动重启app程序

NodeJS05的更多相关文章

随机推荐

  1. python基本使用时常见错误

    python基本使用时常见错误 字符编码错误 如果要学习计算机编程语言,首先就要搞懂字符编码,否则在以后的学习过程中,将会是一场噩梦.在一开始使用的时候,我就遇到了很多的关于字符编码的问题,做个简单的 ...

  2. 7、SpringBoot+Mybatis整合------PageHelper简单分页

    开发工具:STS 代码下载链接:https://github.com/theIndoorTrain/SpringBoot_Mybatis/tree/1d30d2a573ce6784149a28af9b ...

  3. C++编程经验总结1

    面向对象的精髓: 主函数其实就是对于类的元素和动作的重新组合来进行一项活动. 一个思想概念:程设是清楚的,完美的. 数学是清楚的,是完美的. 物理是有趣的,尤其是量子物理 生物是清楚的,尤其是基因 外 ...

  4. js实现二分查找

    二分查找需要数组是有序的,1.先从有序数组的最中间元素开始查找,如果和要查找的元素相等,直接返回索引,若不相等则下一步.2.如果指定的元素大于或者小于中间元素,则在大于或小于的那一半区域内查找,重复第 ...

  5. (排班表二)后台动态绘制Grid表格

    后台动态绘制值班表(Grid表格 列名不固定) 要求:表头除了值班人姓名,还要显示日期,及每天的星期值,用斜杠‘/’分隔.即:几号/星期几 最终实现的效果:根据查询的年月显示每个值班人查询月份每天的值 ...

  6. What is JPA

    What is JPA JPA可以看做是EJB3.0的一部分,但它又不限于EJB 3.0,你可以在Web应用.甚至桌面应用中使用.JPA只是一种Java持久化标准,它意在规范ORM(对象关系映射模型) ...

  7. 转:mysql远程连接 Host * is not allowed to connect to this MySQL server

    在本机登入mysql后,更改"mysql"数据库里的"user"表里的"host"项,从"localhost"改为'%' ...

  8. Maven - 配置镜像仓库

    默认仓库的配置(全球中央仓库): 可以打开maven的安装目录/conf/settings.xml文件,配置镜像,找到如下一段配置,这里默认没有配置任何镜像,但是有一个被注释的配置范例: id: 镜像 ...

  9. MySQL 5.7传统复制到GTID在线切换(一主一从)

    Preface       Classic replication is commonly used in previous version of MySQL.It's really tough in ...

  10. LeetCode962. 最大宽度坡

    问题:最大宽度坡 给定一个整数数组 A,坡是元组 (i, j),其中  i < j 且 A[i] <= A[j].这样的坡的宽度为 j - i. 找出 A 中的坡的最大宽度,如果不存在,返 ...