1. 如果装有防火墙,再将防火墙的端口打开(在LUM新版本中,可以配置防火墙)
2. 打开/usr/local/apache_LuManager/conf/httpd.conf
把里面的8888改掉成您所需的端口
3. 更改/usr/local/LuNamp/cmd/cron_common.sh文件,将其中的8888改成新的端口
4. 执行lum-restart重启LUM
5.删除/usr/local/LuManager/Runtime/下的缓存文件,这样访问后台就可以了
1. 如果装有防火墙,再将防火墙的端口打开(在LUM新版本中,可以配置防火墙)
2. 打开/usr/local/apache_LuManager/conf/httpd.conf
把里面的8888改掉成您所需的端口
3. 更改/usr/local/LuNamp/cmd/cron_common.sh文件,将其中的8888改成新的端口
4. 执行lum-restart重启LUM
5.删除/usr/local/LuManager/Runtime/下的缓存文件,这样访问后台就可以了
来源: ASP.NET MVC5+EF6+EasyUI 后台管理系统(55)-Web打印 – ymnets – 博客园
1.本次主要弥补工作流,用户表单数据的打印
2.使用JQprint做为web打印插件
3.兼容:FireFox,Chrome,IE、
4.没有依赖也没有配置,使用简单

(由于我本地没有打印机,所以弹出输出到传真和PDF,XPS,输出到PDF与打印结果其实是一致的)
引入相关JS
<script src="~/Scripts/jquery.min.js"></script> <script src="~/Scripts/jquery.jqprint-0.3.js"></script>
我这里使用的JQuery v1.11.3
<script language="javascript">
function Print(){
$("#setFormLayout").jqprint();
}
</script>
只需要指定打印内容的DIV,我上面表单是包含在ID为setFormLayout、
$("#printContainer").jqprint({
debug: false, //如果是true则可以显示iframe查看效果(iframe默认高和宽都很小,可以再源码中调大),默认是false
importCSS: true, //true表示引进原来的页面的css,默认是true。(如果是true,先会找$("link[media=print]"),若没有会去找$("link")中的css文件)
printContainer: true, //表示如果原来选择的对象必须被纳入打印(注意:设置为false可能会打破你的CSS规则)。
operaSupport: true//表示如果插件也必须支持歌opera浏览器,在这种情况下,它提供了建立一个临时的打印选项卡。默认是true
});

