MySQL 不允许从远程访问的解决方法

解决方法:
1。 改表法。
可能是你的帐号不允许从远程登陆,只能在localhost。这个时候只要在localhost的那台电脑,登入mysql后,更改 “mysql” 数据库里的 “user” 表里的 “host” 项,从”localhost”改称”%”

复制代码代码如下:
mysql -u root -pvmwaremysql>use mysql;
mysql>update user set host = ‘%’ where user = ‘root’;
mysql>select host, user from user;

2. 授权法。
例如,你想myuser使用mypassword从任何主机连接到mysql服务器的话。
GRANT ALL PRIVILEGES ON *.* TO ‘myuser’@’%’ IDENTIFIED BY ‘mypassword’ WITH GRANT OPTION;
FLUSH PRIVILEGES;
如果你想允许用户myuser从ip为192.168.1.6的主机连接到mysql服务器,并使用mypassword作为密码
GRANT ALL PRIVILEGES ON *.* TO ‘myuser’@’192.168.1.3’ IDENTIFIED BY ‘mypassword’ WITH GRANT OPTION;
FLUSH PRIVILEGES;
如果你想允许用户myuser从ip为192.168.1.6的主机连接到mysql服务器的dk数据库,并使用mypassword作为密码
GRANT ALL PRIVILEGES ON dk.* TO ‘myuser’@’192.168.1.3’ IDENTIFIED BY ‘mypassword’ WITH GRANT OPTION;
FLUSH PRIVILEGES;
我用的*个方法,刚开始发现不行,在网上查了一下,少执行一个语句 mysql>FLUSH RIVILEGES 使修改生效.就可以了
另外一种方法,不过我没有亲自试过的,在csdn.net上找的,可以看一下.
在安装mysql的机器上运行:
1、d:\mysql\bin\>mysql -h localhost -u root //这样应该可以进入MySQL服务器
2、mysql>GRANT ALL PRIVILEGES ON *.* TO ‘root’@’%’ WITH GRANT OPTION //赋予任何主机访问数据的权限
3、mysql>FLUSH PRIVILEGES //修改生效
4、mysql>EXIT //退出MySQL服务器
这样就可以在其它任何的主机上以root身份登录啦!

SVN服务器的本地搭建和使用

Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说.

首先来下载和搭建SVN服务器.

现在Subversion已经迁移到apache网站上了,下载地址:

http://subversion.apache.org/packages.html

这是二进制文件包的下载地址,你可在左侧的导航栏找到源代码,文档的下载地址.

windows操作系统下面的二进制文件包一共有5种,如图:

\

个人认为*好用VisualSVN server 服务端和 TortoiseSVN客户端搭配使用.

点开上面的VisualSVN连接,下载VisualSVN server,如图:

\

然后下载TortoiseSVN客户端,官网下载地址:http://tortoisesvn.net/downloads.html

\

注意下载跟你电脑匹配的安装包,在页面的下面你还可以找到语言包,如图:

\

下载完成后,应该有这些安装包,如图:

\

TortoiseSVN安装包和简体中文语言包

\

VisualSVN server安装包

先安装VisualSVN server的安装包,双击VisualSVN server安装包,如图:

\

点Next,进入下一步,如图:

\

点同意,进图下一步,如图:

\

选择上面一个选项,点Next,进入下一步,如图:

\

Location是指VisualSVN Server的安装目录,Repositorys是指定你的版本库目录.Server Port指定一个端口,Use secure connection勾山表示使用安全连接,Use Subversion authentication 表示使用Subversion自己的用户认证.点击Next,进入下一步,如图:

\

点Install,进入下一步,如图:

\

等待安装完成,如图:

\

安装完成后,启动VisualSVN Server Manager,如图:

\

接下来我们安装TortoiseSVN,双击安装包,进入下一步.如图:

\

点击Next,进入下一步,如图:

\

选择接受,然后点击Next,进入下一步,如图:

\

选择安装路径,然后点击Next,进入下一步,如图:

\

点击Install,开始安装,如图:

\

等待安装完成,安装完成后如图:

\

接下来我们安装简体中文语言包,这个非常简单,一路Next就行,就不截图了.语言包安装完成以后在桌面任意空白地方单击鼠标右键,会在右键菜单里找到SVN,如图:

\

选择设置,进入下一步,如图:

\

在右边的语言里面选择简体中文,然后点击应用,确定,汉化即完成,如图:

\

到这里,服务端和客户端都已经安装完毕,下一篇介绍用VisualSVN Server创建版本库,以及TortoiseSVN的使用.

 

SVN服务器搭建和使用(二)

 

上一篇介绍了VisualSVN Server和TortoiseSVN的下载,安装,汉化.这篇介绍一下如何使用VisualSVN Server建立版本库,以及TortoiseSVN的使用.

首先打开VisualSVN Server Manager,如图:

\

可以在窗口的右边看到版本库的一些信息,比如状态,日志,用户认证,版本库等.要建立版本库,需要右键单击左边窗口的Repositores,如图:

\

在弹出的右键菜单中选择Create New Repository或者新建->Repository,进入下一步:

\

输入版本库名称,勾上Create default structure复选框(推荐这么做).点击OK,版本库就创建好了,版本库中会默认建立trunk,branches,tags三个文件夹,如图:

\

这时候我们将项目导入到版本库中,找到你的项目文件夹,在项目文件夹上点击鼠标右键,找到SVN菜单,选择导入,如图:

\

在弹出的对话框中填上版本库URL,这个URL可以从VisualSVN Server Manager中获取,在你的版本库上单击右键,选择Copy URL to Clipboard,这样就把版本库URL复制到你的剪贴版了.如图:

\

