node

node

eggjs egg-ioredis 中使用lua 脚本 (redis lua 脚本的扫盲帖 )

每天进步一点点lopo1983 发表了文章 • 0 个评论 • 1033 次浏览 • 2022-03-28 23:47 • 来自相关话题

基础语法解析调用Lua脚本的语法:
$ redis-cli --eval path/to/redis.lua numberkeys KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...

--eval,告诉redis-cli读取并运行后面的lua脚本
path/to/redis.lua,是lua脚本的位置,也可以直接为脚本字符串。是一个Lua 5.1 script。
numberkeys ,指定后续参数有几个key。
KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。实例脚本 批量查询hash的值 hget 和切换db 以eggjs为例/**
* @summary 竞拍列表
* @description 1.type 【1】检测用户是否已报名 【2】用户报名的拍卖列表
* @router GET /api/v1/user/auction/auction/list
* @request query string page 第几页
* @request query string limit 每页几个
* @request query string type 类型
* @request query string status 状态
* @apikey Authorization
* @response 200 ACRES
*/
async index() {
const {
ctx,
ctx:{
uid,
query:{
page=1,
limit=12,
type,
status
}
}
}= this;
const RDS = await ctx.app.redis.get('auctionRoom')
try {
// 查询符合条件的hash key
const [[],LIST] = await RDS.sscan(`ar:u:${uid}`,(page-1)*limit,'count',limit);

// 注册脚本
// 1 声明输出的类型 rst {} {}对应key 为数组的下标记
// 2 格式化输入的参数KEYS 对应lua的numberkeys 为1
// 3 lua中切换db 也可以做多个参数 如KEYS2 这里我是固定的 所以只传一个 KEYS
// 4,5,6 执行redis的hget脚本 .. v 为lua中的链接符号
// 7 返回值
await RDS.defineCommand("hmgetall", {
lua: `local rst={};
local id=cjson.decode(KEYS[1]);
redis.call('select',13);
for i,v in pairs(id)
do rst[i]=redis.call('hget', 'ar:' .. v,'meta_info')
end;
return rst;`,
})
// 使用脚本并格式化 输出
ctx.body = (await RDS.hmgetall(1,JSON.stringify(LIST.map(e=>`${e}`)))).reduce((a,b)=>{
a['list'].push(JSON.parse(b));
return a
},{list:,page:{limit,page}})
} catch (err) {
console.log(err)
return ctx.body = {
code: 211,
message: ctx.app.config.env === 'local' ? `${(err.message)}`:'服务器忙,请稍后重试!',
data: err.errors
}
}
}[/i]
 
  查看全部
基础语法解析
调用Lua脚本的语法:
$ redis-cli --eval path/to/redis.lua numberkeys KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...

--eval,告诉redis-cli读取并运行后面的lua脚本
path/to/redis.lua,是lua脚本的位置,也可以直接为脚本字符串。是一个Lua 5.1 script。
numberkeys ,指定后续参数有几个key。
KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
实例脚本 批量查询hash的值 hget 和切换db 以eggjs为例
/**
* @summary 竞拍列表
* @description 1.type 【1】检测用户是否已报名 【2】用户报名的拍卖列表
* @router GET /api/v1/user/auction/auction/list
* @request query string page 第几页
* @request query string limit 每页几个
* @request query string type 类型
* @request query string status 状态
* @apikey Authorization
* @response 200 ACRES
*/
async index() {
const {
ctx,
ctx:{
uid,
query:{
page=1,
limit=12,
type,
status
}
}
}= this;
const RDS = await ctx.app.redis.get('auctionRoom')
try {
// 查询符合条件的hash key
const [[],LIST] = await RDS.sscan(`ar:u:${uid}`,(page-1)*limit,'count',limit);

// 注册脚本
// 1 声明输出的类型 rst {} {}对应key 为数组的下标记
// 2 格式化输入的参数KEYS 对应lua的numberkeys 为1
// 3 lua中切换db 也可以做多个参数 如KEYS2 这里我是固定的 所以只传一个 KEYS
// 4,5,6 执行redis的hget脚本 .. v 为lua中的链接符号
// 7 返回值
await RDS.defineCommand("hmgetall", {
lua: `local rst={};
local id=cjson.decode(KEYS[1]);
redis.call('select',13);
for i,v in pairs(id)
do rst[i]=redis.call('hget', 'ar:' .. v,'meta_info')
end;
return rst;`,
})
// 使用脚本并格式化 输出
ctx.body = (await RDS.hmgetall(1,JSON.stringify(LIST.map(e=>`${e}`)))).reduce((a,b)=>{
a['list'].push(JSON.parse(b));
return a
},{list:,page:{limit,page}})
} catch (err) {
console.log(err)
return ctx.body = {
code: 211,
message: ctx.app.config.env === 'local' ? `${(err.message)}`:'服务器忙,请稍后重试!',
data: err.errors
}
}
}[/i]

 
 

mongodb 分页封装(传统分页)【2020-10-30 修正】

mongodblopo1983 发表了文章 • 0 个评论 • 1503 次浏览 • 2020-09-22 11:47 • 来自相关话题

const pageFn = ({ MATCH = [], OTHERMATCH = [], OTHERFACET = {}, FACET_KEY = {}, limit = 20, page = 1 } = {}) => {
return [{
$facet: {
'list': [
...MATCH,
{
$skip: (page - 1) * limit
},
{
$limit: limit * 1
},
...OTHERMATCH.length ? OTHERMATCH : []
],
'page': [
...MATCH,
{
$count: 'count'
}
],
...OTHERFACET
}
}, {
$project: {
list: {
$cond: [{ $eq: [{ $size: '$list' }, 0] },
[], '$list'
]
},
page: {
$cond: [{ $eq: [{ $size: '$page' }, 0] },
[{ count: 0 }], '$page'
]
},
count: 1,
...FACET_KEY
}
}, {
$unwind: '$page'
}, {
$addFields: {
'page.limit': limit * 1,
'page.page': page * 1
}
}]
};
module.exports = pageFn 查看全部
const pageFn = ({ MATCH = [], OTHERMATCH = [], OTHERFACET = {}, FACET_KEY = {}, limit = 20, page = 1 } = {}) => {
return [{
$facet: {
'list': [
...MATCH,
{
$skip: (page - 1) * limit
},
{
$limit: limit * 1
},
...OTHERMATCH.length ? OTHERMATCH : []
],
'page': [
...MATCH,
{
$count: 'count'
}
],
...OTHERFACET
}
}, {
$project: {
list: {
$cond: [{ $eq: [{ $size: '$list' }, 0] },
[], '$list'
]
},
page: {
$cond: [{ $eq: [{ $size: '$page' }, 0] },
[{ count: 0 }], '$page'
]
},
count: 1,
...FACET_KEY
}
}, {
$unwind: '$page'
}, {
$addFields: {
'page.limit': limit * 1,
'page.page': page * 1
}
}]
};
module.exports = pageFn