使用太过简单,jqprint源码也极其简洁易懂
来源: Force.com微信企业号开发系列(一) – 启用二次验证 – JohnsonWang – 博客园
微信于9月份推出企业号后引起了业界不小的反响,许多企业都在思索企业号将如何影响企业的运营,从本文开始,我将详细阐述微信企业号开发的相关知识,而本文将着重介绍如何实现更高安全机制的二次验证。
申请企业体验号:
企业号顾名思义就是企业来申请的号,申请时就像申请服务号一样,需要提供各种组织证明文件,对广大开发者来说很难操作,好在腾讯公司也像服务号一样开通了体验号申请,留意企业体验号的有效期间非常短,只有90天(服务号测试账号有1年有效期),且如果企业体验号长期不使用还会收到腾讯公司的提前失效提醒邮件。企业体验号的申请链接如下,开发者只需要按照腾讯公司的引导完成注册步骤,立刻就能获得体验号:
http://qydev.weixin.qq.com/try?t=experience
通讯录添加成员:
与公众号不同的是,因为是面向企业内部,所以腾讯允许企业主动添加粉丝,具体操作是进入到通讯录后点击+按钮添加新成员,留意作为唯一识别个人信息,微信号、手机号或者邮箱必须至少有一个,直接搜集微信号通常比较困难,一般可以使用企业HR数据库里的手机号和邮箱等信息,具体操作上除了手工添加还可以通过Excel模板导入以及通过腾讯企业号微信API来添加,关于API添加用户稍后章节介绍。
输入完成以后,可以将企业微信号的二维码发送给员工,员工扫描后会自动出现系统默认的企业号小助手,小助手会自动引导员工通过邮箱或手机验证码来完成员工身份绑定的过程,此为一次验证,企业自行确保通讯录员工数据的正确性,后续依赖于腾讯公司来进行员工验证,验证通过后通讯录状态列的问号会消失,表明一次验证通过:
启用二次验证:
一次验证通常能够满足大多数企业的要求,但对于员工信息以及权限管理比较严格的公司来说,一次验证还不足够放心,希望能够员工通过输入公司内部的用户名和密码再进行一次验证,此为二次验证,二次验证的启用位于企业号首页设置处,到设置画面后滚动画面找到二次验证,点击右侧的选择钮启用二次验证:
此时会弹出如下窗口需要输入企业的二次验证页面地址:
为此我们可以参考企业号官方接口文档http://qydev.weixin.qq.com/wiki/index.php?title=%E5%85%B3%E6%B3%A8%E4%B8%8E%E5%8F%96%E6%B6%88%E5%85%B3%E6%B3%A8在Force.com平台开发相应页面。
开发二次验证用页面:
同样,页面分成两个部分,一部分是显示部分,用来输入用户名和密码,页面示意图如下,用户输入用户名user以及密码123点击绑定按钮既可以完成绑定:
页面名称是EmployeeAuth,页面代码如下,有些属于apex代码特有的标签,无需做深入理解,重要是在第13行按钮的action属性指定了bind方法,当点击按钮的时候将调用控制器类EmployeeAuthController的bind方法:
1 <apex:page standardstylesheets="false" showHeader="false" sidebar="false" controller="EmployeeAuthController">
2 <font size="50">
3 <h1>Please input your user name and password</h1>
4 </font>
5 <font size="30">
6 UserName: user<br />
7 Password: 123<br /><br />
8 <hr/>
9 <apex:form >
10 UserName: <apex:inputText size="100" style="height:100px" value="{!strUsername}" id="strUsername"/><br /><br />
11 Password: <apex:inputText size="100" style="height:100px" value="{!strPassword}" id="strPassword"/><br /><br />
12 <center>
13 <apex:commandButton value="Bind" style="width:600px; height:100px;font-size:50px" action="{!bind}" id="bind" />
14 </center>
15 </apex:form>
16 {!msg}
17 </font>
18 </apex:page>
在解读EmployeeAuthController控制器类的代码前我们首先看看微信二次认证的步骤。
二次验证的步骤与机理:
1. 首先,当微信一次验证(或邮箱或手机号码等认证)完成后,微信会发送如下图所示的消息给到用户:
2. 页面跳转:
当用户点击这个图文的时候实际上打开了一个位于open.weixin.qq.com网站下面的网页,这个页面会做一些处理后跳转到前面在二次验证里设置的URL也就是我们正在开发的这个页面,在跳转的时候还会再我们设置的URL后面加上参数code=CODE&state=STATE,例如在本例里二次验证配置的URL是http://johnson0001-developer-edition.ap1.force.com/EmployeeAuth,那么从腾讯openweixin.qq.com跳转后实际打开的URL是http://johnson0001-developer-edition.ap1.force.com/EmployeeAuth?code=CODE&state=STATE 。这里的state参数是干嘛的腾讯公司并没有说明目前看也并不重要。重要的是code参数,利用这个参数可以调用腾讯的oauth2接口换取员工的userid,留意userid是一个很重要的概念,在企业号里没有微信OpenId一说,只有userid用来唯一标识用户,这个userid实际上就是我们在维护通讯录时的账号字段值:
3. 通过code调用腾讯oauth2接口换取员工userid
关于这个接口的说明参见腾讯文档http://qydev.weixin.qq.com/wiki/index.php?title=%E6%A0%B9%E6%8D%AEcode%E8%8E%B7%E5%8F%96%E6%88%90%E5%91%98%E4%BF%A1%E6%81%AF,也可以参加下方说明,这里需要特别说明的是access token和agentid:
做过微信公共号开发或者看过前面介绍相关开发文章的读者应该不会陌生,当主动调用腾讯的api时都需要access token已确保访问的正当性,获得access token相应的也有一个专门的接口,具体的介绍可以参见腾讯公司文档http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%BB%E5%8A%A8%E8%B0%83%E7%94%A8,简单点说获得access token实际就是通过以下接口:
https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=id&corpsecret=secrect
这个接口里Corpid好找,打开设置就能找到,如下图:
不过corpsecret就没那么好找,实际是需要系统管理员在后台创建管理组,创建管理组后就可以拥有相应的Secret,而这个Secret所拥有的访问权限就是系统管理员创建的管理组所拥有的权限,腾讯文章http://qydev.weixin.qq.com/wiki/index.php?title=Secret也有提到:
再回过头来说agentid腾讯文档里提到指的是“跳转链接时所在的企业应用ID”,在本例里其实指的就是发送“身份验证”图文消息的那个应用也就是“企业小助手”的应用ID,当然在不同的用户场景里可能会是不同的应用在调用换取userid接口,如何查看“企业小助手”的应用ID呢?进到应用中心,第一个就是企业小助手,点击进入就可以看到如下图所示的企业应用ID了:
4. 二次验证
拿到userid后实际就可以进行二次验证了,二次验证的方式有很多种,例如如果公司已经建立起良好的通讯录管理机制(userid等和企业人力资源数据库同步,入职离职员工均能和企业号通讯录同步),拿到userid后只要判断这个userid是一位在职员工就可以自动判断为二次验证通过,或者再保险点如本例演示的,要求员工输入公司的员工用户名和密码进行验证。留意,输入用户名和密码验证的页面也就是我们前面提到的二次验证页面是属于企业拥有也是企业开发的,这样就确保了企业对安全的控制,具体操作上,用户输入用户名和密码后企业可以调用已有的接口进行验证,如果验证成功则将员工的userid等信息保存在业务系统数据库中一遍后续操作。
5.通知腾讯关注成功
现在最后一步等企业在自己的网页里完成了用户验证后只剩下通知腾讯该用户已经验证成功让相应员工关注成功,此时应该调用如下接口,可以看到接口需要的第二个参数即是我们前面换回来的userid:
https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?access_token=ACCESS_TOKEN&userid=USERID
此接口的详细说明如下:
二次验证的代码实现:
按照前面的思路,我们首先获取从腾讯跳转过来的code,并通过code换取用户的userid,换取的这个过程在页面加载中完成,为此主要代码应放在类构造器里。下面的代码里设置了五个变量,其中strPassword和strUsername和用户在页面里输入的用户名和密码相对应,userID用来存储换回来的userid信息,msg用来调试帮助在页面里显示中间信息,accessToken则用来存储access token:
1 public class EmployeeAuthController {
2
3 public String strPassword { get; set; }
4 public String strUsername { get; set; }
5 public String msg { get; set; }
6 public String userID { get; set; }
7 public String accessToken { get; set; }
8
9 public EmployeeAuthController (){
10 accessToken = obtainAccessToken();
11 String code = ApexPages.currentPage().getParameters().get('code');
12 //Obtain user ID
13 Http h = new Http();
14 HttpRequest req = new HttpRequest();
15 req.setMethod('GET');
16 req.setHeader('Accept-Encoding','gzip,deflate');
17 req.setHeader('Content-Type','text/xml;charset=UTF-8');
18 req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
19 req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=' + accessToken + '&code=' + code + '&agentid=0');
20 String bodyRes = '';
21 try{
22 HttpResponse res = h.send(req);
23 bodyRes = res.getBody();
24 }
25 catch(System.CalloutException e) {
26 System.debug('Callout error: '+ e);
27 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
28 }
29 msg = bodyRes ;
30 //String operation to obtain userID:
31 JSONParser parser = JSON.createParser(bodyRes);
32 while(parser.nextToken() != null){
33 if((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
34 String fieldName = parser.getText();
35 parser.nextToken();
36 if(fieldName == 'UserId'){
37 userID = parser.getText();
38 }
39 }
40 }
41 msg = userID;
42 }
43
44 }
上述代码第9行调用obtainAccessToken方法获取accessToken,后续会介绍该方法的详情,accessToken两个小时内会失效,所以这里采取实时获取的方式,当然可以设计的再巧妙些以省却每次实时获取accessToken的网络开销。第10行获得了从腾讯跳转过来时带的code参数,从第11行通过HttpRequest方法来调用换取接口获得userid,留意第18行指定了agentid为0,这是因为验证消息是从企业小助手应用发起的,而企业小助手应用id是0。第29行开始解析返回来的JSON数据获取userid。
下面是obtainAccessToken方法,方法内容也比较直接,主要通过调用gettoken接口来获取accessToken,并通过JSONParser类来解析返回的JSON数据以获得accessToken:
1 private String obtainAccessToken(){
2 String token;
3 Http h = new Http();
4 HttpRequest req = new HttpRequest();
5 req.setMethod('GET');
6 req.setHeader('Accept-Encoding','gzip,deflate');
7 req.setHeader('Content-Type','text/xml;charset=UTF-8');
8 req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
9 req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=wx548178d7f347f582&corpsecret=9pwWy0AVoT6V65hnwZLYdi4jnLLx65ofBRb_Ds0mAozysQoywDaqbqYCqglm2vhr');
10 String bodyRes = '';
11 try{
12 HttpResponse res = h.send(req);
13 bodyRes = res.getBody();
14 }
15 catch(System.CalloutException e) {
16 System.debug('Callout error: '+ e);
17 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
18 }
19 msg = bodyRes;
20 JSONParser parser = JSON.createParser(bodyRes);
21 while(parser.nextToken() != null){
22 if((parser.getCurrentToken() == JSONToken.FIELD_NAME)){
23 String fieldName = parser.getText();
24 parser.nextToken();
25 if(fieldName == 'access_token'){
26 token= parser.getText();
27 }
28 }
29 }
30 msg = token;
31 return token;
32 }
接下来最重要的方法是bind方法,该方法将负责用户身份验证以及通知腾讯用户关注成功,可以看到下面代码里第2行到第6行只做了很简单的用户名密码校验,真实场景里可以根据企业的具体认证机制进行替换,从第9行开始也即企业内部用户认证通过后开始调用authsucc接口通知腾讯用户关注成功。
1 public PageReference bind() {
2 if(!strUsername.equals('user')){
3 msg = 'Please input correct user name';
4 }
5 else if(!strPassword.equals('123')){
6 msg = 'Please input correct password';
7 }
8 else{
9 msg = 'Bind successfully!';
10 //Notify tencent to add user
11 Http h = new Http();
12 HttpRequest req = new HttpRequest();
13 req.setMethod('GET');
14 req.setHeader('Accept-Encoding','gzip,deflate');
15 req.setHeader('Content-Type','text/xml;charset=UTF-8');
16 req.setHeader('User-Agent','Jakarta Commons-HttpClient/3.1');
17 req.setEndpoint('https://qyapi.weixin.qq.com/cgi-bin/user/authsucc?access_token=' + accessToken + '&userid=' + userID);
18 String bodyRes = '';
19 try{
20 HttpResponse res = h.send(req);
21 bodyRes = res.getBody();
22 }
23 catch(System.CalloutException e) {
24 System.debug('Callout error: '+ e);
25 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL, e.getMessage()));
26 }
27 msg = bodyRes ;
28 }
29 }
30
对于JfreeChart最最基本应用
来源: 无法识别的配置节“connectionStrings”的解决方法 – _Witch__的专栏 – 博客频道 – CSDN.NET
无法识别的配置节“connectionStrings”的解决方法
问题:配置错误 说明: 在处理向该请求提供服务所需的配置文件时出错。请检查下面的特定错误详细信息并适当地修改配置文件。 分析器错误信息: 无法识别的配置节“connectionStrings”源错误: 行 1: <configuration> 行 2: 行 3: <connectionStrings/> 行 4: …… 源文件: F:/User/site/CS_2.1.60809.935_SDK/source/Web/web.config 行: 3 原因:用vs2005开发的asp.NET应用程序需要使用.net framework 2.0,而在iis中的默认.net环境是1.1。这时将发生不可识别的节点的问题。解决办法:将.net环境升级为2.0,开始-》运行-》cmd-》 C:/WINDOWS/Microsoft.NET/Framework/v2.0.50727/aspnet_regiis.exe -i (对于原先是ASP.NET1.1来说,要更改为ASP.NET2.0的操作)
C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/aspnet_regiis.exe -i (对于原先是ASP.NET2.0来说,要更改为ASP.NET1.1的操作)
http://blog.163.com/zpihao@126/blog/static/83413979200831541128772/
来源: 如何使用Navicat将psc备份导入到MySQL – 远在上海
吉日嘎拉的DotNet.CommonV4.2程序增加了DotNet.MVC,但是目前的项目用的是MySQL数据库,而SVN上只有psc文件,而不是SQL文件,所以只好Bing搜索一下如何恢复这个数据库,找了半天,不过好在又学会了用一个管理MySQL的客户端,这里记录下来过程,以备不时之需。
第一步:安装MySQL数据库到本机,我用Window 7操作系统,安装32位或64位MySQL都行。默认安装即可。
第二步:安装Navicat for MySQL,并连接到本机,创建数据库UserCenterV42
第三步:将SVN下载下来的psc后缀的备份文件复制到Navicat的临时工作目录(一般在 c:\用户目录\Documents\Navicat\MySQL\servers\下),我的是:C:\Users\troy.cui\Documents\Navicat\MySQL\servers\local\UserCenterV42。注意其中 local 是我在Navicat中创建的连接名,UserCenterV42为数据库名,一定要放在对应数据库名下)