将复制的版本库URL粘贴上,在URL后面加上trunk子路径.然后在导入信息里面填上导入信息”导入项目到版本库”.如图:

\

点击确定,所选中的项目就会被导入到版本库中.如图:

\

项目导入到版本库以后,不能随便让谁都能够读写版本库,所以需要建立用户组和用户.

在VisualSVN Server Manager窗口的左侧右键单击用户组,选择Create User或者新建->User,如图:

\

在弹出的对话框中填写User name和Password,然后点击OK,如图:

\

用相同的方式分别创建用户Develpoer1,Develpoer2,Develpoer3,Test1,Test2,Manger六个用户,分别代表3个开发人员,两个测试人员和一个项目经理,如图:

\

然后我们建立用户组,在VisualSVN Server Manager窗口的左侧右键单击用户组,选择Create Group或者新建->Group,如图:

\

在弹出窗口中填写Group name为Developers,然后点Add按钮,在弹出的窗口中选择三个Developer,加入到这个组,然后点Ok,如图:

\

用相同的方式创建组Managers,Testers,如图:

\

接下来我们给用户组设置权限,在MyRepository上单击右键,选择属性,如图:

\

在弹出的对话框中,选择Security选项卡,点击Add按钮,选中Developers,Managers,Testers三个组,然后添加进来,给Developers,Managers权限设置为Read/Write,Tester权限设置为Read Only,如图:

\

到此,服务端就完成了.

接下来,我们用客户端去检出代码,在桌面空白处单击右键,选择SVN检出,在弹出的对话框中填写版本库URL(具体获取方式,上面讲上传项目到版本库的时候讲过),选择检出目录,点击确定.如图:

\

开始检出项目,如图:

\

检出完成之后,我们打开工作副本文件夹,会看到所有文件和文件夹都有一个绿色的√.如图:

\

至此,创建版本库和使用TortoiseSVN导入项目,检出项目已经介绍完毕.

下一篇介绍TortoiseSVN的使用,以及冲突解决办法.

SVN服务器搭建和使用(三)

 

接下来,试试用TortoiseSVN修改文件,添加文件,删除文件,以及如何解决冲突等.

添加文件

在检出的工作副本中添加一个Readme.txt文本文件,这时候这个文本文件会显示为没有版本控制的状态,如图:

\

这时候,你需要告知TortoiseSVN你的操作,如图:

\

加入以后,你的文件会变成这个状态,如图:

\

这时候使用TortoiseSVN进行提交.这样别人就能看到你所做的更改了,如图.

\

修改文件

使用TortoiseSVN更新,修改工作副本中的Readme.txt文件,加入”hello world!”,然后保存,你会发现Readme.txt文件的图标改变了,如图:

\

这个红色的叹号代表这个文件被修改了,这时候,提交更改,其他人即可看到你的更改.

重命名文件

使用TortoiseSVN更新,重命名工作副本中的Readme.txt文件为”Readme1.txt’,然后保存,你会发现Readme.txt文件的图标改变了,如图:

\

更添加文件一个道理,这时候你需要告诉TortoiseSVN你的操作,如图:

\

加入以后,提交,这时候版本库中的Readme.txt文件将会被重命名为”Readme1.txt”.

删除文件

使用TortoiseSVN更新,使用TortoiseSVN删除工作副本中的Readme.txt文件,然后提交,版本库中的相应文件即被删除掉了,如图:

\

强制写注释

为了以后你能更清晰的看到你所做的每一次更改的原因,你在每次提交的时候应该写上注释,而且尽量详细.如图:

\

但是,可能有的人因为觉得太繁琐,而不填写注释,这不利于以后的版本控制,可以将强制在提交的时候写注释,首先单击右键,选择TortoiseSVN->属性,如图:

\

在弹出的对话框中,点击新建->日志大小,设置提交日志的*小字符数和锁定日志的*小字符数为20,提交文本框中显示边线的字符位置设置为100,点击确定,如图:

\

提交,以后再次提交的时候,如果输入的注释少于20个字符,将无法提交.

冲突解决

冲突问题是*常见的问题,它是这样产生的,A用户check out了一个工作副本A,接着B用户又check out了一个工作副本B.然后A用户对副本A中的文件C做了修改(可以是内容修改,文件删除,重命名,以及位置移动),并且提交.这时候B用户也对文件C的相同部分做了修改,这时候如果B用户进行提交,会先被告知版本过时,要求更新,然后更新的时候会提示冲突了,这时候可以用冲突编辑器进行手动选择.

TortoiseSVN客户端重新设置用户名和密码

 

在*次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么以后就不用每次都输入一遍用户名密码了。

不过,如果后来在服务器端修改了用户名密码,则再次检出时就会出错,而且这个客户端很弱智,出错之后不会自动跳出用户名密码输入框让人更新,我找了半天也没找到修改这个用户名密码的地方。

*终,找到两种解决办法:

办法一:在TortoiseSVN的设置对话框中,选择“已保存数据”,在“认证数据”那一行点击“清除”按钮,清楚保存的认证数据,再检出的时候就会重新跳出用户名密码输入框。

 

\

如果方法一不起作用,则可以采用方法二:

Tortoise的用户名密码等认证信息都是缓存在客户端文件系统的这个目录:

C:/Documents and Settings/Administrator/Application Data/Subversion/auth

删除auth下面的所有文件夹,重新连接远程服务器进行检出,对话框就会出现!

nginx反向代理模块

nginx的反向代理模块有很多种配置,下面介绍一些常用的配置实例:

1.proxy_pass