egg 自动同步关系型数据库model

Nodejslopo1983 发表了文章 • 0 个评论 • 1777 次浏览 • 2020-05-07 12:39 • 来自相关话题

// {app_root}/app.js
module.exports = app => {
app.beforeStart(async () => {
// 从配置中心获取 MySQL 的配置
// { host: 'mysql.com', port: '3306', user: 'test_user', password: 'test_password', database: 'test' }
await app.model.sync({ force: true });
});
}; 查看全部
// {app_root}/app.js
module.exports = app => {
app.beforeStart(async () => {
// 从配置中心获取 MySQL 的配置
// { host: 'mysql.com', port: '3306', user: 'test_user', password: 'test_password', database: 'test' }
await app.model.sync({ force: true });
});
};

Nodejs 开发企业微信第三方应用 (一)

Nodejslopo1983 发表了文章 • 0 个评论 • 1776 次浏览 • 2019-11-30 10:04 • 来自相关话题

框架 :Egg.js
 
配置:
config/config.default.js{
...
// 企业微信配置
config.weWork = {
'CorpID': '*',
'ProviderSecret': '*',
'Token': '*',
'EncodingAESKey': '*',
Saas: {
Apps: {
'suite_id': '*',
'suite_secret': '*-*-*',
'Token': '*',
'EncodingAESKey': '*'
}
}
};
...
}
通用方法(SERVICE)结构
service/qywx

 + auths
    - other.js
    - suiteToken.js
 + user
    - auth.js
 auth.js
 department.js
 index.js
 pushBack.js
 receive.js
 
数据库设计 (MODEL)--mongodb

  wework.js
  wwtoken.js
  jsapiTicket.js
 
任务 (schedule)
 
token_refresh.js
 
控制器 (controller)
 
+wework
 + callback
     data.js
     instruct.js
 + common
     config.js
 pushBack.js
 
路由 (router)
 
// 注册页
router.get('index', '', controller.home.index);
// 登录页
router.get('login', '/login', controller.home.login);
// 安装页面
router.get('steup', '/steup', controller.home.steupApp);
router.resources('file', '/common/file', controller.common.files);
router.post('files', '/common/files', controller.common.files.creates);
// 服務器回調
router.get('weworkPushBack', '/wework/pushBack', controller.wework.pushBack.pushBack);
// 數據回調verifyUrl
router.get('rbData', '/wework/rb/data', controller.wework.callback.data.verifyUrl);
// 指令回調verifyUrl
router.get('rbInstructvf', '/wework/rb/instruct', controller.wework.callback.data.verifyUrl);
router.post('rbInstruct', '/wework/rb/instruct', controller.wework.callback.data.receive); 查看全部
框架 :Egg.js
 
配置:
config/config.default.js
{
...
// 企业微信配置
config.weWork = {
'CorpID': '*',
'ProviderSecret': '*',
'Token': '*',
'EncodingAESKey': '*',
Saas: {
Apps: {
'suite_id': '*',
'suite_secret': '*-*-*',
'Token': '*',
'EncodingAESKey': '*'
}
}
};
...
}

通用方法(SERVICE)结构
service/qywx

 + auths
    - other.js
    - suiteToken.js
 + user
    - auth.js
 auth.js
 department.js
 index.js
 pushBack.js
 receive.js
 
数据库设计 (MODEL)--mongodb

  wework.js
  wwtoken.js
  jsapiTicket.js
 
任务 (schedule)
 
token_refresh.js
 
控制器 (controller)
 
+wework
 + callback
     data.js
     instruct.js
 + common
     config.js
 pushBack.js
 
路由 (router)
 
    // 注册页
router.get('index', '', controller.home.index);
// 登录页
router.get('login', '/login', controller.home.login);
// 安装页面
router.get('steup', '/steup', controller.home.steupApp);
router.resources('file', '/common/file', controller.common.files);
router.post('files', '/common/files', controller.common.files.creates);
// 服務器回調
router.get('weworkPushBack', '/wework/pushBack', controller.wework.pushBack.pushBack);
// 數據回調verifyUrl
router.get('rbData', '/wework/rb/data', controller.wework.callback.data.verifyUrl);
// 指令回調verifyUrl
router.get('rbInstructvf', '/wework/rb/instruct', controller.wework.callback.data.verifyUrl);
router.post('rbInstruct', '/wework/rb/instruct', controller.wework.callback.data.receive);

eggjs 静态文件配置

Nodejslopo1983 发表了文章 • 0 个评论 • 3736 次浏览 • 2019-09-04 17:20 • 来自相关话题

config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
}; 查看全部
config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
};

egg 处理提交的xml

Nodejslopo1983 发表了文章 • 0 个评论 • 2351 次浏览 • 2019-09-04 17:09 • 来自相关话题

最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};
同样的方法可以处理其他的任何格式 查看全部
最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js
    config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};

同样的方法可以处理其他的任何格式


Egg 配置mongoose

Nodejslopo1983 发表了文章 • 0 个评论 • 1823 次浏览 • 2019-08-31 08:55 • 来自相关话题

1.安裝npm i egg-mongoose --save2./config/plugin.jsexports.mongoose = {
enable: true,
package: 'egg-mongoose',
};3./config/config.default.js
 
單一exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};多個exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}controller/user/address (RESTful 風格)const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressControllerrouter.jsrouter.resources('user_address', '/user/address', app.jwt, controller.user.address); 查看全部
1.安裝
npm i egg-mongoose --save
2./config/plugin.js
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
3./config/config.default.js
 
