‘编程学习’ 分类下的所有文章
20167 月25

Maven:下载慢的解决办法

C:\Windows\System32\drivers\etc\hosts

151.101.24.215 repo.maven.apache.org

20167 月4

Nginx:配置静态资源304缓存

location ~ \.(jpg|png|jpeg|gif)$  {
        expires 30d;
        root   /data/www/wizzer.cn/;
}

location ~ \.(js|css)$  {
        expires 2h;
        root   /data/www/wizzer.cn/;
}
20166 月13

Docker:部署Node.js项目

 

Dockerfile:

FROM node:6.2
# Author
MAINTAINER wizzer "wizzer@qq.com"
ENV PORT 1337
RUN apt-get update && apt-get install -y \
		imagemagick \
	--no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN mkdir -p /node/nodeshop
WORKDIR /node/nodeshop

RUN npm config set registry https://registry.npm.taobao.org
RUN npm i node-gyp -g
RUN npm i pm2 -g
ADD api /node/nodeshop/api
ADD assets /node/nodeshop/assets
ADD config /node/nodeshop/config
ADD tasks /node/nodeshop/tasks
ADD views /node/nodeshop/views
ADD app.js /node/nodeshop
ADD Gruntfile.js /node/nodeshop
ADD package.json /node/nodeshop
RUN npm i
EXPOSE ${PORT}
ENV LANG C.UTF-8
ENV TZ "Asia/Shanghai"
VOLUME ["/node/nodeshop/cert", "/node/nodeshop/upload", "/node/nodeshop/backup"]
CMD [ "pm2", "start", "--no-daemon", "app.js" ]

docker-compose.yml:

redis:
  image: redis
db:
  image: mariadb:5.5
  environment:
    "MYSQL_ROOT_PASSWORD": "xxxxxx"
    "MYSQL_DATABASE": "db123"
  command: "mysqld --character-set-server=utf8"
  ports:
    - "127.0.0.1:3306:3306"
  volumes:
    - "/node/nodeshop/db:/var/lib/mysql"
web:
  image: wizzer/nodeshop
  links:
    - redis
    - db
  environment:
    "MYSQL_HOST": "db"
    "MYSQL_USER": "root"
    "MYSQL_PASSWORD": "xxxxxx"
    "MYSQL_DATABASE": "db123"
    "MYSQL_LIMIT": 150
    "REDIS_HOST": "redis"
    "REDIS_PASS": ""
    "LOG_LEVEL": "verbose"
    "PORT": 1337
    "NODE_ENV": "development"
  command: "pm2 start /node/nodeshop/app.js --no-daemon"
  ports:
    - "1337:1337"
  volumes:
    - "/node/nodeshop/cert:/node/nodeshop/cert"
    - "/node/nodeshop/upload:/node/nodeshop/upload"
    - "/node/nodeshop/backup:/node/nodeshop/backup"

说明:
1、把数据库端口3306映射到127.0.0.1:3306 是为了还原数据库,web映射端口不绑定IP这样外网可以访问,通过nginx代理出去.
2、volumes将数据文件、数据库文件使用容器外文件夹,这样重启后不丢失数据.

1、打包最新image
docker build -t wizzer/nodeshop .

. 为当前文件夹,通过Dockerfile打包
wizzer/nodeshop:v1.0 用户名/项目:版本号

docker images 列出所有镜像
docker rmi ID 删除某个镜像
docker ps -a 列出所有容器
docker rm ID 删除某个容器
2、Centos安装Docker-engine 1.7.1版本(windows安装docker-toolbox即可)

vi /etc/yum.repos.d/docker.repo

[dockerrepo]
name=Docker Repository
baseurl=https://yum.dockerproject.org/repo/main/centos/6/
enabled=1
gpgcheck=1
gpgkey=https://yum.dockerproject.org/gpg

yum search docker
yum install docker-engine.x86_64
service docker start 启动docker服务
chkconfig docker on 设置为开启启动

3、Centos安装docker-compose 1.1.0版本(windows安装docker-toolbox即可)

curl -L https://github.com/docker/compose/releases/download/1.7.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

ps:第一行命令复制会少符号,到 https://github.com/docker/compose/releases/ 复制命令。