语法:   proxy_pass URL
配置块:   location,if
详解:此配置项将当前请求反向代理到URL参数指定的服务器上,URL可以是主机名或者IP地址加端口的形式。例如:

  1. // nginx.conf配置文件
  2. // 配置URL地址
  3. proxy_pass http://www.54rd.net/html/webserver/;
  4. // 也可以配置unix句柄
  5. proxy_pass http://unix:/path/to/backend.sock:/webserver/;
  6. // 也可以把HTTP转换成更安全的HTTPS
  7. proxy_pass https://192.168.0.1;

默认情况下反向代理是不会转发请求中的Host头部。如果需要转发,那么必须加上set_header配置:

  1. proxy_set_header Host $host;

2.proxy_method

语法:proxy_method method;
配置块:http,server,location
详解:此配置项表示转发时的协议方法名,例如:

  1. // 配置后客户端发来的GET请求在转发时方法名也会改为POST
  2. proxy_method POST;

3.proxy_hide_header

语法:proxy_hide_header the_header;
配置块:http,server,location
详解:nginx会将上游服务器的响应转发给客户端,但默认不会转发以下HTTP头部字段:Date,Server,X-Pad和X-Accel-*。使用proxy_hide_header后可以任意指定哪些HTTP头部字段不能被转发。例如:

  1. // 例如不转发缓存控制
  2. proxy_hide_header Cache-Control;

4.proxy_pass_header

语法:proxy_pass_header the_header;
配置块:http,server,location
详解:于proxy_hide_header功能相反,proxy_pass_header会将原来禁止转发的header设置成允许转发。例如:

  1. // 允许重定向
  2. proxy_pass_header X-Accel-Redirect;

5.proxy_pass_request_body

语法:proxy_pass_request_body on|off;
默认:proxy_pass_request_body on;
配置块:http,server,location
详解:作用为确定是否向上游服务器发送HTTP包体部分。

6.proxy_pass_request_headers

语法:proxy_pass_request_headers on|off;
默认:proxy_pass_request_headers on;
配置块:http,server,location
详解:作用为确定是否转发HTTP头部。

7.proxy_redirect

语法:proxy_redirect [default|off|redirect replacement];
默认:proxy_redirect default;
配置块:http,server,location
详解:当上游服务器返回的响应时重定向或者刷新请求(如HTTP响应码是302或者301)时,proxy_redirect可以重设HTTP头部的location或refresh字段,例如:

  1. // 如果上游服务器发出的响应码是302,location字段的URL是http://www.54rd.net/html/webserver/,那么实际会转发到http://www.54rd.net/html/php/
  2. proxy_redirect http://www.54rd.net/html/webserver/ http://www.54rd.net/html/php/;
  3. // 还可以使用ngx-http-core-module提供的变量来设置
  4. proxy_redirect http://www.54rd.net/html/webserver/ http://$host:$server_port/;
  5. // 也可以省略repalcement参数中的主机部分,这时会用虚拟主机名称来填充
  6. proxy_redirect http://www.54rd.net/html/webserver/ /html/php/;

======================

在使用nginx的反向代理功能时,有时会出现重定向的url不是我想要的url,例如下面的例子:前端的Nginx负责把http: www 54rd net yum Server 开头的url反向代理到后端的http: 192 168 1 1 Server 上。对于有完整
在使用nginx的反向代理功能时,有时会出现重定向的url不是我想要的url,例如下面的例子:

前端的Nginx负责把http://www.54rd.net/yum/Server/开头的url反向代理到后端的http://192.168.1.1/Server/上。

对于有完整的路径,如http://www.54rd.net/yum/Server/的代理没有问题,Server对应后台服务器的一个目录。

但当访问  http://www.54rd.net/yum/Server时,后端Nginx会发送一个301到/上,于是返回到前端后URL变成了 http://www.54rd.net/Server/,这个url显然不是我们想要的。

在Apache中有个ProxyPassReverse的参数,用来调整反向代理服务器发送的http应答头的url,可以解决这个问题。

查了Nginx的手册后,终于发现了proxy_redirect这个参数,它实现的功能和ProxyPassReverse类似,例如增加如下配置:

  1. location ^~ /yum
  2. {
  3.             proxy_pass http://192.168.1.1/;
  4.             proxy_redirect http://www.54rd.net/ /yum/;
  5. }

这样,当访问http://www.54rd.net/yum/Server后,就会301到http://www.54rd.net/yum/Server/上了。

====================

8.proxy_next_upstream

语法:proxy_next_upstream [error|timeout|invalid_header|http_500|http_502|http_503|http_504|http_404|off];
默认:proxy_next_upstream error timeout;
配置块:http,server,location
详解:此配置项表示当向一台上游服务器转发请求出现错误时,继续换一台上游服务器处理这个请求,这样可以更好的保证客户端只收到来自一个上游服务器的应答。proxy_next_upstream的参数用来说明在哪些情况下会继续选择下一台上游服务器转发请求:

  1. error:当向上游服务器发起连接,发送请求,读取响应时出错时。
  2. timeout:发送请求或者读取响应发生超时时。
  3. invalid_header:上游服务器发送的响应时不合法时。
  4. http_500:上游服务器返回的HTTP响应码是500时。
  5. http_502:上游服务器返回的HTTP响应码是502时。
  6. http_503:上游服务器返回的HTTP响应码是503时。
  7. http_504:上游服务器返回的HTTP响应码是504时。
  8. http_404:上游服务器返回的HTTP响应码是404时。
  9. off:关闭proxy_next_upstream 功能一出错就选择另一台上游服务器再次转发。

小结:nginx的反向代理使用起来还是很方便的,适当的修改配置即可。

PV、UV、IP之间的区别与联系