單一
exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};
多個
exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};
4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}
controller/user/address (RESTful 風格)
const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressController
router.js
router.resources('user_address', '/user/address', app.jwt, controller.user.address);

egg-jwt配置

Nodejslopo1983 发表了文章 • 0 个评论 • 2079 次浏览 • 2019-08-30 18:00 • 来自相关话题

1. 安裝npm i egg-jwt --save
 
2.config/config.default config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};
 
3.config/pluginexports.jwt = {
enable: true,
package: "egg-jwt"
};
 4.service/apps/jwt.jsclass jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService5.使用class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/contextmodule.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取 查看全部
1. 安裝
npm i egg-jwt --save

 
2.config/config.default
    config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};

 
3.config/plugin
exports.jwt = {
enable: true,
package: "egg-jwt"
};

 4.service/apps/jwt.js
class jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService
5.使用
class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}
6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/context
module.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};
在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取

eggjs 设置跨域

Nodejslopo1983 发表了文章 • 0 个评论 • 1700 次浏览 • 2019-08-30 17:57 • 来自相关话题

1.egg-corsnpm install egg-cors --save2.config/plugin.jsexports.cors: {
enable: true,
package: 'egg-cors'
}3.config/config.default.jsconfig.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}; 查看全部
1.egg-cors
npm install  egg-cors --save
2.config/plugin.js
exports.cors: {
enable: true,
package: 'egg-cors'
}
3.config/config.default.js
config.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
};

eggjs 上传文件

Nodejslopo1983 发表了文章 • 0 个评论 • 2773 次浏览 • 2019-08-30 17:52 • 来自相关话题

'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController 查看全部
'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController

Node+eggjs+mongodb 一步步实现 CRM(2)需求整理

每天进步一点点lopo1983 发表了文章 • 0 个评论 • 2177 次浏览 • 2019-03-04 10:00 • 来自相关话题

?























部分附件收限制无法上传(懒得折腾) 请解压缩查看 查看全部
功能结构.png

?
设置.png


资金.png


客户.png


辅助资料.png


部门与员工.png

部分附件收限制无法上传(懒得折腾) 请解压缩查看

Node+eggjs+mongodb 一步步实现 CRM(1)环境搭建

每天进步一点点lopo1983 发表了文章 • 0 个评论 • 3187 次浏览 • 2019-02-28 11:24 • 来自相关话题

本文章建议有一定Nodejs开发经验和熟悉ES6/7的开发人员查看,文中若有错误望指出!
?1.安装nodejs?
?
? ?建议选择?LTS 版本,最低要求 8.x(机器配置不好的,请考虑8.x)。
?
2.egg 安装$ npm i egg-init -g
$ egg-init egg-crm --type=simple
$ cd egg-crm
$ npm inpm run devegg文档地址
?
3.mongoDB安装 (4.x)
?
建议在服务器上安装,以便随时可以开发,这里以centos?安装为例
步骤如下:
创建该路径文件 /etc/yum.repos.d/mongodb-org-4.0.repo[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc安装sudo yum install -y mongodb-org-4.0.6 mongodb-org-server-4.0.6 mongodb-org-shell-4.0.6 mongodb-org-mongos-4.0.6 mongodb-org-tools-4.0.6启动service mongod start?具体可参考官方文档
?
4.相关插件配置 "devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.1.0",
"baidu-aip-sdk": "^2.3.9",
"bce-sdk-js": "^0.2.9",
"decimal": "^0.0.2",
"egg-bin": "^4.11.0",
"egg-ci": "^1.11.0",
"egg-cors": "^2.1.2",
"egg-jwt": "^3.1.6",
"egg-mock": "^3.21.0",
"egg-mongoose": "^3.1.1",
"egg-validate": "^2.0.2",
"eslint": "^5.13.0",
"eslint-config-egg": "^7.1.0",
"lodash": "^4.17.11",
"stream-to-array": "^2.3.0",
"webstorm-disable-index": "^1.2.0",
"xml2js": "^0.4.19"
},
baidu-aip-sdk:百度AI接口用于智能审核 OCR等
bce-sdk-js: 百度BCE 接口 我们会用到百度的BOS 云存储
decimal:处理JS浮点误差
egg-cors:egg跨域
egg-jwt:egg jsonWebToken
egg-mongoose:mongo数据库链接
egg-validate:egg数据校验
lodash:一个十分优秀的函数编程库
stream-to-array:流处理
xml2js:微信支付

4.egg相关配置
?
config.default.js(相关留空的数据请填入自己的数据)'use strict';