第四步:在Navicat中打开数据库UserCenterV42,在备份列表中,就会看到刚才添加的备份,右键点击“还原备份”即可。



我的第2个psc备份恢复(如果单独恢复几个表,可以选择表名)

Navicat 介绍:
强大的数据库管理和设计工具,支持 Win、Mac 和 linux。直观的 GUI 让用户简单地管理 MySQL、MariaDB、SQL Server、SQLite、Oracle 和 PostgreSQL 的数据库。中文版可以14天的免费试用。中文官网:www.navicat.com.cn
来源: WDCP add_user.php任意数据库添加任意用户导致任意命令执行漏洞分析 – JoyChou’s Blog
wdcp (WDlinux Control Panel) 是一套用PHP开发的Linux服务器管理系统,旨在易于使用和管理Linux服务器,通过web后台就可以管理服务器和虚拟主机。和国外的cPanel类似。虚拟主机的小能手。
2014年9月26,wdcp官网公布该漏洞,http://www.wdlinux.cn/bbs/thread-37476-1-1.html 而且可以看到最新版本是wdcp_v2.5.11(20140926)
该漏洞影响版本:wdcp_v2.5.11版本以下。
简单分析下wdcp这个漏洞。由于wdcp是经过编码加密的,所以得解密后分析代码。我简单写了一个解密wdcp整个文件的代码,用的时候只需修改下wdcp的目录。
wdcp_decode.php
<?php
/*
Authou: JoyChou
Date: 2014年12月7日14:50
*/
error_reporting(0);
function wdcp_decode($filename) {
if (!file_exists($filename)) {
return false; //文件名不存在
}
$data = unpack('C*', substr(file_get_contents($filename), 9));
$key = array(0xB8, 0x35, 0x6, 0x2, 0x88, 0x1, 0x5B, 0x7, 0x44, 0x0);
$j = count($data);
foreach($data as $k => &$v) {
$v = $key [ 2 * ($j % 5) ] ^ ~$v;
// $v = sprintf('%u', $v);
$v &= 0xFF;
$v = pack('C*', $v);
-- $j;
}
return gzuncompress(join('', $data));
}
function Traversal_Files($path = '.'){
if (!is_dir($path)) {
echo '参数不是目录';
return false;
}
// //opendir()返回一个目录句柄,失败返回false
if ($current_dir = opendir($path)) {
while (false !== ($file = readdir($current_dir))) { // readdir获取当前目录的文件名喝目录名以及. ..
$sub_dir = $path . DIRECTORY_SEPARATOR . $file; // DIRECTORY_SEPARATOR \或者/
if ($file == '.' || $file == '..') {
continue;
}
else if (is_dir($sub_dir)) {
echo "<h3> Directory Name $file </h3>";
Traversal_Files($sub_dir); //如果是目录,进行递归判断。
}
else{
$file_ext = substr($file, strrpos($file,".")+1);
if ($file_ext == 'php' || $file_ext == 'PHP') {
//echo $sub_dir . '<br>';
file_put_contents($sub_dir . '_decode', wdcp_decode($sub_dir));
unlink($sub_dir);
rename($sub_dir . '_decode', $sub_dir);
}
}
}
}
closedir($current_dir);
}
// 在这修改wdcp目录即可
Traversal_Files("D:\web\cms\wdcp\wdcp_v2.5.11\www\wdlinux\wdcp");
?>
在网上下了一个wdcp_v2.5.7版本,解码后分析add_user.php
require_once "../inc/common.inc.php";
if (isset($_POST['Submit_add'])) {
$user=chop($_POST['user']);
$password=chop($_POST['password']);
$dbname=chop($_POST['dbname']);
check_user($user);
check_string($password);
check_string($dbname);
create_db_user($user,$password,$host);
grant_db_user($user,$host,$dbname);
mysql_add_user($user,$password,$host,$dbname,$rtime);
optlog($wdcdn_uid,"增加mysql数据库 $user",0,0);
str_go_url("数据库用户增加成功!",0);
}
毫无违和感,很粗暴的直接在数据库里增加用户,require的../inc/common.inc.php也没有做任何的登录限制。如果$_POST[‘dbname’]为空,默认的数据库是information_schema,当然要利用就得指定我们想要的数据库,一般是mySQL数据库。而且在mySQL目录下还有一个user_add.php,代码如下,和add_user.php最大的区别是它包含了login.php进行了登录验证。你肯定会猜不透为什么有了user_add.php还需要add_user.php。恩,我也猜不透。
user_add.php 关键代码
require_once "../inc/common.inc.php";
require_once "../login.php";
//require_once "../inc/admlogin.php";
//if ($wdcp_gid!=1) exit;
if (isset($_POST['Submit_add'])) {
$user=chop($_POST['user']);
$sid=intval($_POST['sid']);
$password=chop($_POST['password']);
$dbname=chop($_POST['dbname']);
$host=chop($_POST['host']);
if ($dbname=="0") go_back("选择的数据库有错!");
check_user($user);
//system_name_check($user,0);
//check_string($password);
check_passwd($password);
check_string($dbname);
system_name_check($user,0);
//check_exists_dbname($dbname);
//system_name_check($dbname,1);
create_db_user($user,$password,$host);
grant_db_user($user,$host,$dbname);
mysql_add_user($user,$password,$host,$dbname,$rtime);
optlog($wdcp_uid,"增加mysql数据库用户 $user",0,0);
str_go_url("数据库用户增加成功!",0);
该漏洞好无脑,跳广场舞的大妈都会搞站了。
测试环境:
漏洞url:http://www.hackme.com:8080/mySQL/add_user.php,可以看到用户名拿有一个6-15个字符,其实对长度的限制是大于3小于30. 由于要指定mysql数据库,所以用hackbar提交POST数据,提交的数据是Submit_add=xxoo&user=xxoo&password=xxoo&dbname=mysql

而且lanmp一键安装的站在wdcp同级目录会有phpmyadmin,所以用phpmyadmin登录,可以看到用刚新增的xxoo用户登录成功。

登录成功后,就可以看到mysql数据库user表里面的root密码,wdcp密码(都是mysql5加密)。

如果wdcp密码丢cmd5没解出来,root密码解出来,那用phpmyadmin登录root,拥有wdcp数据库的权限后,再解wdcp密码的md5。再拥有wdcp后台密码和mysql数据库root密码后,权限也是掉掉的。
一般拿到wdcp密码后,登录wdcp,在后台的“系统管理”==>“运行命令”,可以随意执行非useradd|userdel|usermod|passwd|rc\.d|init\.d和rm|dd|sudo以及/dev/|mkfs命令的命令。一般执行wget命令,下载远程恶意文件或者后门,chmod修改权限,运行自己的后门。这个命令修改的代码在/syc/cmd.php中。而且此时是root权限,有了root权限,在linux下面就可以任意操作了,达到任意命令执行。

0A 20 20 20 20 20 20 20 20 T_T 想想也醉了,还不如删掉。来源: 微信小程序:原生热布局终将改变世界 – 银河使者 – 博客园
最近朋友圈已经被微信小程序刷屏了,这也难怪,腾讯的产品拥有广泛的影响力,谁便推出个东西,都会有很多人认为会改变世界,这不,张小龙刚一发布微信小程序的消息,很多人(技术的和非技术的)就跟打了鸡血似的,估计现在已经鸡血告急了!
我也看了网上的一些关于微信小程序的文章,估计那帮家伙连微信小程序是什么都没搞清楚,就在那里一本正经地胡说八道。好吧,我就通过本文让大家了解一些什么是微信小程序,以及微信小程序到底能为我们带来什么。
关于微信小程序的误解和讨论已经太多了。这里就说一些主要的。
1. 微信小程序与Web(B/S)的关系
2. 小程序的性能可能不如原生App
3. 腾讯要做一个AppStore,和苹果、Google对掐
4. 由于微信小程序入口太深,对于高频应用不适合
5. 微信小程序会逐渐取代原生App,原生App必将没落
1. 微信小程序与Web(B/S)的关系
由于之前有微信公众号,而公众号里面的程序其实就是将移动Web(主要是HTML5、CSS、JavaScript等技术)嵌入到微信中,当然,会调用一些微信提供的API。所以很多人自然而然会想到,微信小程序用的也是HTML5。不过说实话,微信小程序和HTML5、甚至和Web,一毛钱关系都没用。因为Web就是性能低下的代名词,尤其对于那些最求完美、有强迫症的家伙,在手机上使用Web简直不能忍受。千万别说,等以后手机性能会和现在的PC一样牛叉就好了,哈哈,等到那时候,就会出现比手机更牛叉,更小巧,当然,性能也更差的设备,如果手机成为了PC,那么这些新出现的设备将会取代现在手机的位置。就像永远等待新产品降价再买,真的降价了,又会有更好的产品问世,既享受新产品,又享受低价的时候将永远不会到来。
既然说微信小程序和Web一点关系都没有,那么有什么证据呢?这一点从官方文档的描述就可以看出。感兴趣的读者可以通过下面的地址查看微信小程序官方文档。
https://mp.weixin.qq.com/wiki
微信小程序分为工程和页面两部分,工程由三个文件组成:app.js、app.json和app.wxss。其中app.js是JavaScript文件,用于编写全局的事件,如微信小程序启动时要执行的代码,有点像iOS工程中AppDelegate.m文件的作用。app.json用于配置微信小程序,如由哪些页面组成,有点像Android工程中AndroidManifest.xml文件的作用。app.wxss是公共样式表,用于设置整个工程都可以使用的样式,有点像Android中theme或style资源,全局都可以使用。
可能有人会问,微信小程序不是使用了JavaScript吗?难道和Web没有关系。谁告诉你JavaScript和Web有关系了,JavaScript只是一种语言,未必用在Web上,JavaScript同样可以用在服务端,如Node.js。
微信小程序的页面部分由4个文件组成。这里的页面实际上就是窗口。假设页面名字为index,那么该页面由index.js、index.wxml、index.wxss和index.json组成。index.js用于编写页面的逻辑代码、index.wxml是腾讯自己设计的一种标记语言,可以称为微信标记语言,用于描述UI的、index.wxss是针对该页面的样式表,私有的。index.json是针对页面的配置文件。
这里关键点是index.wxss。这东西似曾相识,用过React Native的读者应该很熟悉JSX,一种描述UI的类XML语言。其基本原理是通过XML文件描述UI,并动态创建原生的UI。例如,React Native用View来描述顶层视图,用Text来描述文本输出控件,那么我们可以使用下面的代码来模拟这一动态创建过程。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
Android:View component = null;if(tag == “View”){ component = new ViewGroup(…);}else if(tag == “Text”){ component = new TextView(…);}iOS:UIView *component;if(tag == “View”){ component = [UIView new];}else if(tag == “Text”){ component = [UILabel new];} |
上面描述的是基本的动态创建组件的过程,当然,实际实现要比这个复杂的多,这里只做了原理上的描述。很显然,系统会根据不同平台,以及在JSX中的描述,生成不同的原生组件。
微信小程序的原理类似,对于React Native来说,使用的是JSX,而微信小程序用的是wxml(微信标记语言),一种腾讯自己设计的类JSX的语言,下面是wxml的代码示例。
|
1
2
3
4
5
6
7
8
9
|
<view class="container"> <view bindtap="bindViewTap" class="userinfo"> <image class="userinfo-avatar" src="{{userInfo.avatarUrl}}" background-size="cover"></image> <text class="userinfo-nickname">{{userInfo.nickName}}</text> </view> <view class="usermotto"> <text class="user-motto">{{motto}}</text> </view> </view> |
下面则是JSX的代码示例。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<View style={{flex:1}}> <DrawerLayoutAndroid ref={drawerLayoutAndroid => { this.drawerLayoutAndroid = drawerLayoutAndroid; }} drawerWidth={150} drawerPosition={DrawerLayoutAndroid.positions.left} renderNavigationView={() =>navigationView}> <View style={{flex: 1, alignItems:'center'}}> <Text style={{margin: 10, fontSize: 15, textAlign: 'right'}}>我是主布局内容</Text> </View> </DrawerLayoutAndroid> <View style={{flexDirection:'row'}}> <Text style={{flex:1}} onPress={this.onPress.bind(this)}>Open</Text> <Text style={{flex:1}} onPress={()=>this.drawerLayoutAndroid.closeDrawer(0)}>Close</Text> </View></View> |
从上面两端代码可以看出,JSX和wxml非常类似,只是具体的组件名称和命名风格不同,例如,JSX所有组件名称首字母都大写(如Text),而wxml所有组件名称首字母都小写(如text),其他的还有组件属性有一定的差异。
不管JSX和wxml的代码风格是否一样,系统处理他们的原理都是一样的,就是根据这些代码自动生成原生的组件,就像前面描述的动态创建原生组件的过程一样。
原生和热布局混合开发
尽管本文的主标题是微信小程序,不过核心要点则是原生和热布局混合开发。这里只是用微信小程序做一个引子。由于目前移动平台主要有Android和iOS。这两个平台使用的开发技术完全不同(前者主要使用Java,后者主要使用OC或Swift),所以就需要有一种可以同时开发两种平台的技术,这样理论上开发成本可以节省一半。
以前比较流行的技术是混合开发(Hybird),这种技术很简单,就是HTML5+CSS+JavaScript的结合。就和木桶原理一样,木桶装多少水,是由最短那个模板决定的,而这三个组合,HTML5就成为那个短板,从而拖慢了Hybird的整体性能。
其实对于Hybird技术,我们只需要其中的两个优势:跨平台和热更新。跨平台很好理解,各个平台都会有Web浏览器,而热更新主要是逻辑代码和UI布局的热更新。逻辑代码这个不用操心,热更新就用JavaScript好了,这里主要讨论UI布局的热更新。在Hybird时代,使用的是HTML5和CSS。这东西热更新没问题,但性能有问题,如果把HTML5组件和原生的组件放到同一个窗口,是可以感觉到他们的不同的。所以现在的主要焦点集中在UI布局既可以实现热更新,性能达到或接近原生组件。HTML5达到了前者的要求,但没有达到后者的要求。我们知道,Android布局使用了Layout,iOS布局使用了storyboard,不管是那种技术,都不支持热更新,都是固化到apk和ipa文件中的。不过这两种技术都支持动态创建组件,所以React Native率先推出了利用JSX描述组件的位置、尺寸以及其他属性,然后再根据这些属性动态创建本地组件的技术。其实JSX会生成一种中间状态,我们可以称为虚拟DOM(Virtual DOM),其实就是一种中间组件而已,然后系统会根据运行平台的不同(Android和iOS),将其动态生成不同平台的原生组件,这样很容易实现热更新,因为JSX就是个普通的文本文件,可以谁便从网络上下载,这一点和HTML5相同。由于组件都是动态创建的原生的,所以和在Layout、storyboard中定义的静态原生组件的性能相同,因此,很容易解决前面描述的问题。我们也可以把这种利用XML或其他格式描述UI布局,并实现动态生成原生组件的技术称为原生热布局。
微信小程序借鉴了React Native的原理。所不同的是,React Native是通用的,而且可以任意扩展。而微信小程序必须运行在微信提供的架构上,是一种寄生的原生热布局。
其实,除了React Native和微信小程序,还有阿里巴巴的Weex(http://alibaba.github.io/weex),这是阿里巴巴前端团队发布的一个开源框架,有兴趣的读者可以到这个地址研究下这些框架。也是用了类似Virtual DOM的技术,可以三位一体(Android/iOS/HTML5),这一点,React Native对应的React.js可以生产HTML5,微信小程序理论上也可以。希望以后能推出类似的技术,开发微信小程序的同时,也可以同时开发基于HTML5的微信公众号。
通过原生热布局的应用,App的性能完全可以和原生媲美(其实就是动态生成的原生组件),目前已经有很多类似的框架问世,相信以后会更多。相信这些原生热布局的方式以后会在很长一段时间成为跨平台开发的主流,因为她的颜值实在太高了!
组件与变量绑定
微信小程序有一个比较有意思的特性,就是可以将组件和变量进行绑定,当更新组件时(如text),只需修改变量的值,组件就会做相应的更新,这一点区别于传统更新组件的方式:通过id或name引用组件,然后使用组件中相关方式或属性进行更新。例如,下面的代码
<text class=”user-motto”>{{motto}}</text>
其中motto是一个变量,在index.js文件中定义,代码如下:
|
1
2
3
4
5
6
7
8
|
var app = getApp() Page({ data: { motto: 'Hello World', userInfo: {} }, … … }) |
现在只需要修改data中的motto变量的值,text组件就会自动显示该变量的值。
其实React Native也同样采用了这种方式,只不过React Native也可以采用直接引用组件的方式来更新组件。
2. 小程序的性能可能不如原生App
这个问题前面已经回答了,小程序采用了动态生成原生组件的方式。不管里面具体是如何做的,总之,要想让性能达到原生App的程度,除了使用原生组件外,没有其他方式。HTML5再怎么优化,也不可能有原生App的性能。就和汽车速度再快,也不可能超过飞机的速度,因为运动介子不同,也就决定了他的极限。
3. 腾讯要做一个AppStore,和苹果、Google对掐
好吧,持这种观点的同学应该比较富有想象力。当然,小程序需要运行在微信中,这是毫无疑问的,从表面上看,确实和AppStore比较像。不过腾讯可能只想做个小程序(你们想多了),因为微信在国内的用户增长量已经到了极限,不可能有大的飞跃了。腾讯继续另一个东西来刺激增长,也许是来自投资人的压力,或来自盈利的压力,腾讯在隔一段时间必须做点什么,从QQ到微信,再从微信到小程序,就是这样,如果不出所料,在若干年后,如果腾讯还存在的话,可能会推出其他什么东西,估计到时应该会有很多人说,这东西必将取代微信小程序,_^_。
当然,还有人说,腾讯是要做个OS,其实这就扯远了,腾讯是互联网公司,不是软件公司,做OS不是他的强项。再说,小程序和OS差着十万八千里呢。其实微信小程序就是借用了React Native的原理(在RN出现的同时,腾讯一直在研究这种技术,估计是为微信小程序做技术上的储备),将原始热布局嵌入到了微信,并提供了一些公开的接口的微信扩展。我觉得将微信小程序定义为微信扩展更合适。
4. 由于微信小程序入口太深,对于高频应用不适合
入口太深,弄浅就好了。Android和iOS很容易直接将App中的功能作为单独的App安装在系统上,作为第一层的图标,这只是技术问题而已,对于腾讯都不是问题。
5. 微信小程序会逐渐取代原生App,原生App必将没落
都说了,小程序是微信的扩展,而且由于其封闭性,无法让程序员自由扩展(微信是不可能开源的),所以小程序不能像React Native一样可以开发各种App,只是作为微信的一种补充而已。所以原生App在未来仍然将作为主流。当然,也会带来一些不同,可怜的技术哥又有多了一个活,就是除了原生App、微信公众号外,还要开发微信小程序!好吧,祝技术哥好运!
微信小程序的开发
腾讯自己做了一款小程序开发工具,读者可以从下面的地址下载。
https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/devtools.html?t=1475052047016
下面是截图

看样子还不错,不过必须要有App ID才能进行开发。目前小程序在内侧阶段,只有受到邀请才能自己生产App ID。不过大家可以看一下官方的文档,基本可以了解开发的过程。在该页也包含了小程序中的API和组件列表,和React Native相当接近。
学习微信小程序的前导技术
小程序逻辑代码使用的JavaScript,所以要想编写小程序,必须学会JavaScript,除了JavaScript外,读者可以先研究一下React Native技术,因为这种技术和小程序非常类似,基本上RN学会后,开发小程序就会变得非常轻松。为了让读者尽快进入微信小程序的世界,我特意开发了JavaScript和React Native的视频课程:(JavaScript)http://edu.csdn.net/course/detail/2910 (React Native)http://edu.csdn.net/course/detail/2883 通过这些课程,读者可以为学习小程序做充分的准备。
机器人、无人驾驶、无人机创业者的福音
来源: Google 开源 SLAM 地图软件 Cartographer,可用于机器人、无人驾驶和无人机系统
Google 在官方声明中提到,SLAM 算法结合了来自多个传感器的数据,比如 LIDAR 激光雷达传感器,通过向其他物体发射光线,然后测量光线反射回来的时间,探测周围的环境;IMU 惯性测量单元,用于测量物体三轴姿态角(或角速率)以及加速度;还有来自多个摄像头的数据。综合这些庞杂的数据,得以计算传感器及传感器周围的环境。
SLAM 技术是自动驾驶平台最重要的技术部分,适用于无人驾驶、仓库自动叉车、吸尘机器人和无人机等。Cartographer 基于此创建了全球范围内的实时地图,并且结合 ROS 及其他外部技术支持,Cartographer 现已经支持 Toyota HSR、TurtleBots、PR2、Revo LDS 这几个机器人平台。
![]()
实际上,Cartographer 不光是这项开源技术库的名字,它对应的还是一套数据收集装置——“背包”,和街景采集背包 Trekker 相似,Cartographer 也需要穿戴者穿过不同楼层,以采集和绘制相应空间。在 2014 年 9 月,Google 表示已通过 Cartographer 创建了 6 张室内地图,而现在,我们已经能在看到博物馆、美术馆及很多著名建筑的室内情形,并且在和德意志博物馆(现世界最大的科技博物馆)的合作中,Google 还对外公布了收集 3 年的 LIDAR 和 IMU 数据。
来源: 解决Godaddy部分DNS被封的2个方法_站长心得_www.knowsky.com
最近有人传言godaddy大部分dns服务器被封锁,导致国内用户无法正常登录网站。后来看到有人竟然这样写:“GoDaddy DNS再次被屏蔽,国内站长何去何从”,我真是无语了。
其实封的DNS数量很少,只有几个,也许大部分叫嚣者都是国内那些idc的托,在造势,从舆论上强迫不明真相的站长接受他们的垃圾高价主机。
解决dns被封的方法有两个:
一,更换第三方dns服务器。
国内比较著名的免费dns服务器有dnspod,百度搜索一下就知道怎么用了,我在这里不做过多描述。
二,更换godaddy的dns未被天朝屏蔽的地址。
这也是我此次揭露网络谎言的重点,方法很简单。
那么现在我就告诉大家godaddy提供的dns服务器地址,以及如何来识别可用的即未被封的dns服务器。
作为世界最大的域名注册商之一,它提供了很多的dns服务器,默认只开启了两个,当然我们可以添加很多。
1,确实地址范围在:NS1.DOMAINCONTROL.COM——NS90.DOMAINCONTROL.COM 之间。
2,选用合适的dns,这次用到的工具是批量ping工具“PingInfoView”,百度搜索下载。
3,打开PingInfoView软件,在弹出的Ping Options窗口中输入dns服务器地址,一行一个。

4,完成第3步后,点击ok,

下面我把dns地址直接帖上来,朋友们不用自己一个一个输入,或者用excel处理了。
| NS1.DOMAINCONTROL.COMNS2.DOMAINCONTROL.COM
NS3.DOMAINCONTROL.COM NS4.DOMAINCONTROL.COM NS5.DOMAINCONTROL.COM NS6.DOMAINCONTROL.COM NS7.DOMAINCONTROL.COM NS8.DOMAINCONTROL.COM NS9.DOMAINCONTROL.COM NS10.DOMAINCONTROL.COM NS11.DOMAINCONTROL.COM NS12.DOMAINCONTROL.COM NS13.DOMAINCONTROL.COM NS14.DOMAINCONTROL.COM NS15.DOMAINCONTROL.COM NS16.DOMAINCONTROL.COM NS17.DOMAINCONTROL.COM NS18.DOMAINCONTROL.COM NS19.DOMAINCONTROL.COM NS20.DOMAINCONTROL.COM NS21.DOMAINCONTROL.COM NS22.DOMAINCONTROL.COM NS23.DOMAINCONTROL.COM NS24.DOMAINCONTROL.COM NS25.DOMAINCONTROL.COM NS26.DOMAINCONTROL.COM NS27.DOMAINCONTROL.COM NS28.DOMAINCONTROL.COM NS29.DOMAINCONTROL.COM NS30.DOMAINCONTROL.COM |
NS31.DOMAINCONTROL.COMNS32.DOMAINCONTROL.COM
NS33.DOMAINCONTROL.COM NS34.DOMAINCONTROL.COM NS35.DOMAINCONTROL.COM NS36.DOMAINCONTROL.COM NS37.DOMAINCONTROL.COM NS38.DOMAINCONTROL.COM NS39.DOMAINCONTROL.COM NS40.DOMAINCONTROL.COM NS41.DOMAINCONTROL.COM NS42.DOMAINCONTROL.COM NS43.DOMAINCONTROL.COM NS44.DOMAINCONTROL.COM NS45.DOMAINCONTROL.COM NS46.DOMAINCONTROL.COM NS47.DOMAINCONTROL.COM NS48.DOMAINCONTROL.COM NS49.DOMAINCONTROL.COM NS50.DOMAINCONTROL.COM NS51.DOMAINCONTROL.COM NS52.DOMAINCONTROL.COM NS53.DOMAINCONTROL.COM NS54.DOMAINCONTROL.COM NS55.DOMAINCONTROL.COM NS56.DOMAINCONTROL.COM NS57.DOMAINCONTROL.COM NS58.DOMAINCONTROL.COM NS59.DOMAINCONTROL.COM NS60.DOMAINCONTROL.COM |
NS61.DOMAINCONTROL.COMNS62.DOMAINCONTROL.COM
NS63.DOMAINCONTROL.COM NS64.DOMAINCONTROL.COM NS65.DOMAINCONTROL.COM NS66.DOMAINCONTROL.COM NS67.DOMAINCONTROL.COM NS68.DOMAINCONTROL.COM NS69.DOMAINCONTROL.COM NS70.DOMAINCONTROL.COM NS71.DOMAINCONTROL.COM NS72.DOMAINCONTROL.COM NS73.DOMAINCONTROL.COM NS74.DOMAINCONTROL.COM NS75.DOMAINCONTROL.COM NS76.DOMAINCONTROL.COM NS77.DOMAINCONTROL.COM NS78.DOMAINCONTROL.COM NS79.DOMAINCONTROL.COM NS80.DOMAINCONTROL.COM NS81.DOMAINCONTROL.COM NS82.DOMAINCONTROL.COM NS83.DOMAINCONTROL.COM NS84.DOMAINCONTROL.COM NS85.DOMAINCONTROL.COM NS86.DOMAINCONTROL.COM NS87.DOMAINCONTROL.COM NS88.DOMAINCONTROL.COM NS89.DOMAINCONTROL.COM NS90.DOMAINCONTROL.COM |
结果证明九十多个dns,也就有十多个不能用,怎么能说是大规模屏蔽呢。
怎么样更换godaddy的dns服务器地址,会者跳过,不会的请点击:http://www.icdiary.com/html/1989.html