Node.js:集成QQ信任登录
1、申请AppId、AppKey和验证字符串
http://connect.qq.com/manage/login
网站首页头文件添加验证字符串,如:
<meta property=”qc:admins” content=”765754250763563070636” />
填写回调地址:
必须是公网地址,可以填写多个,注意 /xxx 和 http://wizzer.cn/xxx 是两个地址,两个都需要配置。
2、开发完成
登录页面:
<span id=”qqLoginBtn”></span>
<script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="<%=qq_appid||''%>" data-redirecturi="<%=req.baseUrl%>/public/shop/pc/account/oauthQq" charset="utf-8" ></script> <script type="text/javascript"> QC.Login({ btnId:"qqLoginBtn", //插入按钮的节点id scope: "get_user_info" },function(oInfo, oOpts){ //登陆成功执行 var nickname=QC.String.escHTML(oInfo.nickname);//获取QQ会员名 var info={ nickname:nickname, gender:oInfo.gender, headimgurl:oInfo.figureurl_qq_1 //头像40X40 };//封装对象 if(QC.Login.check()){ QC.Login.getMe(function(openId, accessToken){ info.openid=openId;//传递openid及昵称头像等,业务逻辑自动注册会员或登录 $.post( "/public/shop/pc/account/oauthQqStatus", info, function(result){ console.log(result); if(result.code==0){ window.location.href=$("#r").val()||'/member';//登录成功跳转 }else{ alert('登录失败'); } },'json' ); }); } });</script>
回调页面:
<script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" charset="utf-8" data-callback="true"></script>
退出登录:
<%if(sails.config.system.ShopConfig.oauth_open&&sails.config.system.ShopConfig.pay_wxpay&&sails.config.system.ShopConfig.oauth_qq){ var qq_appid=''; if(sails.config.system.ShopConfig.oauth_qq_info){ qq_appid=sails.config.system.ShopConfig.oauth_qq_info.qq_appid; } %> <script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="<%=qq_appid||''%>" data-redirecturi="http://<%=sails.config.system.AppDomain%>/public/shop/pc/account/oauthQq" charset="utf-8" ></script> <script type="text/javascript"> QC.Login.signOut(); if(QC.Login.check()==false){ window.location.href='/public/shop/pc/account/logout';//先QQ登出,再清除session }else{ window.location.reload(); } </script> <%}else{%> <script type="text/javascript"> window.location.href='/public/shop/pc/account/logout'; </script> <%}%>
3、申请审核
审核条件:登录页面有QQ登录图标、使用申请的QQ或测试QQ号,测试可以正常登录后提交申请,否则肯定是不通过的。
Node.js 商城系统开发进展
Node.js:集成百度编辑器的上传功能
Ueditor1.4.3.1版本,仅贴了图片上传代码,其他自己加。。。
/** * Created by root on 11/16/15. */ var fs = require('fs-extra'); var moment = require("moment"); module.exports = { index: function (req, res) { if (req.session.auth && !req.session.user.disabled) { var action = req.query.action; //加载配置文件 fs.readFile(sails.config.appPath + '/assets/plugins/ueditor/node/config.json', 'utf8', function (err, config_txt) { var config = JSON.parse(config_txt); switch (action) { case 'config': return res.send(config_txt); break; case 'uploadimage': req.file('Filedata').upload({ maxBytes: config.imageMaxSize }, function (err, uploadedFiles) { if (err)return res.json({state: sails.__('file.upload.err')}); var filename = uploadedFiles[0].filename; var type = uploadedFiles[0].type; var fd = uploadedFiles[0].fd; var size = uploadedFiles[0].size; console.log('uploadimage:::' + JSON.stringify(uploadedFiles)); if(config.imageAllowFiles.indexOf(fd.substring(fd.lastIndexOf('.')))<0) return res.json({state: sails.__('file.upload.err')}); var file = fd.substring(fd.lastIndexOf('/')); var newPath = sails.config.system.AppBase + sails.config.system.UploadPath + "/image/" + moment().format("YYYYMMDD") + file; fs.copy(fd, sails.config.appPath + newPath, function (err) { if (err)return res.json({state: sails.__('file.upload.err')}); return res.json({state: 'SUCCESS', url: newPath, title: filename, original: filename, type: type, size: size}); }) }); break; } }); } else { return res.json({state: sails.__('private.forbidden'), url: '', title: '', original: '', type: '', size: 0}); } } };
Node.js:微信消息回复、推送的实现
适应场景:Sails框架、微信公众号数据配置在数据库中,支持多个公众号。
1、Model定义(Waterline)
文件路径:/api/models/wx/Wx_config.js
/** * Created by root on 10/25/15. */ var moment = require('moment'); module.exports = { schema: true, autoCreatedAt: false, autoUpdatedAt: false, attributes: { id: { type: 'integer', autoIncrement: true, primaryKey: true }, appname: { type: 'string', required: true }, ghid: {//原始ID type: 'string', unique: true, required: true }, appid: { type: 'string', unique: true, required: true }, appsecret: { type: 'string', unique: true, required: true }, encodingAESKey:{ type: 'string', unique: true, required: true }, token: { type: 'string', unique: true, required: true }, access_token: { type: 'string' }, expire_time: { type:'integer', defaultsTo:function(){ return 0; } }, createdBy:{ type: 'integer' }, createdAt:{ type:'integer', defaultsTo:function(){ return moment().format('X'); } } } };
2、Sails默认不支持微信xml post,改造之
文件路径:/config/http.js
rawParser: function(req, res, next) { switch(req.headers['content-type']) { case 'text/xml': require('body-parser').raw({ type: 'text/xml' })(req, res, next); break; default : next(); } }, order: [ 'startRequestTimer', 'cookieParser', 'session', 'myRequestLogger', 'rawParser', 'bodyParser', 'handleBodyParserError', 'compress', 'methodOverride', 'poweredBy', '$custom', 'router', 'www', 'favicon', '404', '500' ],
3、控制类
文件路径:/api/controllers/open/WeixinController.js
微信公众号后台配置路径:http://127.0.0.1/open/weixin/api?wxid=1
/** * Created by root on 10/25/15. */ module.exports = { api: function (req, res) { var id = req.query.wxid; Wx_config.findOne(id).exec(function (err, conf) { if (err)return res.send(200, 'fail'); if (req.body) { WeixinService.loop(req, function (data) { if (data.type = 'text') {//用户发送纯文本 var msg = {toUserName: data.openid, fromUserName: conf.ghid, content: 'Node.js Test...'}; WeixinService.sendTextMsg(res, msg);//向用户回复消息 } }); } //签名 if (WeixinService.checkSignature(req, conf.token)) { res.send(200, req.query.echostr); } else { res.send(200, 'fail'); } }); } };
4、微信服务工具类
文件路径:/api/services/WeixinService.js
/** * Created by root on 10/26/15. */ var sha1 = require('sha1'), xml2js = require('xml2js'); module.exports = { /** * 签名验证 * @param req * @param token * @returns {boolean} */ checkSignature: function (req, token) { var signature = req.query.signature, timestamp = req.query.timestamp, nonce = req.query.nonce, echostr = req.query.echostr; // 按照字典排序 var array = [token, timestamp, nonce]; array.sort(); // 连接 var str = sha1(array.join("")); // 对比签名 return str == signature; }, /** * 监听用户消息 * @param req * @param callback */ loop: function (req, callback) { var body = req.body.toString('utf-8'); var data = {}; xml2js.parseString(body, function (err, json) { if (err) { } else { console.log('json::' + JSON.stringify(json)); data.type = json.xml.MsgType; data.openid = json.xml.FromUserName; if (data.type == 'text') { data.txt = json.xml.Content; } else if (data.type == 'image') { data.pic = json.xml.PicUrl; } return callback(data); } }); }, /** * 发送文本消息 * @param res * @param msg */ sendTextMsg: function (res, msg) { var time = Math.round(new Date().getTime() / 1000); var funcFlag = msg.funcFlag ? msg.funcFlag : 0; var output = "" + "<xml>" + "<ToUserName><![CDATA[" + msg.toUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + msg.fromUserName + "]]></FromUserName>" + "<CreateTime>" + time + "</CreateTime>" + "<MsgType><![CDATA[text]]></MsgType>" + "<Content><![CDATA[" + msg.content + "]]></Content>" + "<FuncFlag>" + funcFlag + "</FuncFlag>" + "</xml>"; res.type('xml'); res.send(output); }, /** * 发送图文消息 * @param res * @param msg */ sendNewsMsg: function (res, msg) { var time = Math.round(new Date().getTime() / 1000); var articlesStr = ""; for (var i = 0; i < msg.articles.length; i++) { articlesStr += "<item>" + "<Title><![CDATA[" + msg.articles[i].title + "]]></Title>" + "<Description><![CDATA[" + msg.articles[i].description + "]]></Description>" + "<PicUrl><![CDATA[" + msg.articles[i].picUrl + "]]></PicUrl>" + "<Url><![CDATA[" + msg.articles[i].url + "]]></Url>" + "</item>"; } var funcFlag = msg.funcFlag ? msg.funcFlag : 0; var output = "" + "<xml>" + "<ToUserName><![CDATA[" + msg.toUserName + "]]></ToUserName>" + "<FromUserName><![CDATA[" + msg.fromUserName + "]]></FromUserName>" + "<CreateTime>" + time + "</CreateTime>" + "<MsgType><![CDATA[news]]></MsgType>" + "<ArticleCount>" + msg.articles.length + "</ArticleCount>" + "<Articles>" + articlesStr + "</Articles>" + "<FuncFlag>" + funcFlag + "</FuncFlag>" + "</xml>"; res.type('xml'); res.send(output); } };
Nodejs版本:0.12.7
Sails版本:0.11.0
require相关组件,记得安装。
参考项目1:https://github.com/node-webot/wechat-api
参考项目2:https://github.com/JeremyWei/weixin_api
jquery.datatables 使用方法:Ajax分页、字段排序、传递参数等
Html:
姓名状态是否在线操作
用户名 datatables初始化:
var datatable; function initDatatable() { datatable = $('.datatable').DataTable({ "processing": false, "serverSide": true, "select": true, "ordering": true, "language": { "url": "/plugins/datatables/cn.json" }, "preDrawCallback": function () { sublime.closeLoadingbar($(".main-content")); sublime.showLoadingbar($(".main-content")); }, "drawCallback": function () { sublime.closeLoadingbar($(".main-content")); }, "ajax": { "url": "/private/sys/user/data", "type": "post", "data": function (d) { d.unitid = $('#unitid').val(); d.loginname=$('#loginname').val(); d.nickname=$('#nickname').val(); } }, "order":[[0,"desc"]], "columns": [ {"data": "loginname", "bSortable": true}, {"data": "nickname", "bSortable": true}, {"data": "disabled", "bSortable": true}, {"data": "online", "bSortable": true} ], "columnDefs": [ { "render": function (data, type, row) { return 'html.....'; }, "targets": 4 }, { "render": function (data, type, row) { if (data) { return ''; } else { return ''; } }, "targets": 3 }, { "render": function (data, type, row) { if (!data) { return ''; } else { return ''; } }, "targets": 2 } ] }); datatable.on('click', 'tr', function () { $(this).toggleClass('selected'); }); $("#searchBtn").on('click',function(){ datatable.ajax.reload(null, false); }); }重新加载数据:
datatable.ajax.reload(null, false);//当前页 datatable.ajax.reload();//回到第一页排序:通过后台参数 order数组得到dir:asc/desc,通过order的column下标,获取columns数组中的data字段名,两者结合写排序条件
后台把所有参数打印出来,你就知道代码应该怎么写了……over响应的数据格式:
{ "draw": draw, "recordsTotal": pageSize, "recordsFiltered": count, "data": list }Nodejs 后端完整代码:
data: function (req, res) { var pageSize = parseInt(req.body.length); var start = parseInt(req.body.start); var page = start / pageSize + 1; var draw = parseInt(req.body.draw); var unitid = req.body.unitid || 1; var loginname = req.body.loginname || ''; var nickname = req.body.nickname || ''; var order = req.body.order || []; var columns = req.body.columns || []; var sort = {}; var where = {unitid: unitid}; if (loginname) { where.loginname = {'like':'%'+loginname+'%'}; } if (nickname) { where.nickname = {'like':'%'+nickname+'%'}; } if (order.length > 0) { sort[columns[order[0].column].data] = order[0].dir; } Sys_user.count(where).exec(function (err, count) { if (!err && count > 0) { Sys_user.find(where) .sort(sort) .paginate({page: page, limit: pageSize}) .exec(function (err, list) { return res.json({ "draw": draw, "recordsTotal": pageSize, "recordsFiltered": count, "data": list }); }); } else { return res.json({ "draw": draw, "recordsTotal": pageSize, "recordsFiltered": 0, "data": [] }); } }); },
Sails:Waterline多对多查询
Sys_user.js
module.exports = { schema: true, autoCreatedAt: false, autoUpdatedAt: false, attributes: { id: { type: 'integer', autoIncrement: true, primaryKey: true }, roles: { collection: 'Sys_role', via: 'users' } } };
Sys_role.js
users: { collection: 'Sys_user', via: 'roles' //dominant: true },
使用populate查询
Sys_role.findOne(1).populate('users').populate('menus').exec(function(err, role) { console.log(':::'+JSON.stringify(role.users)); console.log(':::'+JSON.stringify(role.menus)); });
Node:加盐salt密码验证
npm install bcrypt –save
var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync(‘pass’, salt);
console.log(‘加密::’+hash);
console.log(‘解密::’+bcrypt.compareSync(‘pass’,hash));
Node:搭建sails.js开发环境
友情提示:do not 在windows下开发node.js应用,否则你会浪费很多时间并且会pia撞墙的……
1.CentOS6.5 安装 nodejs 并配置到环境
———————————–
>>gedit /etc/profile
export NODE_HOME=/soft/node-v0.12.7-linux-x64
export PATH=$NODE_HOME/bin:$PATH
>>source /etc/profile
>>node -v
2.npm 设置为国内源
———————————–
>>npm config set registry https://registry.npm.taobao.org
3.安装必备模块 node-gyp (CentOS6.5 自带Python2.6.6)
———————————–
>>npm install node-gyp -g
4.安装WebStorm 并安装JDK7
———————————–
>>rpm -ivh jdk-7u79-linux-x64.rpm
>>gedit /etc/profile
JAVA_HOME=/usr/java/jdk1.7.0_79
CLASSPATH=.:$JAVA_HOME/lib.tools.jar
PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME CLASSPATH PATH
>>source /etc/profile
5.安装Git 并生成ssh密钥,github帐号设置中添加密钥
———————————–
>>yum install git
>>cd ~/.ssh
>>ssh-keygen -t rsa -C “wizzer@qq.com”
>>cat ~/.ssh/id_rsa.pub
>>git clone git@github.com:Wizzercn/nodeshop.git
>>git pull
>>git commit -am ‘note’
>>git push
6.验证码组件ccap,需安装python2.7
————————————
http://blog.csdn.net/tiantiandjava/article/details/17242345
>>npm install ccap –save