module.exports = appInfo => {
const config = exports = {};

// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1539582326426_4353';

// csrf配置
config.security = {
csrf: {
enable: false,
ignoreJSON: true
},
domainWhiteList: ['http://localhost:7001', 'http://192.168.0.123', 'http://localhost]
};
//
config.cors = {
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
credentials: true
};
// // add your config here
// config.middleware = ;
config.middleware = ['errorHandler', 'responseFormatter', 'jwtErrorHandler'];
config.middleware.errorHandler = {
match: '/api',
};
config.middleware.responseFormatter = {
match: '/api',
};
//短信配置
config.sms = {
svip: {
uri: ‘',
name: '',
password: '',
},
};
// 邮箱配置
config.email = {
service: 'QQex',
port: 465,
secureConnection: true,
auth: {
user: '',
pass: '',
}
}
// mongodb配置
config.mongoose = {
url: 'mongodb://127.0.0.1/geecrm',
options: {},
};
// bos云存储
/*****************begin********************/
config.baiduBos = {
endpoint: 'http://bj.bcebos.com',
credentials: {
ak: '',
sk: ''
}
};
config.baiduBosBucket = '';
/*****************end***********************/
// baidu AIP
config.baiduAIP = {
APP_ID: '',
API_KEY: '',
SECRET_KEY: ''
};
// baidu VOD
config.baiduVod = {
endpoint: 'http://vod.bj.baidubce.com',
credentials: {
ak: '',
sk: ''
}
};
// 企业微信配置
config.weWork = {
'corpid': '',
'corpsecret': '',
'agentId': ''
};
// 微信配置
config.wechatApi = {
appId: '',
appSecret: '',
};
// 默认json 设置
config.JSONS = {
'code': 200,
'message': 'success',
'uri': 'https://api.lanjing.xyz',
};
config.alipay = {
appId: "",
rsaPrivate: "",
notifyUrl: "", //异步回调
signType: "RSA2",
rsaPublic: "",
sandbox: false //沙箱环境
}

config.wechatPay = {
partnerKey: "",
appId: "",
mchId: "",
notifyUrl: "http://www.langjing.xyz/wechat/notify", //异步回调,到微信平台设置下
pfx: ""
}
//
return config;
};
??plugin.js ? ? ? ? ?'use strict';
exports.validate = {
enable: true,
package: 'egg-validate',
};
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
exports.jwt = {
enable: true,
package: "egg-jwt"
};
exports.cors = {
enable: true,
package: "egg-cors"
};

?
?项目目录结构 (文件夹可按需建立无内容留空即可)

?





? 查看全部

本文章建议有一定Nodejs开发经验和熟悉ES6/7的开发人员查看,文中若有错误望指出!


?1.安装nodejs?
?
? ?建议选择?LTS 版本,最低要求 8.x(机器配置不好的,请考虑8.x)。
?
2.egg 安装
$ npm i egg-init -g
$ egg-init egg-crm --type=simple
$ cd egg-crm
$ npm i
npm run dev
egg文档地址
?
3.mongoDB安装 (4.x)
?
建议在服务器上安装,以便随时可以开发,这里以centos?安装为例
步骤如下:
创建该路径文件 /etc/yum.repos.d/mongodb-org-4.0.repo
[mongodb-org-4.0]
name=MongoDB Repository
baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/4.0/x86_64/
gpgcheck=1
enabled=1
gpgkey=https://www.mongodb.org/static/pgp/server-4.0.asc
安装
sudo yum install -y mongodb-org-4.0.6 mongodb-org-server-4.0.6 mongodb-org-shell-4.0.6 mongodb-org-mongos-4.0.6 mongodb-org-tools-4.0.6
启动
service mongod start
?具体可参考官方文档
?
4.相关插件配置
  "devDependencies": {
"autod": "^3.0.1",
"autod-egg": "^1.1.0",
"baidu-aip-sdk": "^2.3.9",
"bce-sdk-js": "^0.2.9",
"decimal": "^0.0.2",
"egg-bin": "^4.11.0",
"egg-ci": "^1.11.0",
"egg-cors": "^2.1.2",
"egg-jwt": "^3.1.6",
"egg-mock": "^3.21.0",
"egg-mongoose": "^3.1.1",
"egg-validate": "^2.0.2",
"eslint": "^5.13.0",
"eslint-config-egg": "^7.1.0",
"lodash": "^4.17.11",
"stream-to-array": "^2.3.0",
"webstorm-disable-index": "^1.2.0",
"xml2js": "^0.4.19"
},

baidu-aip-sdk:百度AI接口用于智能审核 OCR等
bce-sdk-js: 百度BCE 接口 我们会用到百度的BOS 云存储
decimal:处理JS浮点误差
egg-cors:egg跨域
egg-jwt:egg jsonWebToken
egg-mongoose:mongo数据库链接
egg-validate:egg数据校验
lodash:一个十分优秀的函数编程库
stream-to-array:流处理
xml2js:微信支付

4.egg相关配置
?
config.default.js(相关留空的数据请填入自己的数据)
'use strict';

module.exports = appInfo => {
const config = exports = {};

// use for cookie sign key, should change to your own and keep security
config.keys = appInfo.name + '_1539582326426_4353';

// csrf配置
config.security = {
csrf: {
enable: false,
ignoreJSON: true
},
domainWhiteList: ['http://localhost:7001', 'http://192.168.0.123', 'http://localhost]
};
//
config.cors = {
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
credentials: true
};
// // add your config here
// config.middleware = ;
config.middleware = ['errorHandler', 'responseFormatter', 'jwtErrorHandler'];
config.middleware.errorHandler = {
match: '/api',
};
config.middleware.responseFormatter = {
match: '/api',
};
//短信配置
config.sms = {
svip: {
uri: ‘',
name: '',
password: '',
},
};
// 邮箱配置
config.email = {
service: 'QQex',
port: 465,
secureConnection: true,
auth: {
user: '',
pass: '',
}
}
// mongodb配置
config.mongoose = {
url: 'mongodb://127.0.0.1/geecrm',
options: {},
};
// bos云存储
/*****************begin********************/
config.baiduBos = {
endpoint: 'http://bj.bcebos.com',
credentials: {
ak: '',
sk: ''
}
};
config.baiduBosBucket = '';
/*****************end***********************/
// baidu AIP
config.baiduAIP = {
APP_ID: '',
API_KEY: '',
SECRET_KEY: ''
};
// baidu VOD
config.baiduVod = {
endpoint: 'http://vod.bj.baidubce.com',
credentials: {
ak: '',
sk: ''
}
};
// 企业微信配置
config.weWork = {
'corpid': '',
'corpsecret': '',
'agentId': ''
};
// 微信配置
config.wechatApi = {
appId: '',
appSecret: '',
};
// 默认json 设置
config.JSONS = {
'code': 200,
'message': 'success',
'uri': 'https://api.lanjing.xyz',
};
config.alipay = {
appId: "",
rsaPrivate: "",
notifyUrl: "", //异步回调
signType: "RSA2",
rsaPublic: "",
sandbox: false //沙箱环境
}

config.wechatPay = {
partnerKey: "",
appId: "",
mchId: "",
notifyUrl: "http://www.langjing.xyz/wechat/notify", //异步回调,到微信平台设置下
pfx: ""
}
//
return config;
};

??plugin.js ? ? ? ? ?
'use strict';
exports.validate = {
enable: true,
package: 'egg-validate',
};
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
exports.jwt = {
enable: true,
package: "egg-jwt"
};
exports.cors = {
enable: true,
package: "egg-cors"
};


?
?项目目录结构 (文件夹可按需建立无内容留空即可)

?
QQ图片20190304101503.png


?

eggjs egg-ioredis 中使用lua 脚本 (redis lua 脚本的扫盲帖 )

每天进步一点点lopo1983 发表了文章 • 0 个评论 • 1033 次浏览 • 2022-03-28 23:47 • 来自相关话题

基础语法解析调用Lua脚本的语法:
$ redis-cli --eval path/to/redis.lua numberkeys KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...

--eval,告诉redis-cli读取并运行后面的lua脚本
path/to/redis.lua,是lua脚本的位置,也可以直接为脚本字符串。是一个Lua 5.1 script。
numberkeys ,指定后续参数有几个key。
KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。实例脚本 批量查询hash的值 hget 和切换db 以eggjs为例/**
* @summary 竞拍列表
* @description 1.type 【1】检测用户是否已报名 【2】用户报名的拍卖列表
* @router GET /api/v1/user/auction/auction/list
* @request query string page 第几页
* @request query string limit 每页几个
* @request query string type 类型
* @request query string status 状态
* @apikey Authorization
* @response 200 ACRES
*/
async index() {
const {
ctx,
ctx:{
uid,
query:{
page=1,
limit=12,
type,
status
}
}
}= this;
const RDS = await ctx.app.redis.get('auctionRoom')
try {
// 查询符合条件的hash key
const [[],LIST] = await RDS.sscan(`ar:u:${uid}`,(page-1)*limit,'count',limit);

// 注册脚本
// 1 声明输出的类型 rst {} {}对应key 为数组的下标记
// 2 格式化输入的参数KEYS 对应lua的numberkeys 为1
// 3 lua中切换db 也可以做多个参数 如KEYS2 这里我是固定的 所以只传一个 KEYS
// 4,5,6 执行redis的hget脚本 .. v 为lua中的链接符号
// 7 返回值
await RDS.defineCommand("hmgetall", {
lua: `local rst={};
local id=cjson.decode(KEYS[1]);
redis.call('select',13);
for i,v in pairs(id)
do rst[i]=redis.call('hget', 'ar:' .. v,'meta_info')
end;
return rst;`,
})
// 使用脚本并格式化 输出
ctx.body = (await RDS.hmgetall(1,JSON.stringify(LIST.map(e=>`${e}`)))).reduce((a,b)=>{
a['list'].push(JSON.parse(b));
return a
},{list:,page:{limit,page}})
} catch (err) {
console.log(err)
return ctx.body = {
code: 211,
message: ctx.app.config.env === 'local' ? `${(err.message)}`:'服务器忙,请稍后重试!',
data: err.errors
}
}
}[/i]
 
  查看全部
基础语法解析
调用Lua脚本的语法:
$ redis-cli --eval path/to/redis.lua numberkeys KEYS[1] KEYS[2] , ARGV[1] ARGV[2] ...

--eval,告诉redis-cli读取并运行后面的lua脚本
path/to/redis.lua,是lua脚本的位置,也可以直接为脚本字符串。是一个Lua 5.1 script。
numberkeys ,指定后续参数有几个key。
KEYS[1] KEYS[2],是要操作的键,可以指定多个,在lua脚本中通过KEYS[1], KEYS[2]获取
ARGV[1] ARGV[2],参数,在lua脚本中通过ARGV[1], ARGV[2]获取。
实例脚本 批量查询hash的值 hget 和切换db 以eggjs为例
/**
* @summary 竞拍列表
* @description 1.type 【1】检测用户是否已报名 【2】用户报名的拍卖列表
* @router GET /api/v1/user/auction/auction/list
* @request query string page 第几页
* @request query string limit 每页几个
* @request query string type 类型
* @request query string status 状态
* @apikey Authorization
* @response 200 ACRES
*/
async index() {
const {
ctx,
ctx:{
uid,
query:{
page=1,
limit=12,
type,
status
}
}
}= this;
const RDS = await ctx.app.redis.get('auctionRoom')
try {
// 查询符合条件的hash key
const [[],LIST] = await RDS.sscan(`ar:u:${uid}`,(page-1)*limit,'count',limit);

// 注册脚本
// 1 声明输出的类型 rst {} {}对应key 为数组的下标记
// 2 格式化输入的参数KEYS 对应lua的numberkeys 为1
// 3 lua中切换db 也可以做多个参数 如KEYS2 这里我是固定的 所以只传一个 KEYS
// 4,5,6 执行redis的hget脚本 .. v 为lua中的链接符号
// 7 返回值
await RDS.defineCommand("hmgetall", {
lua: `local rst={};
local id=cjson.decode(KEYS[1]);
redis.call('select',13);
for i,v in pairs(id)
do rst[i]=redis.call('hget', 'ar:' .. v,'meta_info')
end;
return rst;`,
})
// 使用脚本并格式化 输出
ctx.body = (await RDS.hmgetall(1,JSON.stringify(LIST.map(e=>`${e}`)))).reduce((a,b)=>{
a['list'].push(JSON.parse(b));
return a
},{list:,page:{limit,page}})
} catch (err) {
console.log(err)
return ctx.body = {
code: 211,
message: ctx.app.config.env === 'local' ? `${(err.message)}`:'服务器忙,请稍后重试!',
data: err.errors
}
}
}[/i]

 
 

mongodb 分页封装(传统分页)【2020-10-30 修正】

mongodblopo1983 发表了文章 • 0 个评论 • 1503 次浏览 • 2020-09-22 11:47 • 来自相关话题

const pageFn = ({ MATCH = [], OTHERMATCH = [], OTHERFACET = {}, FACET_KEY = {}, limit = 20, page = 1 } = {}) => {
return [{
$facet: {
'list': [
...MATCH,
{
$skip: (page - 1) * limit
},
{
$limit: limit * 1
},
...OTHERMATCH.length ? OTHERMATCH : []
],
'page': [
...MATCH,
{
$count: 'count'
}
],
...OTHERFACET
}
}, {
$project: {
list: {
$cond: [{ $eq: [{ $size: '$list' }, 0] },
[], '$list'
]
},
page: {
$cond: [{ $eq: [{ $size: '$page' }, 0] },
[{ count: 0 }], '$page'
]
},
count: 1,
...FACET_KEY
}
}, {
$unwind: '$page'
}, {
$addFields: {
'page.limit': limit * 1,
'page.page': page * 1
}
}]
};
module.exports = pageFn 查看全部
const pageFn = ({ MATCH = [], OTHERMATCH = [], OTHERFACET = {}, FACET_KEY = {}, limit = 20, page = 1 } = {}) => {
return [{
$facet: {
'list': [
...MATCH,
{
$skip: (page - 1) * limit
},
{
$limit: limit * 1
},
...OTHERMATCH.length ? OTHERMATCH : []
],
'page': [
...MATCH,
{
$count: 'count'
}
],
...OTHERFACET
}
}, {
$project: {
list: {
$cond: [{ $eq: [{ $size: '$list' }, 0] },
[], '$list'
]
},
page: {
$cond: [{ $eq: [{ $size: '$page' }, 0] },
[{ count: 0 }], '$page'
]
},
count: 1,
...FACET_KEY
}
}, {
$unwind: '$page'
}, {
$addFields: {
'page.limit': limit * 1,
'page.page': page * 1
}
}]
};
module.exports = pageFn

egg 自动同步关系型数据库model

Nodejslopo1983 发表了文章 • 0 个评论 • 1777 次浏览 • 2020-05-07 12:39 • 来自相关话题

// {app_root}/app.js
module.exports = app => {
app.beforeStart(async () => {
// 从配置中心获取 MySQL 的配置
// { host: 'mysql.com', port: '3306', user: 'test_user', password: 'test_password', database: 'test' }
await app.model.sync({ force: true });
});
}; 查看全部
// {app_root}/app.js
module.exports = app => {
app.beforeStart(async () => {
// 从配置中心获取 MySQL 的配置
// { host: 'mysql.com', port: '3306', user: 'test_user', password: 'test_password', database: 'test' }
await app.model.sync({ force: true });
});
};

Nodejs 开发企业微信第三方应用 (一)

Nodejslopo1983 发表了文章 • 0 个评论 • 1776 次浏览 • 2019-11-30 10:04 • 来自相关话题

框架 :Egg.js
 
配置:
config/config.default.js{
...
// 企业微信配置
config.weWork = {
'CorpID': '*',
'ProviderSecret': '*',
'Token': '*',
'EncodingAESKey': '*',
Saas: {
Apps: {
'suite_id': '*',
'suite_secret': '*-*-*',
'Token': '*',
'EncodingAESKey': '*'
}
}
};
...
}
通用方法(SERVICE)结构
service/qywx

 + auths
    - other.js
    - suiteToken.js
 + user
    - auth.js
 auth.js
 department.js
 index.js
 pushBack.js
 receive.js
 
数据库设计 (MODEL)--mongodb

  wework.js
  wwtoken.js
  jsapiTicket.js
 
任务 (schedule)
 
token_refresh.js
 
控制器 (controller)
 
+wework
 + callback
     data.js
     instruct.js
 + common
     config.js
 pushBack.js
 
路由 (router)
 
// 注册页
router.get('index', '', controller.home.index);
// 登录页
router.get('login', '/login', controller.home.login);
// 安装页面
router.get('steup', '/steup', controller.home.steupApp);
router.resources('file', '/common/file', controller.common.files);
router.post('files', '/common/files', controller.common.files.creates);
// 服務器回調
router.get('weworkPushBack', '/wework/pushBack', controller.wework.pushBack.pushBack);
// 數據回調verifyUrl
router.get('rbData', '/wework/rb/data', controller.wework.callback.data.verifyUrl);
// 指令回調verifyUrl
router.get('rbInstructvf', '/wework/rb/instruct', controller.wework.callback.data.verifyUrl);
router.post('rbInstruct', '/wework/rb/instruct', controller.wework.callback.data.receive); 查看全部
框架 :Egg.js
 
配置:
config/config.default.js
{
...
// 企业微信配置
config.weWork = {
'CorpID': '*',
'ProviderSecret': '*',
'Token': '*',
'EncodingAESKey': '*',
Saas: {
Apps: {
'suite_id': '*',
'suite_secret': '*-*-*',
'Token': '*',
'EncodingAESKey': '*'
}
}
};
...
}

通用方法(SERVICE)结构
service/qywx

 + auths
    - other.js
    - suiteToken.js
 + user
    - auth.js
 auth.js
 department.js
 index.js
 pushBack.js
 receive.js
 
数据库设计 (MODEL)--mongodb

  wework.js
  wwtoken.js
  jsapiTicket.js
 
任务 (schedule)
 
token_refresh.js
 
控制器 (controller)
 
+wework
 + callback
     data.js
     instruct.js
 + common
     config.js
 pushBack.js
 
路由 (router)
 
    // 注册页
router.get('index', '', controller.home.index);
// 登录页
router.get('login', '/login', controller.home.login);
// 安装页面
router.get('steup', '/steup', controller.home.steupApp);
router.resources('file', '/common/file', controller.common.files);
router.post('files', '/common/files', controller.common.files.creates);
// 服務器回調
router.get('weworkPushBack', '/wework/pushBack', controller.wework.pushBack.pushBack);
// 數據回調verifyUrl
router.get('rbData', '/wework/rb/data', controller.wework.callback.data.verifyUrl);
// 指令回調verifyUrl
router.get('rbInstructvf', '/wework/rb/instruct', controller.wework.callback.data.verifyUrl);
router.post('rbInstruct', '/wework/rb/instruct', controller.wework.callback.data.receive);

eggjs 静态文件配置

Nodejslopo1983 发表了文章 • 0 个评论 • 3736 次浏览 • 2019-09-04 17:20 • 来自相关话题

config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
}; 查看全部
config.default.js
// 靜態目錄及緩存設置
config.static = {
prefix: '/', //靜態化URL 我這裏默認網站根目錄(項目需要)
dir: path.join(appInfo.baseDir, 'app/public'), // 靜態文件夾地址 可以設置多個 可以簡寫為 :['app/public','app/public1']
dynamic: true, //是否緩存靜態資源
preload: false, //啓動項目開啓緩存
// maxAge: 31536000,
maxAge: 0, //緩存時間 開發建議設0 跳坑
buffer: true, //是否緩存到内存 默認prod 緩存
};

egg 处理提交的xml

Nodejslopo1983 发表了文章 • 0 个评论 • 2351 次浏览 • 2019-09-04 17:09 • 来自相关话题

最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};
同样的方法可以处理其他的任何格式 查看全部
最近在做企业微信相关的接口转发 发现回调是XML 数据格式 
egg默认是没有处理xml(目前在文档里面没找到.....)
看了下egg的源码 发现处理request 是用的bodyParser