PV是网站分析的一个术语,用以衡量网站用户访问的网页的数量。对于广告主,PV值可预期它可以带来多少广告收入。一般来说,PV与来访者的数量成正比,但是PV并不直接决定页面的真实来访者数量,如同一个来访者通过不断的刷新页面,也可以制造出非常高的PV。
   PV、UV、IP之间的区别与联系 - 以德糊人 - ——挨踢民工 Playkid——
   1、什么是PV值
  PV(page view)即页面浏览量或点击量,是衡量一个网站或网页用户访问量。具体的说,PV值就是所有访问者在24小时(0点到24点)内看了某个网站多少个页面或某个网页多少次。PV是指页面刷新的次数,每一次页面刷新,就算做一次PV流量。
  度量方法就是从浏览器发出一个对网络服务器的请求(Request),网络服务器接到这个请求后,会将该请求对应的一个网页(Page)发送给浏览器,从而产生了一个PV。那么在这里只要是这个请求发送给了浏览器,无论这个页面是否完全打开(下载完成),那么都是应当计为1个PV。
   2、什么是UV值
  UV(unique visitor)即独立访客数,指访问某个站点或点击某个网页的不同IP地址的人数。在同一天内,UV只记录*次进入网站的具有独立IP的访问者,在同一天内再次访问该网站则不计数。UV提供了一定时间内不同观众数量的统计指标,而没有反应出网站的全面活动。通过IP和cookie是判断UV值的两种方式:
   用Cookie分析UV值
  当客户端*次访问某个网站服务器的时候,网站服务器会给这个客户端的电脑发出一个Cookie,通常放在这个客户端电脑的C盘当中。在这个Cookie中会分配一个独一无二的编号,这其中会记录一些访问服务器的信息,如访问时间,访问了哪些页面等等。当你下次再访问这个服务器的时候,服务器就可以直接从你的电脑中找到上一次放进去的Cookie文件,并且对其进行一些更新,但那个独一无二的编号是不会变的。
   PV、UV、IP之间的区别与联系 - 以德糊人 - ——挨踢民工 Playkid——
   3、IP即独立IP数
  IP可以理解为独立IP的访问用户,指1天内使用不同IP地址的用户访问网站的数量,同一IP无论访问了几个页面,独立IP数均为1。但是假如说两台机器访问而使用的是同一个IP,那么只能算是一个IP的访问。
  IP和UV之间的数据不会有太大的差异,通常UV量和比IP量高出一点,每个UV相对于每个IP更准确地对应一个实际的浏览者。
  ①UV大于IP
  这种情况就是在网吧、学校、公司等,公用相同IP的场所中不同的用户,或者多种不同浏览器访问您网站,那么UV数会大于IP数。
  ②UV小于IP
  在家庭中大多数电脑使用ADSL拨号上网,所以同一个用户在家里不同时间访问您网站时,IP可能会不同,因为它会根据时间变动IP,即动态的IP地址,但是实际访客数唯一,便会出现UV数小于IP数。

十个免费的 Web 压力测试工具

本文列举了是十个免费工具,可以用来进行Web的负载/压力测试的。这样你就可以知道你的服务器以及你的WEB应用能够扛得住多少的并发量,以及网站性能。

0. Grinder –  Grinder是一个开源的JVM负载测试框架,它通过很多负载注射器来为分布式测试提供了便利。 支持用于执行测试脚本的Jython脚本引擎HTTP测试可通过HTTP代理进行管理。根据项目网站的说法,Grinder的 主要目标用户是“理解他们所测代码的人——Grinder不仅仅是带有一组相关响应时间的‘黑盒’测试。由于测试过程可以进行编码——而不是简单地脚本 化,所以程序员能测试应用中内部的各个层次,而不仅仅是通过用户界面测试响应时间。

The Grinder

1. Pylot -Pylot 是一款开源的测试web service性能和扩展性的工具,它运行HTTP 负载测试,这对容量计划,确定基准点,分析以及系统调优都很有用处。Pylot产生并发负载(HTTP Requests),检验服务器响应,以及产生带有metrics的报表。通过GUI或者shell/console来执行和监视test suites。

Pylot Main Logo

 

2. Web Capacity Analysis Tool (WCAT) – 这是一种轻量级负载生成实用工具,不仅能够重现对 Web 服务器(或负载平衡服务器场)的脚本 HTTP 请求,同时还可以收集性能统计数据供日后分析之用。WCAT 是多线程应用程序,并且支持从单个源控制多个负载测试客户端,因此您可以模拟数千个并发用户。该实用工具利用您的旧机器作为测试客户端,其中每个测试客户 端又可以产生多个虚拟客户端(*大数量取决于客户端机器的网络适配器和其他硬件)。您可以选择使用 HTTP 1.0 还是 HTTP 1.1 请求,以及是否使用 SSL。并且,如果测试方案需要,您还可以使用脚本执行的基本或 NTLM 身份验证来访问站点的受限部分。(如果您的站点使用 cookie、表单或基于会话的身份验证,那您可以创建正确的 GET 或 POST 请求来对测试用户进行身份验证。)WCAT 还可管理您站点可能设置的任何 cookie,所以配置文件和会话信息将永久保存。

3. fwptt – fwptt 也是一个用来进行WEB应用负载测试的工具。它可以记录一般的请求,也可以记录Ajax请求。它可以用来测试 asp.net, jsp, php 或是其它的Web应用。

4. JCrawler – JCrawler是一个开源(CPL) 的WEB应用压力测试工具。通过其名字,你就可以知道这是一个用Java写的像网页爬虫一样的工具。只要你给其几个URL,它就可以开始爬过去了,它用一 种特殊的方式来产生你WEB应用的负载。这个工具可以用来测试搜索引擎对你站点产生的负载。当然,其还有另一功能,你可以建立你的网站地图和再点击一下, 将自动提交Sitemap给前5名的搜索引擎!