4、迁移镜像
docker ps -a 列出容器快照
docker export ID > nodeshop.tar 将容器快照导出
cat /node/nodeshop.tar | docker import – wizzer/nodeshop 加载容器快照

5、创建运行目录
分别创建4个文件夹【必须】
/node/nodeshop/cert 将证书文件拷贝进去
/node/nodeshop/upload 附件上传文件夹
/node/nodeshop/backup 数据库备份文件夹
/node/nodeshop/db 数据库文件夹
将Dockfile 、 docker-compose.yml 拷贝到 /node/nodeshop 目录

6、启动项目

cd /node/nodeshop
docker-compose up -d

docker-compose ps 列出正在运行的服务
docker-compose stop 停止服务
docker ps -a 列出所有容器状态
docker rm ID 删除容器

若要修改环境变量,可以修改 /node/nodeshop/docker-compose.yml 文件内容

7、安装mariadb客户端(用于连接数据库)

cd /etc/yum.repos.d/
vi MariaDB.repo

[mariadb]
name = MariaDB
baseurl = http://yum.mariadb.org/5.5/centos6-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1

yum install MariaDB-client

MariaDB-server 不需要安装

8、还原数据

mysql -h 127.0.0.1 -u root -p
密码
show databases;
use nodeshop;
source /node/nodeshop/db.sql;
show tables;
exit;

9、重启docker容器

docker-compose stop
docker-compose start

10、进入容器执行命令,比如测试网络情况

docker ps -a
docler exec -it ID /bin/bash
ping 192.168.1.11
exit

如果网络不通,可能需要关闭防火墙,然后重启docker服务:

service docker restart

11、容器开机自启动

vi /etc/rc.d/rc.local
/usr/local/bin/docker-compose -f /node/sunshop/docker-compose.yml up -d

注意:如果是centos7 则需要执行 chmod +x /etc/rc.d/rc.local 添加执行权限.

 


本教程适用于Centos6.x版本,7或有不同。

20165 月24

Node.js:集成apidoc

本文基于Sails.js MVC框架
一、安装

npm i apidoc -save
npm i grunt-apidoc -save

二、配置

package.json

增加配置项

"apidoc": {
  "title": "Sunshop"
},

tasks/config/apidoc.js

/**
 * Created by wizzer on 2016/5/24.
 */
module.exports = function (grunt) {
  grunt.config.set('apidoc', {
    myapp: {
      src: "api/controllers/api",
      dest: "apidoc/",
      options: {
        includeFilters: [ ".*\\.json$" ]
      }
    }
  });
  grunt.loadNpmTasks('grunt-apidoc');
};

tasks/register/compileAssets.js

module.exports = function (grunt) {
	grunt.registerTask('compileAssets', [
		'clean:dev',
		'jst:dev',
		'less:dev',
		'copy:dev',
		'coffee:dev',
    'apidoc:myapp' // <-- apidoc
	]);
};

 

api/controllers/api/oauth.json  一个API文档示例,详细参数见apidoc官网。

/**
 * @api {POST} /api/oauth/token Token
 * @apiName Token
 * @apiGroup Oauth
 * @apiVersion 1.0.0
 * @apiDescription 获取Token
 * @apiPermission anyone
 *
 * @apiParam {string} client_id client_id
 * @apiParam {string} client_secret client_secret
 *
 * @apiParamExample {json} 示例
 *   POST /api/oauth/token
 *   {
 *      "client_id": "client_id",
 *      "client_secret": "client_secret"
 *   }
 *
 * @apiSuccess (成功) {number} code 0
 * @apiSuccess (成功) {string} msg success
 * @apiSuccess (成功) {Object} data Token对象
 * @apiSuccess (成功) {string} data.token Token
 * @apiSuccess (成功) {number} data.expires 失效时间(24小时)请保存若失效重新获取
 * @apiSuccess (成功) {number} data.appid AppId
 * @apiSuccessExample {json} 示例
 *   HTTP/1.1 200 OK
 *   {
 *     "code": 0,
 *     "msg": "success",
 *     "data": {
 *       "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOjIsImV4cCI6MTQ2NDE1NjA2OTg3Nn0.4i_o7gCjCKvOImSi4peCMgCUrzpdgbtmvMECKf5wkqE",
 *       "expires": 1464156069876,
 *       "appid": 2
 *     }
 *   }
 *
 * @apiError (失败) {number} code 1:client_id不存在 2:client_id禁用 3:client_secret错误 4:参数错误
 * @apiError (失败) {string} msg 错误文字描述
 * @apiErrorExample {json} 示例
 *   HTTP/1.1 200 OK
 *   {
 *     "code": 1
 *     "msg": "client_id has error"
 *   }
 */