config.default.js
    config.bodyParser = {
enable: true,
// @see https://github.com/hapijs/qs/b ... %23L8 for more options
queryString: {
arrayLimit: 100,
depth: 5,
parameterLimit: 1000,
},
enableTypes: ['json', 'form', 'text'],
extendTypes: {
text: ['text/xml', 'application/xml'],
},
};

同样的方法可以处理其他的任何格式


Egg 配置mongoose

Nodejslopo1983 发表了文章 • 0 个评论 • 1823 次浏览 • 2019-08-31 08:55 • 来自相关话题

1.安裝npm i egg-mongoose --save2./config/plugin.jsexports.mongoose = {
enable: true,
package: 'egg-mongoose',
};3./config/config.default.js
 
單一exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};多個exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}controller/user/address (RESTful 風格)const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressControllerrouter.jsrouter.resources('user_address', '/user/address', app.jwt, controller.user.address); 查看全部
1.安裝
npm i egg-mongoose --save
2./config/plugin.js
exports.mongoose = {
enable: true,
package: 'egg-mongoose',
};
3./config/config.default.js
 
單一
exports.mongoose = {
url: 'mongodb://127.0.0.1/example',
options: {},
plugins: [createdPlugin, [updatedPlugin, pluginOptions]],
};
多個
exports.mongoose = {
clients: {
// clientId, access the client instance by app.mongooseDB.get('clientId')
db1: {
url: 'mongodb://127.0.0.1/example1',
options: {},
},
db2: {
url: 'mongodb://127.0.0.1/example2',
options: {},
},
},
};
4.使用(案例參考)
model/user/address (model文件夾 在app目錄下自己創建)
module.exports = app => {
const mongoose = app.mongoose;
const Schema = mongoose.Schema;
const {
ctx,
helper,
service
} = app.createAnonymousContext();
const {
objToQuery
} = helper;
const UserAddressSchema = new Schema({
// 用户id
_uid: {
type: Schema.Types.ObjectId,
ref: 'account_user',
required: true,
index: true
},
default_id: '',
addresses: [{
// 数组ID
_id: mongoose.Schema.Types.ObjectId,
// 收件人名称
name: '',
// 聯係電話
phone: '',
// 省市区地址
Region: '',
// 城市id
RegionId: '',
// 郵編
postcode: '',
// 详细地址
location: '',
// 地址标签
tag: ''
}]
}, {
timestamps: {
createdAt: 'created',
updatedAt: 'updated'
}
});
UserAddressSchema.statics = {
// 添加地址
addAddress: async function(_uid, BODYS) {
const { isDefault } = BODYS;
const _id = mongoose.Types.ObjectId();
const MODEL = this.findOneAndUpdate({
_uid
}, {
$push: {
'addresses': {
...BODYS,
_id
}
},
...isDefault && { default_id: _id }
}, {
new: true,
fields: 'addresses default_id -_id'
})
try {
const DATAS = await MODEL;
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 删除地址
deleteAddress: async function(_uid, _id) {
const MODEL = this.findOneAndUpdate({
_uid
}, {
$pull: {
'addresses': {
_id
}
}
})
try {
const DATAS = await MODEL;
console.log(DATAS)
return DATAS
} catch (error) {
console.log(error)
return error
}
},
// 更新地址
updateAddress: async function(_uid, BODYS) {
const { _id, isDefault } = BODYS;
delete BODYS._id;
delete BODYS.isDefault;
const MODEL = this.findOneAndUpdate({
_uid,
'addresses._id': _id
}, {
$set: {...objToQuery(BODYS, 'addresses')
}
}, {
fields: 'addresses default_id -_id'
});
try {
// 修改数据
const DATAS = await MODEL;

// 修改默认
!!isDefault && await this.setDefault(_uid, isDefault, _id);
return !!DATAS.addresses.length
} catch (error) {
console.log(error)
return error
}
},
// 設置默認
setDefault: async function(_uid, isDefaults, _id) {
const default_id = !!isDefaults ? _id : '';
const MODEL = this.findOneAndUpdate({ _uid }, { default_id });
try {
const MB = await MODEL;
return MB
} catch (error) {
console.log(error);
return error
}
},
// 获取单一地址
getOne: async function(_uid, _id) {
const MODEL = this.findOne({
_uid,
}, {
'addresses': {
'$elemMatch': {
_id
}
}
}, {
fields: 'addresses default_id -_id'
});
console.log(_id)
try {
if (_id !== "default") {
const DATAS = await MODEL;
return DATAS.addresses[0]
}
} catch (error) {
console.log(error)
return error
}
},
// 获取全部地址
getAllAddress: async function(_uid, query) {
const MODEL1 = this.findOneAndUpdate({ _uid }, { _uid, query }, { new: true, upsert: true, fields: 'addresses default_id -_id' });
// const MODEL2 = this.create({ _uid })
try {
const DATAS = await MODEL1;
return DATAS
// console.log(!!DATAS._uid)
// return DATAS._uid ? DATAS.addresses : (await MODEL2).addresses
} catch (error) {
console.log(error)
return error
}
},
// 獲取默認地址
getDefaultAddress: async function(_uid) {
const MODEL = this.findOne({ _uid }, {}, {
fields: 'default_id -_id'
});
try {
const { default_id } = await MODEL;
return await this.getOne(_uid, default_id)
} catch (error) {
console.log(error);
return error
}
}
}
return mongoose.model('user_address', UserAddressSchema);
}
controller/user/address (RESTful 風格)
const indexController = require('../index');
class invoiceAddressController extends indexController {
constructor(ctx) {
super(ctx);
this.MODEL = ctx.model.User.Address;
};
/**
* @name 获取所有用户地址列表
*
*/
async index() {
const ctx = this.ctx;
const isDefault = Object.keys(ctx.query).includes('default');
const RESULT = !!isDefault ?
await this.MODEL.getDefaultAddress(ctx._uid()) :
await this.MODEL.getAllAddress(ctx._uid());
ctx.body = RESULT
};
/**
* @name 获取用户地址列表
*/
async show() {
const ctx = this.ctx;
const RESULT = await this.MODEL.getOne(ctx._uid(), ctx.params.id);
ctx.body = RESULT
};
/**
* @name 创建地址
*/
async create() {
const ctx = this.ctx;
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag
})
const RESULT = await this.MODEL.addAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 更新
*
*/
async update() {
const {
ctx
} = this;
const _id = ctx.params.id
const {
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action
} = ctx.request.body;
const BODYS = this.DUFN({
name,
phone,
postcode,
Region,
RegionId,
location,
isDefault,
tag,
action,
_id
})
const RESULT = action === 'setDefault' ?
await this.MODEL.setDefault(ctx._uid(), isDefault, _id) :
await this.MODEL.updateAddress(ctx._uid(), BODYS);
ctx.body = RESULT
};
/**
* @name 删除
*/
async destroy() {
const ctx = this.ctx;
const RESULT = await this.MODEL.deleteAddress(ctx._uid(), ctx.params.id);
ctx.body = RESULT
}
}
module.exports = invoiceAddressController
router.js
router.resources('user_address', '/user/address', app.jwt, controller.user.address);

egg-jwt配置

Nodejslopo1983 发表了文章 • 0 个评论 • 2079 次浏览 • 2019-08-30 18:00 • 来自相关话题

1. 安裝npm i egg-jwt --save
 
2.config/config.default config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};
 