5. Apache JMeter – Apache JMeter是一个专门为运行和服务器装载测试而设计的、100%的纯Java桌面运行程序。原先它是为Web/HTTP测试而设计的,但是它已经扩展以 支持各种各样的测试模块。它和用于HTTP和SQL数据库(使用JDBC)的模块一起运送。它可以用来测试静止资料库或者活动资料库中的服务器的运行情 况,可以用来模拟对服务器或者网络系统加以重负荷以测试它的抵抗力,或者用来分析不同负荷类型下的所有运行情况。它也提供了一个可替换的界面用来定制数据 显示,测试同步及测试的创建和执行。

6. Siege -Siege(英文意思是围攻)是一个压力测试和评测工具,设计用于WEB开发这评估应用在压力下的承受能力:可以根据配置对一个WEB站点进行多用户的并发访问,记录每 个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行。 Siege 支持基本的认证,cookies, HTTP 和 HTTPS 协议。

7. http_load – http_load 以并行复用的方式运行,用以测试web服务器的吞吐量与负载。但是它不同于大多数压力测试工具,它可以以一个单一的进程运行,一般不会把客户机搞死。可以可以测试HTTPS类的网站请求。

8. Web Polygraph – Web Polygraph这个软件也是一个用于测试WEB性能的工具,这个工具是很多公司的标准测试工具,包括微软在分析其软件性能的时候,也是使用这个工具做为基准工具的。很多招聘测试员的广告中都注明需要熟练掌握这个测试工具。

9. OpenSTA – OpenSTA是一个免费的、开放源代码的web性能测试工具,能录制功能非常强大的脚本过程,执行性能测试。例如虚拟多个不同的用户同时登陆被测试网 站。其还能对录制的测试脚本进行,按指定的语法进行编辑。在录制完测试脚本后,可以对测试脚本进行编辑,以便进行特定的性能指标分析。其较为丰富的图形化 测试结果大大提高了测试报告的可阅读性。OpenSTA 基于CORBA 的结构体系,它通过虚拟一个proxy,使用其专用的脚本控制语言,记录通过 proxy 的一切HTTP/S traffic。通过分析OpenSTA的性能指标收集器收集的各项性能指标,以及HTTP 数据,对系统的性能进行分析。

AMD异步模块定义介绍和Require.js中使用jQuery及jQuery插件的方法

AMD 模块

AMD(异步模块定义,Asynchronous Module Definition)格式总体的目标是为现在的开发者提供一个可用的模块化 JavaScript 的解决方案。

AMD 模块格式本身是一个关于如何定义模块的提案,在这种定义下模块和依赖项都能够异步地进行加载。它有很多独特的优势,包括天生的异步及高度灵活等特性,这些特性能够解除常见的代码与模块标识间的那种紧密耦合。目前它已经被很多项目所接纳,包括jQuery(1.7)。

RequireJS

RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范。

jQuery 对AMD的支持

jQuery 1.7 开始支持将 jQuery 注册为一个AMD异步模块。有很多兼容的脚本加载器(包括 RequireJS 和 curl)都可以用一个异步模块格式来加载模块,这也就表示不需要太多 hack 就能让一切运行起来。可以看看jQuery 1.7 中的源码:

代码如下:
// Expose jQuery as an AMD module , but only for AMD loaders that
// understand the issues with loading multiple versions of jQuery
// in a page that all might call define().
  —-仍然可以采用常规用法,amd模式只有在amd加载器调用时才走amd模式。
//The loader will indicate   they have special allowances for multiple jQuery versions by
// specifying define.amd.jQuery = true. Register as a named module,
// since jQuery can be concatenated with other files that may use define,
// but not use a proper concatenation script that understands anonymous
// AMD modules. A named AMD is safest and most robust way to register.
// Lowercase jquery is used because AMD module names are derived from
// file names, and jQuery is normally delivered in a lowercase file name .
if ( typeof define === “function” && define.amd && define.amd.jQuery ) {
define( “jquery”, [], function () { return jQuery; } );
}

 

其工作的原理是,所使用的脚本加载器通过指定一个属性,即 define.amd.jQuery 为 true,来标明自己可以支持多个 jQuery 版本。如果有兴趣了解特定的实现细节的话,我们可以将 jQuery 注册为一个具名模块,因为可能会有这样的风险,即它可能被与其它使用了 AMD 的 define() 方法的文件拼合在一起,而没有使用一个合适的、理解匿名 AMD 模块定义的拼合脚本。

高版本的jQuery (1.11.1) 去掉了define.amd.jQuery判断:

代码如下:

if ( typeof define === “function” && define.amd ) {
define( “jquery”, [], function() {
return jQuery;
});
}

 

Require.js中使用jQuery

Require.js中使用jQuery非常方便,简单配置就可以了,例如:

代码如下:

// 简单的配置
require.config({

// RequireJS 通过一个相对的路径 baseUrl来加载所有代码。baseUrl通常被设置成data-main属性指定脚本的同级目录。
baseUrl: “./js”,

// 第三方脚本模块的别名,jquery比libs/jquery-1.11.1.min.js简洁明了;
paths: {

“jquery”: “libs/jquery-1.11.1.min.js”

}

});

// 开始使用jQuery 模块
require([“jquery”], function ($) {

//你的代码
//这里直接可以使用jquery的方法,比如:$( “#result” ).html( “Hello World!” );

});

 

Require.js中使用jQuery 插件

虽然jQuery的支持AMD的API, 这并不意味着jQuery插件也是和AMD兼容的。

一般的jQuery 插件格式:

代码如下:
(function ($) {
$.fn.m??yPlugin = function () {
//你自己的插件代码
};
})(jQuery);

不过我们稍微修改一下就可以使用Require.js加载一个jQuery插件:

代码如下:
;(function (factory) {
if (typeof define === “function” && define.amd) {
// AMD模式
define([ “jquery” ], factory);
} else {
// 全局模式
factory(jQuery);
}
}(function ($) {
$.fn.jqueryPlugin = function () {
//插件代码
};
}));

或者这样:

define(["jquery"], // Require jquery

       function($){
//把你原来的插件代码放这里吧,这样就行了
//注意文件命名哦
});

Require.js中使用jQuery UI组件

Require.js中使用jQuery UI组件也类似的,只要改造一下jQuery Widget Factory 代码就可以了,并且感觉jQuery UI的依赖关系加载就可以了。例如:

代码如下:
(function (widgetFactory) {

if (typeof define === “function” && define.amd) {
// AMD模式
define(“jquery.ui.widget”, [“jquery”], function () {

widgetFactory(window.jQuery);

});
} else {
// 全局模式
widgetFactory(window.jQuery);
}
}
(function ($, undefined) {
// jQuery Widget Factory 代码
}));

AMD, CommonJS, UMD简介

*近几年,我们可以选择的Javascript组件的生态系统一直在稳步增长。虽然陡增的选择范围是*好的,但当组件混合匹配使用时就会出现很尴尬的局面。开发新手们会很快发现不是所有组件都能彼此“和平相处”。

为了解决这个问题,两种竞争关系的模块规范AMD和CommonJS问世了,它们允许开发者遵照一种约定的沙箱化和模块化的方式来写代码,这样就能避免“污染生态系统”。

AMD

随着RequireJS成为*流行的实现方式,异步模块规范(AMD)在前端界已经被广泛认同。

下面是只依赖jquery的模块foo的代码:

  1. // 文件名: foo.js
  2. define([“jquery”], function ($) {
  3. // 方法
  4. function myFunc(){};
  5. // 暴露公共方法
  6. return myFunc;
  7. });

还有稍微复杂点的例子,下面的代码依赖了多个组件并且暴露多个方法:

  1. // 文件名: foo.js
  2. define([“jquery”, “underscore”], function ($, _) {
  3. // 方法
  4. function a(){}; // 私有方法,因为没有被返回(见下面)
  5. function b(){}; // 公共方法,因为被返回了
  6. function c(){}; // 公共方法,因为被返回了
  7. // 暴露公共方法
  8. return {
  9. b: b,
  10. c: c
  11. }
  12. });

定义的*个部分是一个依赖数组,第二个部分是回调函数,只有当依赖的组件可用时(像RequireJS这样的脚本加载器会负责这一部分,包括找到文件路径)回调函数才被执行。

注意,依赖组件和变量的顺序是一一对应的(例如,jquery->$, underscore->_)。

同时注意,我们可以用任意的变量名来表示依赖组件。假如我们把$改成

jQuery$,在函数体里面的所有对jQuery的引用都由$变成了

。还要注意,*重要的是你不能在回调函数外面引用变量$和_,因为它相对其它代码是独立的。这正是模块化的目的所在!

CommonJS

如果你用Node写过东西的话,你可能会熟悉CommonJS的风格(node使用的格式与之相差无几)。因为有Browserify,它也一直被前端界广泛认同。

就像前面的格式一样,下面是用CommonJS规范实现的foo模块的写法:

  1. // 文件名: foo.js
  2. // 依赖
  3. var $ = require(“jquery”);
  4. // 方法
  5. function myFunc(){};
  6. // 暴露公共方法(一个)
  7. module.exports = myFunc;

还有更复杂的例子,下面的代码依赖了多个组件并且暴露多个方法:

  1. // 文件名: foo.js
  2. var $ = require(“jquery”);
  3. var _ = require(“underscore”);
  4. // methods
  5. function a(){}; // 私有方法,因为它没在module.exports中 (见下面)
  6. function b(){}; // 公共方法,因为它在module.exports中定义了
  7. function c(){}; // 公共方法,因为它在module.exports中定义了
  8. // 暴露公共方法
  9. module.exports = {
  10. b: b,
  11. c: c
  12. };

AMD与CMD的区别

CMD相当于按需加载,定义一个模块的时候不需要立即制定依赖模块,在需要的时候require就可以了,比较方便;而AMD则相反,定义模块的时候需要制定依赖模块,并以形参的方式引入factory中。

UMD: 通用模块规范

既然CommonJs和AMD风格一样流行,似乎缺少一个统一的规范。所以人们产生了这样的需求,希望有支持两种风格的“通用”模式,于是通用模块规范(UMD)诞生了。

不得不承认,这个模式略难看,但是它兼容了AMD和CommonJS,同时还支持老式的“全局”变量规范:

  1. (function (root, factory) {
  2. if (typeof define === “function” && define.amd) {
  3. // AMD
  4. define([“jquery”], factory);
  5. } else if (typeof exports === “object”) {
  6. // Node, CommonJS之类的
  7. module.exports = factory(require(“jquery”));
  8. } else {
  9. // 浏览器全局变量(root 即 window)
  10. root.returnExports = factory(root.jQuery);
  11. }
  12. }(this, function ($) {
  13. // 方法
  14. function myFunc(){};
  15. // 暴露公共方法
  16. return myFunc;
  17. }));
注:echarts中的中国地图china.js就采用的这种方式