框架配置静态目录,让其可访问:
config/http.js

customMiddleware: function (app) {
    app.use('/apidoc', require('express')['static'](require('path').normalize(__dirname + '/../apidoc')));
},
20165 月18

Node.js 企业级开发框架

基于Sails.js MVC框架,路由自动映射,完善的权限控制体系,优美的后台界面。

集成最基础的通用功能:

系统(机构管理、用户管理、角色管理、菜单管理、定时任务、数据库备份、IP访问控制、登录日志等)

CMS(站点管理、栏目管理、内容管理、广告及链接等)

微信(会员列表、微信消息、群发消息、自动回复、关键词回复、帐号配置、菜单配置等)

 

演示地址:http://www.nodeshop.cn

联系方式:QQ  1162-4317   (备注nodejs)

 

界面截图:

QQ截图20160518095645

2

20165 月4

Node.js:集成QQ信任登录

1、申请AppId、AppKey和验证字符串

http://connect.qq.com/manage/login

网站首页头文件添加验证字符串,如:

<meta property=”qc:adminscontent=”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号,测试可以正常登录后提交申请,否则肯定是不通过的。

 

20163 月2

Node.js 商城系统开发进展

商品规格、会员价、商品相册、图片缩放、二维码等等,用其他语言实现起来可能比较简单的功能,用node.js 实现起来,毕竟全靠自己摸索,花了好多时间,,好在做好了,泪奔。。

 

1 2 3 4

201512 月20

Nginx+Tomcat负载均衡、绑定多域名、设置开机启动的安装步骤

1、JDK安装
/data1/soft/java/
>>chmod 777 jdk-6u45-linux-x64-rpm.bin
>>jdk-6u45-linux-x64-rpm.bin
>>gedit /etc/profile
JAVA_HOME=/data1/soft/java/jdk1.6.0_45

CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

PATH=$JAVA_HOME/bin:$PATH
export JAVA_HOME
export CLASSPATH
export PATH
>>source /etc/profile

2、TOMCAT安装
将原windows系统中的tomcat主要文件拷贝到linux(conf、lib、bin),并新建空文件夹(logs、temp、work)
/data1/soft/tomcat1 多网站的那个tomcat
/data1/soft/tomcat2 少网站的那个tomcat
分别修改两个tomcat下的server.xml文件,将项目路径分别替换为 /data1/www/websties1 和 /data1/www/websties2
>>/data1/soft/tomcat/bin/startup.sh //启动tomcat
>>/data1/soft/tomcat/bin/shutdown.sh //停止tomcat

开机启动:
http://jingyan.baidu.com/article/6525d4b1382f0aac7d2e9421.html
【tomcat1、tomcat2分别设置为启动项】
除了百度经验之外,要在catalina.sh 里加上下面三行,否则在自启动的时候找不到jdk
export JAVA_HOME=/data1/soft/java/jdk1.6.0_45
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH

3、Nginx安装
>>rpm -ivh http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm
>>yum -y install nginx
通过命令安装后
配置文件:/etc/nginx/nginx.conf
域名配置:/etc/nginx/conf.d/ 一个域名一个配置文件,不要的域名可以备份后删除