3.config/pluginexports.jwt = {
enable: true,
package: "egg-jwt"
};
 4.service/apps/jwt.jsclass jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService5.使用class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/contextmodule.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取 查看全部
1. 安裝
npm i egg-jwt --save

 
2.config/config.default
    config.jwt = {
secret: appInfo.name + '_1539582326426_4353',
unless: {
path:
}
};

 
3.config/plugin
exports.jwt = {
enable: true,
package: "egg-jwt"
};

 4.service/apps/jwt.js
class jwtService extends Service {
constructor(ctx) {
super(ctx)
};
// jwt 加密 使用HS256
/**
*
* @param {Object} parmas 需封装的参数
* @param {String} type 类型 default:'web' ->24hrs
* @param {Boolean} expires 是否设置过期 default:true
*/
async sign(parmas, type = 'web', expires = true) {
const app = this.app;
return await app.jwt.sign({ ...parmas }, app.config.jwt.secret, { algorithm: 'HS256', ...(expires && { expiresIn: `${type === 'web' ? '24 hrs' : '30 days'}` }) })
}
// JWT 解密
async verify(token) {
const { app } = this;
return await app.jwt.verify(token, app.config.jwt.secret, { algorithm: 'HS256' })
}
}
module.exports = jwtService
5.使用
class weChatTemplateService extends indexService {
constructor(ctx) {
super(ctx);
this.userMODEL = ctx.model.Account.User;
this.tokenSERVICE = ctx.service.account.jwt
};
...
setToken(params, other) {
return { 'token': this.tokenSERVICE.create(params), ...other }
};
...
}
6.鑒權
egg-jwt已经封装了verify 不需要再做 verify
获取token 数据 使用 this.ctx.state.user 获取
亦可在context封装鉴权
/extend/context
module.exports = {
isAdmin() {
return this.state.user.group === 1 ? false : true;
},
_uid() {
return this.state.user._id
}
};
在controller 下面可以直接用
ctx.isAdmin() ctx._uid() 来获取