保持跟上面例子一样的模式,下面是更复杂的例子,它依赖了多个组件并且暴露多个方法:

  1. (function (root, factory) {
  2. if (typeof define === “function” && define.amd) {
  3. // AMD
  4. define([“jquery”, “underscore”], factory);
  5. } else if (typeof exports === “object”) {
  6. // Node, CommonJS之类的
  7. module.exports = factory(require(“jquery”), require(“underscore”));
  8. } else {
  9. // 浏览器全局变量(root 即 window)
  10. root.returnExports = factory(root.jQuery, root._);
  11. }
  12. }(this, function ($, _) {
  13. // 方法
  14. function a(){}; // 私有方法,因为它没被返回 (见下面)
  15. function b(){}; // 公共方法,因为被返回了
  16. function c(){}; // 公共方法,因为被返回了
  17. // 暴露公共方法
  18. return {
  19. b: b,
  20. c: c
  21. }
  22. }));

RequireJS和AMD规范

概述

RequireJS是一个工具库,主要用于客户端的模块管理。它可以让客户端的代码分成一个个模块,实现异步或动态加载,从而提高代码的性能和可维护性。它的模块管理遵守AMD规范(Asynchronous Module Definition)。

RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。

首先,将require.js嵌入网页,然后就能在网页中进行模块化编程了。

 <script data-main="scripts/main" src="scripts/require.js"></script>

上面代码的data-main属性不可省略,用于指定主代码所在的脚本文件,在上例中为scripts子目录下的main.js文件。用户自定义的代码就放在这个main.js文件中。

define方法:定义模块

define方法用于定义模块,RequireJS要求每个模块放在一个单独的文件里。

按照是否依赖其他模块,可以分成两种情况讨论。*种情况是定义独立模块,即所定义的模块不依赖其他模块;第二种情况是定义非独立模块,即所定义的模块依赖于其他模块。

(1)独立模块

如果被定义的模块是一个独立模块,不需要依赖任何其他模块,可以直接用define方法生成。

  1. define({
  2. method1: function() {},
  3. method2: function() {},
  4. });

上面代码生成了一个拥有method1、method2两个方法的模块。

另一种等价的写法是,把对象写成一个函数,该函数的返回值就是输出的模块。

  1. define(function () {
  2. return {
  3. method1: function() {},
  4. method2: function() {},
  5. };
  6. });

后一种写法的自由度更高一点,可以在函数体内写一些模块初始化代码。

值得指出的是,define定义的模块可以返回任何值,不限于对象。

(2)非独立模块

如果被定义的模块需要依赖其他模块,则define方法必须采用下面的格式。

  1. define([‘module1’, ‘module2’], function(m1, m2) {
  2. });

define方法的*个参数是一个数组,它的成员是当前模块所依赖的模块。比如,[‘module1’, ‘module2’]表示我们定义的这个新模块依赖于module1模块和module2模块,只有先加载这两个模块,新模块才能正常运行。一般情况下,module1模块和module2模块指的是,当前目录下的module1.js文件和module2.js文件,等同于写成[’./module1’, ‘./module2’]。

define方法的第二个参数是一个函数,当前面数组的所有成员加载成功后,它将被调用。它的参数与数组的成员一一对应,比如function(m1, m2)就表示,这个函数的*个参数m1对应module1模块,第二个参数m2对应module2模块。这个函数必须返回一个对象,供其他模块调用。

  1. define([‘module1’, ‘module2’], function(m1, m2) {
  2. return {
  3. method: function() {
  4. m1.methodA();
  5. m2.methodB();
  6. }
  7. };
  8. });

上面代码表示新模块返回一个对象,该对象的method方法就是外部调用的接口,menthod方法内部调用了m1模块的methodA方法和m2模块的methodB方法。

需要注意的是,回调函数必须返回一个对象,这个对象就是你定义的模块。

如果依赖的模块很多,参数与模块一一对应的写法非常麻烦。

  1. define(
  2. [ ‘dep1’, ‘dep2’, ‘dep3’, ‘dep4’, ‘dep5’, ‘dep6’, ‘dep7’, ‘dep8’],
  3. function(dep1, dep2, dep3, dep4, dep5, dep6, dep7, dep8){
  4. }
  5. );

为了避免像上面代码那样繁琐的写法,RequireJS提供一种更简单的写法。

  1. define(
  2. function (require) {
  3. var dep1 = require(‘dep1’),
  4. dep2 = require(‘dep2’),
  5. dep3 = require(‘dep3’),
  6. dep4 = require(‘dep4’),
  7. dep5 = require(‘dep5’),
  8. dep6 = require(‘dep6’),
  9. dep7 = require(‘dep7’),
  10. dep8 = require(‘dep8’);
  11. }
  12. });

下面是一个define实际运用的例子。

  1. define([‘math’, ‘graph’],
  2. function ( math, graph ) {
  3. return {
  4. plot: function(x, y){
  5. return graph.drawPie(math.randomGrid(x,y));
  6. }
  7. }
  8. };
  9. );

上面代码定义的模块依赖math和graph两个库,然后返回一个具有plot接口的对象。

另一个实际的例子是,通过判断浏览器是否为IE,而选择加载zepto或jQuery。

  1. define((‘__proto__’ in {} ? [‘zepto’] : [‘jquery’]), function($) {
  2. return $;
  3. });

上面代码定义了一个中间模块,该模块先判断浏览器是否支持__proto__属性(除了IE,其他浏览器都支持),如果返回true,就加载zepto库,否则加载jQuery库。

require方法:调用模块

require方法用于调用模块。它的参数与define方法类似。

  1. require([‘foo’, ‘bar’], function ( foo, bar ) {
  2. foo.doSomething();
  3. });

上面方法表示加载foo和bar两个模块,当这两个模块都加载成功后,执行一个回调函数。该回调函数就用来完成具体的任务。