server {
listen 80;
server_name test.wizzer.cn;
location / {
proxy_pass http://test.wizzer.cn:8101;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

日志文件路径:/var/logs/nginx
服务启动或通知
>>service nginx stop
>>service nginx start
设置为随机启动
>>chkconfig nginx on

4、Nginx代理权限设置
若通过域名+端口号可访问,但80端口显示 502 Bad Gateway ,日志/var/logs/nginx/error.log报
2015/12/19 18:02:03 [crit] 9978#0: *8 connect() to 61.132.139.155:8101 failed (13: Permission denied) while connecting to upstream, client: 124.73.13.21, server: test.wizzer.cn, request: “GET / HTTP/1.1”, upstream: “http://61.132.139.155:8101/”, host: “test.wizzer.cn”
则需要设置selinux权限(宽容模式):
>>setenforce 0
>>setsebool -P httpd_can_network_connect 1

5、防火墙配置
>>vi /etc/sysconfig/iptables
#########################################################
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state –state NEW -m tcp -p tcp –dport 21 -j ACCEPT
-A INPUT -m state –state NEW -m tcp -p tcp –dport 22 -j ACCEPT
-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT
-A INPUT -j REJECT –reject-with icmp-host-prohibited
-A FORWARD -j REJECT –reject-with icmp-host-prohibited
COMMIT
#########################################################

>>/etc/init.d/iptables restart #重启防火墙使配置生效,或者命令 service iptables restart

201512 月15

LNMP:Nginx+PHP Ci框架配置注意事项

CodeIgniter

php.ini  修改:

cgi.fix_pathinfo=1

 

nginx/vhost/ 域名配置:

 

server {
listen 80;
server_name www.wizzer.cn wizzer.cn;
root “/data/www/www.wizzer.cn”;
location / {
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?$1 last;
break;
}
}
location ~ \.php(.*)$ {
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
}

201510 月27

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

201510 月16

jquery.datatables 使用方法:Ajax分页、字段排序、传递参数等

1

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": []
        });
      }
    });
  },
20159 月12

CentOS:6.5防火墙设置开放端口

1) 打开端口
vi /etc/sysconfig/iptables

-A INPUT -m state –state NEW -m tcp -p tcp –dport 80 -j ACCEPT
注意:新开放的端口一定要在端口22后面

重启防火墙使配置生效
/etc/init.d/iptables restart

查看开放端口
/etc/init.d/iptables status

1) 永久性生效,重启后不会复原

开启: chkconfig iptables on

关闭: chkconfig iptables off

2) 即时生效,重启后复原

开启: service iptables start

关闭: service iptables stop

20159 月11

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));
    });

 

20159 月10

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));

20159 月9

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

20156 月8

Centos:安装mysql

# yum update
# yum search mysql

# yum list mysql
# yum list mysql-server

# yum install mysql
# yum install mysql-server

运行命令chkconfig –levels 235 mysqld on使MySQL服务可以自动启动,并使用命令/etc/init.d/mysqld start立刻启动MySQL服务

设置MySQL的root密码,运行命令/usr/bin/mysqladmin -u root password ‘new-password’,其中’new-password’是新设的密码,如123456

 

20156 月4

WSO2:配置webservice代理 地址不对的问题

Home > Manage > Services > List

选择配置的代理名,点击 Transports 进入菜单

Home > Manage > Services > List > Service Dashboard > Transport Management

选中一个协议,比如http 配置 hostname参数 ,设置为ip地址

 

QQ截图20150604143348

20155 月18

Activiti:获取节点走向

 @At
    public String test5(@Param("taskId") String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null)
            return "null";
        ProcessDefinitionEntity def = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService).getDeployedProcessDefinition(task.getProcessDefinitionId());
        List<ActivityImpl> activitiList = def.getActivities();
        System.out.println("getTaskDefinitionKey:::" + task.getTaskDefinitionKey());
        NutMap map = new NutMap();
        int type = 0;
        getTaskActivitys(task.getTaskDefinitionKey(), activitiList, type, map);
        return Json.toJson(map);
    }

    public static List<PvmActivity> getTaskActivitys(String activityId, List<ActivityImpl> activityList, int type, NutMap map) {
        List<PvmActivity> activitiyIds = new ArrayList<>();
        for (ActivityImpl activityImpl : activityList) {
            String id = activityImpl.getId();

            if (activityId.equals(id)) {
                List<PvmTransition> outgoingTransitions = activityImpl.getOutgoingTransitions();//获取某节点所有线路
                List<NutMap> list = new ArrayList<>();
                for (PvmTransition tr : outgoingTransitions) {
                    NutMap map1 = new NutMap();
                    PvmActivity ac = tr.getDestination();//获取线路的终点节点
                    if (ac.getProperty("type").equals("userTask")) {
                        map.setv("type", type++);
                        map1.setv("id", ac.getId());
                        map1.setv("name", ac.getProperty("name"));
                        String conditionText=Strings.sNull(tr.getProperty("conditionText"));
                        if(!Strings.isEmpty(conditionText)){
                            map1.setv("conditionText",conditionText );
                        }
                        list.add(map1);
                    } else if (ac.getProperty("type").equals("exclusiveGateway")) {
                        getTaskActivitys(ac.getId(), activityList, type, map);
                    } else {
                        map.setv("type", type++);
                        break;
                    }
                }
                if (list.size() > 0)
                    map.addv("list", list);
                break;
            }
        }
        return activitiyIds;
    }