eggjs 设置跨域

Nodejslopo1983 发表了文章 • 0 个评论 • 1700 次浏览 • 2019-08-30 17:57 • 来自相关话题

1.egg-corsnpm install egg-cors --save2.config/plugin.jsexports.cors: {
enable: true,
package: 'egg-cors'
}3.config/config.default.jsconfig.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
}; 查看全部
1.egg-cors
npm install  egg-cors --save
2.config/plugin.js
exports.cors: {
enable: true,
package: 'egg-cors'
}
3.config/config.default.js
config.security = {
  csrf: {
    enable: false
  },
  domainWhiteList: [ '*' ]
};

config.cors = {
origin: '*',
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS'
};

eggjs 上传文件

Nodejslopo1983 发表了文章 • 0 个评论 • 2773 次浏览 • 2019-08-30 17:52 • 来自相关话题

'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController 查看全部
'use strict';
const Controller = require('egg').Controller;
// 文件存储
const fs = require('fs');
const path = require('path');
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');

class UploadController extends Controller {
/**
*
* @param {*} stream 传入的Buffer流
* @param {*} paths 保存的路径
* @param {*} multiple 是否多文件
* @param {*} files 多文件返回
*/
async upload(stream, paths = "app/public/img", multiple = false, files = []) {
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
const target = path.join(this.config.baseDir, paths, filename);
const writeStream = fs.createWriteStream(target);
try {
await awaitWriteStream(stream.pipe(writeStream));
return !!multiple ? files.push(filename) : filename;
} catch (err) {
await sendToWormhole(stream);
return { code: 422, message: '上传失败,请重试!' }
}
};
// 单文件
async create() {
const ctx = this.ctx;
// 获取流
const stream = await ctx.getFileStream();
// 生成文件名
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe流写入信息
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
// 保存失败销毁stream 不然接口会pending到超时
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
this.ctx.body = {
data: filename
};
};
// 多文件
async creates() {
const ctx = this.ctx;
// 获取文件流组
const streams = ctx.multipart();
let stream;
// 保存返回的文件信息
let files = [];
// 其他form 参数
let fields = {}
while ((stream = await streams()) != null) {
// 检查是否有其他参数 如果有写入 这里做案例 不做处理
if (stream.length) {
fields[stream[0]] = stream[1]
} else {
// 空文件处理
if (!stream.filename) {
return;
}
// 设置文件名称
const filename = Math.random().toString(36).substr(2) + new Date().getTime() + path.extname(stream.filename).toLocaleLowerCase();
// pipe 设置
const target = path.join(this.config.baseDir, 'app/public/img', filename);
const writeStream = fs.createWriteStream(target);
try {
// 保存
await awaitWriteStream(stream.pipe(writeStream));
// 写入数组
files.push({ filename, path: `/img/${filename}` })
} catch (err) {
await sendToWormhole(stream);
this.ctx.body = { code: 422, message: '上传失败,请重试!' }
throw err;
}
}
}
this.ctx.body = {
data: { files, fields }
};
}
}

module.exports = UploadController