require方法的*个参数,是一个表示依赖关系的数组。这个数组可以写得很灵活,请看下面的例子。

  1. require( [ window.JSON ? undefined : ‘util/json2’ ], function ( JSON ) {
  2. JSON = JSON || window.JSON;
  3. console.log( JSON.parse( ‘{ “JSON” : “HERE” }’ ) );
  4. });

上面代码加载JSON模块时,首先判断浏览器是否原生支持JSON对象。如果是的,则将undefined传入回调函数,否则加载util目录下的json2模块。

require方法也可以用在define方法内部。

  1. define(function (require) {
  2. var otherModule = require(‘otherModule’);
  3. });

下面的例子显示了如何动态加载模块。

  1. define(function ( require ) {
  2. var isReady = false, foobar;
  3. require([‘foo’, ‘bar’], function (foo, bar) {
  4. isReady = true;
  5. foobar = foo() + bar();
  6. });
  7. return {
  8. isReady: isReady,
  9. foobar: foobar
  10. };
  11. });

上面代码所定义的模块,内部加载了foo和bar两个模块,在没有加载完成前,isReady属性值为false,加载完成后就变成了true。因此,可以根据isReady属性的值,决定下一步的动作。

下面的例子是模块的输出结果是一个promise对象。

  1. define([‘lib/Deferred’], function( Deferred ){
  2. var defer = new Deferred();
  3. require([‘lib/templates/?index.html’,‘lib/data/?stats’],
  4. function( template, data ){
  5. defer.resolve({ template: template, data:data });
  6. }
  7. );
  8. return defer.promise();
  9. });

上面代码的define方法返回一个promise对象,可以在该对象的then方法,指定下一步的动作。

如果服务器端采用JSONP模式,则可以直接在require中调用,方法是指定JSONP的callback参数为define。

  1. require( [
  2. “http://someapi.com/foo?callback=define”
  3. ], function (data) {
  4. console.log(data);
  5. });

require方法允许添加第三个参数,即错误处理的回调函数。

  1. require(
  2. [ “backbone” ],
  3. function ( Backbone ) {
  4. return Backbone.View.extend({ /* … */ });
  5. },
  6. function (err) {
  7. // …
  8. }
  9. );

require方法的第三个参数,即处理错误的回调函数,接受一个error对象作为参数。

require对象还允许指定一个全局性的Error事件的监听函数。所有没有被上面的方法捕获的错误,都会被触发这个监听函数。

  1. requirejs.onError = function (err) {
  2. // …
  3. };

AMD模式小结

define和require这两个定义模块、调用模块的方法,合称为AMD模式。它的模块定义的方法非常清晰,不会污染全局环境,能够清楚地显示依赖关系。

AMD模式可以用于浏览器环境,并且允许非同步加载模块,也可以根据需要动态加载模块。

配置require.js:config方法

require方法本身也是一个对象,它带有一个config方法,用来配置require.js运行参数。config方法接受一个对象作为参数。

  1. require.config({
  2. paths: {
  3. jquery: [
  4. ‘//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.0/jquery.min.js’,
  5. ‘lib/jquery’
  6. ]
  7. }
  8. });

config方法的参数对象有以下主要成员:

(1)paths

paths参数指定各个模块的位置。这个位置可以是同一个服务器上的相对位置,也可以是外部网址。可以为每个模块定义多个位置,如果*个位置加载失败,则加载第二个位置,上面的示例就表示如果CDN加载失败,则加载服务器上的备用脚本。需要注意的是,指定本地文件路径时,可以省略文件*后的js后缀名。

  1. require([“jquery”], function($) {
  2. // …
  3. });

上面代码加载jquery模块,因为jquery的路径已经在paths参数中定义了,所以就会到事先设定的位置下载。

(2)baseUrl

baseUrl参数指定本地模块位置的基准目录,即本地模块的路径是相对于哪个目录的。该属性通常由require.js加载时的data-main属性指定。

(3)shim

有些库不是AMD兼容的,这时就需要指定shim属性的值。shim可以理解成“垫片”,用来帮助require.js加载非AMD规范的库。

  1. require.config({
  2. paths: {
  3. “backbone”: “vendor/backbone”,
  4. “underscore”: “vendor/underscore”
  5. },
  6. shim: {
  7. “backbone”: {
  8. deps: [ “underscore” ],
  9. exports: “Backbone”
  10. },
  11. “underscore”: {
  12. exports: “_”
  13. }
  14. }
  15. });

上面代码中的backbone和underscore就是非AMD规范的库。shim指定它们的依赖关系(backbone依赖于underscore),以及输出符号(backbone为“Backbone”,underscore为“_”)。

插件

RequireJS允许使用插件,加载各种格式的数据。完整的插件清单可以查看官方网站

下面是插入文本数据所使用的text插件的例子。

  1. define([
  2. ‘backbone’,
  3. ‘text!templates.html’
  4. ], function( Backbone, template ){
  5. // …
  6. });

上面代码加载的*个模块是backbone,第二个模块则是一个文本,用’text!’表示。该文本作为字符串,存放在回调函数的template变量中。

JDBC连接池、监控组件 Druid简介

Druid是一个JDBC组件,它包括三部分:

  • DruidDriver 代理Driver,能够提供基于Filter-Chain模式的插件体系。
  • DruidDataSource 高效可管理的数据库连接池。
  • SQLParser

Druid可以做什么?

1) 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。

2) 替换DBCPC3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。

3) 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。

4) SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-LoggingLog4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。

扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter-Chain机制,很方便编写JDBC层的扩展插件。

如下是一个基于Druid内置扩展StatFilter的监控实现:

%title插图%num

Druid 的 JavaDoc 文档请看

http://tool.oschina.net/apidocs/apidoc?api=druid0.26