20155 月12

Nutz:集成CXF webservice

通过配置文件实现(这个支持CXF spring注解)点这里

pom.xml

	<!--CXF START-->
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-api</artifactId>
            <version>2.7.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>2.7.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-bindings-soap</artifactId>
            <version>2.7.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>2.7.15</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-ws-security</artifactId>
            <version>2.7.15</version>
        </dependency>
        <!--CXF END-->

web.xml

    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <servlet-class>com.auto.webservice.servlet.CXFServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/webservice/*</url-pattern>
    </servlet-mapping>
CXFServlet.java:
package com.auto.webservice.servlet;

import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.nutz.ioc.Ioc;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;

import javax.jws.WebService;
import javax.servlet.ServletConfig;
import javax.xml.namespace.QName;

/**
 * Created by wizzer on 15-4-10.
 */
@SuppressWarnings("serial")
public class CXFServlet extends CXFNonSpringServlet {
    private final Log log = Logs.get();

    @Override
    protected void loadBus(ServletConfig sc) {
        super.loadBus(sc);

        //全局配置
        Bus bus = getBus();
        //添加白名单过滤器
        bus.getInInterceptors().add(new IpAddressInInterceptor());
        //使用全局配置
        BusFactory.setDefaultBus(bus);
        Ioc ioc = Mvcs.ctx().getDefaultIoc();
        for (String name : ioc.getNames()) {
            try {
                Object obj = ioc.get(null, name);
                if (!obj.getClass().getPackage().getName().equals("com.auto.webservice.server")) {
                    continue;
                }
                if (obj.getClass().getAnnotation(WebService.class) == null)
                    continue;
                Class face = Class.forName(obj.getClass().getPackage().getName() + "." + Strings.upperFirst(name));
                ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
                // 设置服务接口类
                serverFactoryBean.setServiceClass(face);
                // 服务请求路径
                serverFactoryBean.setAddress("/" + name.substring(0, name.indexOf("Service")));
                // 设置服务实现类
                serverFactoryBean.setServiceBean(obj);
                serverFactoryBean.setBindingId("http://schemas.xmlsoap.org/wsdl/soap12/");
                serverFactoryBean.create();
            } catch (Throwable e) {
            }
        }


    }
}

接口类

WorkflowService.java
package com.auto.webservice.server;

import org.nutz.json.Json;

import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wizzer on 15-4-13.
 */
@WebService
public interface WorkflowService {
    String start(String flowKey, String userId);//启动流程

}

 

实现类

WorkflowServiceImpl.java

 

package com.auto.webservice.server;

import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.StartFormData;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.Mvcs;

import javax.jws.WebService;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wizzer on 15-4-13.
 */
@IocBean(name = "workflowService")
@WebService
public class WorkflowServiceImpl implements WorkflowService {
    private final Log log = Logs.get();
    @Inject
    Dao dao;
    @Inject
    FormService formService;
    @Inject
    IdentityService identityService;
    @Inject
    RepositoryService repositoryService;
    @Inject
    RuntimeService runtimeService;
    @Inject
    TaskService taskService;

    /**
     * 启动一个流程
     *
     * @param flowKey 流程模型key
     * @param userId  用户ID
     * @return
     */
    public String start(String flowKey, String userId) {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            if (!Strings.isEmpty(userId)) {
                identityService.setAuthenticatedUserId(userId);
            }
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(flowKey);
            map.put("errcode", 0);
            map.put("errmsg", "");
            map.put("processInstanceId", processInstance.getId());
        } catch (Exception e) {
            log.error("WebServcice启动流程出错", e);
            map.put("errcode", 1);
            map.put("errmsg", e.getMessage());
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return Json.toJson(map, JsonFormat.compact());
    }


}

 

20155 月7

Nutz:随笔01

在nutz filter作用域内才能Mvcs.getIoc()

其他情况:

Mvcs.ctx().getDefaultIoc().get(xxx.class)