<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>杰克，快跑！ &#187; 软件开发</title>
	<atom:link href="http://blog.jackrun.com/archives/category/development/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.jackrun.com</link>
	<description>busy to live or busy to die</description>
	<lastBuildDate>Fri, 18 Jun 2010 09:15:30 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Hadoop配置及安装部署</title>
		<link>http://blog.jackrun.com/archives/559.html</link>
		<comments>http://blog.jackrun.com/archives/559.html#comments</comments>
		<pubDate>Mon, 26 Apr 2010 06:41:47 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[hadoop]]></category>

		<guid isPermaLink="false">http://blog.jackrun.com/?p=559</guid>
		<description><![CDATA[以前博客上的老文，最近又重新在搞hadoop，转过来方便查阅
硬件环境
共有3台机器，均使用的FC5系统，Java使用的是jdk1.6.0。IP配置如下：
dbrg-1：202.197.18.72
dbrg-2：202.197.18.73
dbrg-3：202.197.18.74
这里有一点需要强调的就是，务必要确保每台机器的主机名和IP地址之间能正确解析。
一个很简单的测试办法就是ping一下主机名，比如在dbrg-1上ping dbrg-2，如果能ping通就OK！若不能正确解析，可以修改/etc/hosts文件，如果该台机器作Namenode用，则需要在hosts文件中加上集群中所有机器的IP地址及其对应的主机名；如果该台机器作Datanode用，则只需要在hosts文件中加上本机IP地址和Namenode机器的IP地址。
以本文为例，dbrg-1中的/etc/hosts文件看起来就应该是这样的：
127.0.0.0         localhost     localhost
202.197.18.72     dbrg-1        dbrg-1
202.197.18.73     dbrg-2        dbrg-2
202.197.18.74     dbrg-3        dbrg-3
dbrg-2中的/etc/hosts文件看起来就应该是这样的：
127.0.0.0         localhost    localhost
202.197.18.72     dbrg-1       dbrg-1
202.197.18.73     dbrg-2       dbrg-2
在上一篇学习笔记中提到过，对于Hadoop来说，在HDFS看来，节点分为Namenode和Datanode，其中Namenode只有一个，Datanode可以是很多；在MapReduce看来，节点又分为Jobtracker和Tasktracker，其中Jobtracker只有一个，Tasktracker可以是很多。
我是将namenode和jobtracker部署在dbrg-1上，dbrg-2,dbrg-3作为datanode和tasktracker。当然你也可以将namenode，datanode，jobtracker，tasktracker全部部署在一台机器上
 目录结构
由于Hadoop要求所有机器上hadoop的部署目录结构要相同，并且都有一个相同的用户名的帐户。
我的三台机器上是这样的：都有一个dbrg的帐户，主目录是/home/dbrg
Hadoop部署目录结构如下：/home/dbrg/HadoopInstall，所有的hadoop版本放在这个目录中。
将hadoop0.12.0压缩包解压至HadoopInstall中，为了方便以后升级，建议建立一个链接指向要使用的hadoop版本，不妨设为hadoop
[dbrg@dbrg-1:HadoopInstall]$ln -s hadoop0.12.0   hadoop
这样一来，所有的配置文件都在/hadoop/conf/目录中，所有执行程序都在/hadoop/bin目录中。
但是由于上述目录中hadoop的配置文件和hadoop的安装目录是放在一起的，这样一旦日后升级hadoop版本的时候所有的配置文件都会被覆盖，因此建议将配置文件与安装目录分离，一种比较好的方法就是建立一个存放配置文件的目录，/home/dbrg/HadoopInstall/hadoop-config/，然后将/hadoop/conf/目录中的hadoop_site.xml，slaves，hadoop_env.sh三个文件拷贝到hadoop-config/目录中(这个问题很奇怪，在官网上的Getting Started With Hadoop中说是只需要拷贝这个三个文件到自己创建的目录就可以了，但我在实际配置的时候发现还必须把masters这个文件也拷贝到hadoop-conf/目录中才行，不然启动Hadoop的时候就会报错说找不到masters这个文件)，并指定环境变量$HADOOP_CONF_DIR指向该目录。环境变量在/home/dbrg/.bashrc和/etc/profile中设定。
综上所述，为了方便以后升级版本，我们需要做到配置文件与安装目录分离，并通过设定一个指向我们要使用的版本的hadoop的链接，这样可以减少我们对配置文件的维护。在下面的部分，你就会体会到这样分离以及链接的好处了。
SSH设置
在Hadoop启动以后，Namenode是通过SSH（Secure Shell）来启动和停止各个节点上的各种守护进程的，这就需要在节点之间执行指令的时候是不需要输入密码的方式，故我们需要配置SSH使用无密码公钥认证的方式。
首先要保证每台机器上都装了SSH服务器，且都正常启动。实际中我们用的都是OpenSSH，这是SSH协议的一个免费开源实现。FC5中默认安装的OpenSSH版本是OpenSSH4.3P2。
以本文中的三台机器为例，现在dbrg-1是主节点，它需要主动发起SSH连接到dbrg-2和dbrg-3，对于SSH服务来说，dbrg-1就是SSH客户端，而dbrg-2、dbrg-3则是SSH服务端，因此在dbrg-2，dbrg-3上需要确定sshd服务已经启动。简单的说，在dbrg-1上需要生成一个密钥对，即一个私钥，一个公钥。将公钥拷贝到dbrg-2，dbrg-3上，这样，比如当dbrg-1向dbrg-2发起ssh连接的时候，dbrg-2上就会生成一个随机数并用dbrg-1的公钥对这个随机数进行加密，并发送给dbrg-1；dbrg-1收到这个加密的数以后用私钥进行解密，并将解密后的数发送回dbrg-2，dbrg-2确认解密的数无误后就允许dbrg-1进行连接了。这就完成了一次公钥认证过程。
对于本文中的三台机器，首先在dbrg-1上生成密钥对：
[dbrg@dbrg-1:~]$ssh-keygen -t rsa
这个命令将为dbrg-1上的用户dbrg生成其密钥对，询问其保存路径时直接回车采用默认路径，当提示要为生成的密钥输入passphrase的时候，直接回车，也就是将其设定为空密码。生成的密钥对id_rsa，id_rsa.pub，默认存储在/home/dbrg/.ssh目录下。然后将id_rsa.pub的内容复制到每个机器(也包括本机)的/home/dbrg/.ssh/authorized_keys文件中，如果机器上已经有authorized_keys这个文件了，就在文件末尾加上id_rsa.pub中的内容，如果没有authorized_keys这个文件，直接cp或者scp就好了，下面的操作假设各个机器上都没有authorized_keys文件。
对于dbrg-1
[dbrg@dbrg-1:.ssh]$cp id_rsa.pub authorized_keys
对于dbrg-2（dbrg-3同dbrg-2的方法）
[dbrg@dbrg-2:~]$mkdir .ssh
[dbrg@dbrg-1:.ssh]$scp authorized_keys dbrg-2:/home/dbrg/.ssh/
此处的scp就是通过ssh进行远程copy，此处需要输入远程主机的密码，即dbrg-2机器上dbrg帐户的密码，当然，你也可以用其他方法将authorized_keys文件拷贝到其他机器上
[dbrg@dbrg-2:.ssh]$chmod 644 authorized_keys
这一步非常关键，必须保证authorized_keys只对其所有者有读写权限，其他人不允许有写的权限，否则SSH是不会工作的。我就曾经在配置SSH的时候郁闷了好久。
[dbrg@dbrg-2:.ssh]ls -la
drwx&#8212;&#8212; 2 dbrg dbrg .
drwx&#8212;&#8212; 3 dbrg dbrg ..
-rw-r&#8211;r&#8211; 1 dbrg dbrg authorized_keys
注意每个机器上的.ssh目录的ls -la都应该和上面是一样的
接着，在三台机器上都需要对sshd服务进行配置(其实是可以不用配置的，完成了上面的那些操作了以后SSH就已经可以工作了)，在三台机器上修改文件/etc/ssh/sshd_config
#去除密码认证
PasswordAuthentication no
AuthorizedKeyFile   .ssh/authorized_keys
至此各个机器上的SSH配置已经完成，可以测试一下了，比如dbrg-1向dbrg-2发起ssh连接
[dbrg@dbrg-1:~]$ssh dbrg-2
如果ssh配置好了，就会出现以下提示信息
The authenticity of host [dbrg-2] can&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>以前博客上的老文，最近又重新在搞hadoop，转过来方便查阅</p>
<p>硬件环境<br />
共有3台机器，均使用的FC5系统，Java使用的是jdk1.6.0。IP配置如下：<br />
dbrg-1：202.197.18.72<br />
dbrg-2：202.197.18.73<br />
dbrg-3：202.197.18.74</p>
<p>这里有一点需要强调的就是，务必要确保每台机器的主机名和IP地址之间能正确解析。</p>
<p>一个很简单的测试办法就是ping一下主机名，比如在dbrg-1上ping dbrg-2，如果能ping通就OK！若不能正确解析，可以修改/etc/hosts文件，如果该台机器作Namenode用，则需要在hosts文件中加上集群中所有机器的IP地址及其对应的主机名；如果该台机器作Datanode用，则只需要在hosts文件中加上本机IP地址和Namenode机器的IP地址。</p>
<p>以本文为例，dbrg-1中的/etc/hosts文件看起来就应该是这样的：<br />
127.0.0.0         localhost     localhost<br />
202.197.18.72     dbrg-1        dbrg-1<br />
202.197.18.73     dbrg-2        dbrg-2<br />
202.197.18.74     dbrg-3        dbrg-3</p>
<p>dbrg-2中的/etc/hosts文件看起来就应该是这样的：<br />
127.0.0.0         localhost    localhost<br />
202.197.18.72     dbrg-1       dbrg-1<br />
202.197.18.73     dbrg-2       dbrg-2</p>
<p>在上一篇学习笔记中提到过，对于Hadoop来说，在HDFS看来，节点分为Namenode和Datanode，其中Namenode只有一个，Datanode可以是很多；在MapReduce看来，节点又分为Jobtracker和Tasktracker，其中Jobtracker只有一个，Tasktracker可以是很多。<br />
我是将namenode和jobtracker部署在dbrg-1上，dbrg-2,dbrg-3作为datanode和tasktracker。当然你也可以将namenode，datanode，jobtracker，tasktracker全部部署在一台机器上</p>
<p><span id="more-559"></span> 目录结构<br />
由于Hadoop要求所有机器上hadoop的部署目录结构要相同，并且都有一个相同的用户名的帐户。<br />
我的三台机器上是这样的：都有一个dbrg的帐户，主目录是/home/dbrg<br />
Hadoop部署目录结构如下：/home/dbrg/HadoopInstall，所有的hadoop版本放在这个目录中。<br />
将hadoop0.12.0压缩包解压至HadoopInstall中，为了方便以后升级，建议建立一个链接指向要使用的hadoop版本，不妨设为hadoop<br />
[dbrg@dbrg-1:HadoopInstall]$ln -s hadoop0.12.0   hadoop<br />
这样一来，所有的配置文件都在/hadoop/conf/目录中，所有执行程序都在/hadoop/bin目录中。<br />
但是由于上述目录中hadoop的配置文件和hadoop的安装目录是放在一起的，这样一旦日后升级hadoop版本的时候所有的配置文件都会被覆盖，因此建议将配置文件与安装目录分离，一种比较好的方法就是建立一个存放配置文件的目录，/home/dbrg/HadoopInstall/hadoop-config/，然后将/hadoop/conf/目录中的hadoop_site.xml，slaves，hadoop_env.sh三个文件拷贝到hadoop-config/目录中(这个问题很奇怪，在官网上的<a title="Getting Started With Hadoop" href="http://wiki.apache.org/lucene-hadoop/GettingStartedWithHadoop"><span style="color: #009933;">Getting Started With Hadoop</span></a>中说是只需要拷贝这个三个文件到自己创建的目录就可以了，但我在实际配置的时候发现还必须把masters这个文件也拷贝到hadoop-conf/目录中才行，不然启动Hadoop的时候就会报错说找不到masters这个文件)，并指定环境变量$HADOOP_CONF_DIR指向该目录。环境变量在/home/dbrg/.bashrc和/etc/profile中设定。<br />
综上所述，为了方便以后升级版本，我们需要做到配置文件与安装目录分离，并通过设定一个指向我们要使用的版本的hadoop的链接，这样可以减少我们对配置文件的维护。在下面的部分，你就会体会到这样分离以及链接的好处了。<br />
SSH设置<br />
在Hadoop启动以后，Namenode是通过<a title="SSH" href="http://www.ssh.com/products/ssh_secure_shell/"><span style="color: #009933;">SSH</span></a>（Secure Shell）来启动和停止各个节点上的各种守护进程的，这就需要在节点之间执行指令的时候是不需要输入密码的方式，故我们需要配置SSH使用无密码公钥认证的方式。<br />
首先要保证每台机器上都装了SSH服务器，且都正常启动。实际中我们用的都是<a title="OpenSSH" href="http://www.openssh.com/"><span style="color: #009933;">OpenSSH</span></a>，这是SSH协议的一个免费开源实现。FC5中默认安装的OpenSSH版本是OpenSSH4.3P2。<br />
以本文中的三台机器为例，现在dbrg-1是主节点，它需要主动发起SSH连接到dbrg-2和dbrg-3，对于SSH服务来说，dbrg-1就是SSH客户端，而dbrg-2、dbrg-3则是SSH服务端，因此在dbrg-2，dbrg-3上需要确定sshd服务已经启动。简单的说，在dbrg-1上需要生成一个密钥对，即一个私钥，一个公钥。将公钥拷贝到dbrg-2，dbrg-3上，这样，比如当dbrg-1向dbrg-2发起ssh连接的时候，dbrg-2上就会生成一个随机数并用dbrg-1的公钥对这个随机数进行加密，并发送给dbrg-1；dbrg-1收到这个加密的数以后用私钥进行解密，并将解密后的数发送回dbrg-2，dbrg-2确认解密的数无误后就允许dbrg-1进行连接了。这就完成了一次公钥认证过程。</p>
<p>对于本文中的三台机器，首先在dbrg-1上生成密钥对：<br />
[dbrg@dbrg-1:~]$ssh-keygen -t rsa<br />
这个命令将为dbrg-1上的用户dbrg生成其密钥对，询问其保存路径时直接回车采用默认路径，当提示要为生成的密钥输入passphrase的时候，直接回车，也就是将其设定为空密码。生成的密钥对id_rsa，id_rsa.pub，默认存储在/home/dbrg/.ssh目录下。然后将id_rsa.pub的内容复制到每个机器(也包括本机)的/home/dbrg/.ssh/authorized_keys文件中，如果机器上已经有authorized_keys这个文件了，就在文件末尾加上id_rsa.pub中的内容，如果没有authorized_keys这个文件，直接cp或者scp就好了，下面的操作假设各个机器上都没有authorized_keys文件。</p>
<p>对于dbrg-1<br />
[dbrg@dbrg-1:.ssh]$cp id_rsa.pub authorized_keys</p>
<p>对于dbrg-2（dbrg-3同dbrg-2的方法）<br />
[dbrg@dbrg-2:~]$mkdir .ssh<br />
[dbrg@dbrg-1:.ssh]$scp authorized_keys dbrg-2:/home/dbrg/.ssh/<br />
此处的scp就是通过ssh进行远程copy，此处需要输入远程主机的密码，即dbrg-2机器上dbrg帐户的密码，当然，你也可以用其他方法将authorized_keys文件拷贝到其他机器上</p>
<p>[dbrg@dbrg-2:.ssh]$chmod 644 authorized_keys<br />
这一步非常关键，必须保证authorized_keys只对其所有者有读写权限，其他人不允许有写的权限，否则SSH是不会工作的。我就曾经在配置SSH的时候郁闷了好久。</p>
<p>[dbrg@dbrg-2:.ssh]ls -la<br />
drwx&#8212;&#8212; 2 dbrg dbrg .<br />
drwx&#8212;&#8212; 3 dbrg dbrg ..<br />
-rw-r&#8211;r&#8211; 1 dbrg dbrg authorized_keys<br />
注意每个机器上的.ssh目录的ls -la都应该和上面是一样的</p>
<p>接着，在三台机器上都需要对sshd服务进行配置(其实是可以不用配置的，完成了上面的那些操作了以后SSH就已经可以工作了)，在三台机器上修改文件/etc/ssh/sshd_config<br />
#去除密码认证<br />
PasswordAuthentication no<br />
AuthorizedKeyFile   .ssh/authorized_keys</p>
<p>至此各个机器上的SSH配置已经完成，可以测试一下了，比如dbrg-1向dbrg-2发起ssh连接<br />
[dbrg@dbrg-1:~]$ssh dbrg-2<br />
如果ssh配置好了，就会出现以下提示信息<br />
The authenticity of host [dbrg-2] can&#8217;t be established.<br />
Key fingerprint is 1024 5f:a0:0b:65:d3:82:df:ab:44:62:6d:98:9c:fe:e9:52.<br />
Are you sure you want to continue connecting (yes/no)?<br />
OpenSSH告诉你它不知道这台主机，但是你不用担心这个问题，因为你是第一次登录这台主机。键入“yes”。这将把这台主机的“识别标记”加到“~/.ssh/know_hosts”文件中。第二次访问这台主机的时候就不会再显示这条提示信息了。<br />
然后你会发现不需要输入密码就可以建立ssh连接了，恭喜你，配置成功了<br />
不过，别忘了测试本机ssh dbrg-1<br />
Hadoop环境变量<br />
在/home/dbrg/HadoopInstall/hadoop-conf目录下的hadoop_env.sh中设置Hadoop需要的环境变量，其中JAVA_HOME是必须设定的变量。HADOOP_HOME变量可以设定也可以不设定，如果不设定，HADOOP_HOME默认的是bin目录的父目录，即本文中的/home/dbrg/HadoopInstall/hadoop。我的是这样设置的<br />
export HADOOP_HOME=/home/dbrg/HadoopInstall/hadoop<br />
export JAVA_HOME=/usr/java/jdk1.6.0<br />
从这个地方就可以看出前面所述的创建hadoop0.12.0的链接hadoop的优点了，当以后更新hadoop的版本的时候，就不需要在改配置文件，只需要更改链接就可以了。<br />
Hadoop配置文件<br />
如前所述，在hadoop-conf/目录下，打开slaves文件，该文件用来指定所有的从节点，一行指定一个主机名。即本文中的dbrg-2，dbrg-3，因此slaves文件看起来应该是这样的<br />
dbrg-2<br />
dbrg-3<br />
在conf/目录中的hadoop-default.xml中包含了Hadoop的所有配置项，但是不允许直接修改！可以在hadoop-conf/目录下的hadoop-site.xml里面定义我们需要的项，其值会覆盖hadoop-default.xml中的默认值。可以根据自己的实际需要来进行定制。以下是我的配置档：<br />
&lt;?xml version=&#8221;1.0&#8243;?&gt;<br />
&lt;?xml-stylesheet type=&#8221;text/xsl&#8221; href=&#8221;configuration.xsl&#8221;?&gt;<br />
&lt;!&#8211; Put site-specific property overrides in this file. &#8211;&gt;<br />
&lt;configuration&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;fs.default.name&lt;/name&gt;<br />
&lt;value&gt;dbrg-1:9000&lt;/value&gt;<br />
&lt;description&gt;The name of the default file system. Either the literal string &#8220;local&#8221; or a host:port for DFS.&lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;mapred.job.tracker&lt;/name&gt;<br />
&lt;value&gt;dbrg-1:9001&lt;/value&gt;<br />
&lt;description&gt;The host and port that the MapReduce job tracker runs at. If &#8220;local&#8221;, then jobs are run in-process as a single map and reduce task.&lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;hadoop.tmp.dir&lt;/name&gt;<br />
&lt;value&gt;/home/dbrg/HadoopInstall/tmp&lt;/value&gt;<br />
&lt;description&gt;A base for other temporary directories.&lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;dfs.name.dir&lt;/name&gt;<br />
&lt;value&gt;/home/dbrg/HadoopInstall/filesystem/name&lt;/value&gt;<br />
&lt;description&gt;Determines where on the local filesystem the DFS name node should store the name table. If this is a comma-delimited list of directories then the name table is replicated in all of the directories, for redundancy. &lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;dfs.data.dir&lt;/name&gt;<br />
&lt;value&gt;/home/dbrg/HadoopInstall/filesystem/data&lt;/value&gt;<br />
&lt;description&gt;Determines where on the local filesystem an DFS data node should store its blocks. If this is a comma-delimited list of directories, then data will be stored in all named directories, typically on different devices. Directories that do not exist are ignored.&lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;property&gt;<br />
&lt;name&gt;dfs.replication&lt;/name&gt;<br />
&lt;value&gt;1&lt;/value&gt;<br />
&lt;description&gt;Default block replication. The actual number of replications can be specified when the file is created. The default is used if replication is not specified in create time.&lt;/description&gt;<br />
&lt;/property&gt;<br />
&lt;/configuration&gt;<br />
部署Hadoop<br />
前面讲的这么多Hadoop的环境变量和配置文件都是在dbrg-1这台机器上的，现在需要将hadoop部署到其他的机器上，保证目录结构一致。<br />
[dbrg@dbrg-1:~]$scp -r /home/dbrg/HadoopInstall dbrg-2:/home/dbrg/<br />
[dbrg@dbrg-1:~]$scp -r /home/dbrg/HadoopInstall dbrg-3:/home/dbrg/<br />
至此，可以说，Hadoop已经在各个机器上部署完毕了下面就让我们开始启动Hadoop吧<br />
启动Hadoop<br />
启动之前，我们先要格式化namenode，先进入~/HadoopInstall/hadoop目录，执行下面的命令<br />
[dbrg@dbrg-1:hadoop]$bin/hadoop namenode -format<br />
不出意外，应该会提示格式化成功。如果不成功，就去hadoop/logs/目录下去查看日志文件<br />
下面就该正式启动hadoop啦，在bin/下面有很多启动脚本，可以根据自己的需要来启动。<br />
* start-all.sh 启动所有的Hadoop守护。包括namenode, datanode, jobtracker, tasktrack<br />
* stop-all.sh 停止所有的Hadoop<br />
* start-mapred.sh 启动Map/Reduce守护。包括Jobtracker和Tasktrack<br />
* stop-mapred.sh 停止Map/Reduce守护<br />
* start-dfs.sh 启动Hadoop DFS守护.Namenode和Datanode<br />
* stop-dfs.sh 停止DFS守护</p>
<p>在这里，简单启动所有守护<br />
[dbrg@dbrg-1:hadoop]$bin/start-all.sh</p>
<p>同样，如果要停止hadoop，则<br />
[dbrg@dbrg-1:hadoop]$bin/stop-all.sh<br />
HDFS操作<br />
运行bin/目录的hadoop命令，可以查看Haoop所有支持的操作及其用法，这里以几个简单的操作为例。</p>
<p>建立目录<br />
[dbrg@dbrg-1:hadoop]$bin/hadoop dfs -mkdir testdir<br />
在HDFS中建立一个名为testdir的目录</p>
<p>复制文件<br />
[dbrg@dbrg-1:hadoop]$bin/hadoop dfs -put /home/dbrg/large.zip testfile.zip<br />
把本地文件large.zip拷贝到HDFS的根目录/user/dbrg/下，文件名为testfile.zip</p>
<p>查看现有文件<br />
[dbrg@dbrg-1:hadoop]$bin/hadoop dfs -ls</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/559.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>从HTTP状态 301，302，200 来看页面跳转</title>
		<link>http://blog.jackrun.com/archives/463.html</link>
		<comments>http://blog.jackrun.com/archives/463.html#comments</comments>
		<pubDate>Mon, 30 Mar 2009 08:03:46 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[301跳转]]></category>
		<category><![CDATA[302跳转]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=463</guid>
		<description><![CDATA[301和302 Http状态有啥区别？
301，302 都是HTTP状态的编码，都代表着某个URL发生了转移，不同之处在于：
301 redirect: 301 代表永久性转移(Permanently Moved)，
302 redirect: 302 代表暂时性转移(Temporarily Moved )，
当然　Http 状态 200 标示没有任何问题发生。
 
这两种转移在使用的时候有啥好处或者问题？
301 重定向是网页更改地址后对搜索引擎友好的最好方法，只要不是暂时搬移的情况,都建议使用301来做转址。
302 重定向是临时性转移。
在前些年，不少Black Hat SEO曾广泛应用这项技术作弊，目前，各大主要搜索引擎均加强了打击力度，象Google前些年对Business.com以及近来对BMW德国网站的惩罚。即使网站客观上不是spam，也很容易被搜寻引擎容易误判为spam而遭到惩罚。

研究搜索引擎优化（SEO）的人，应该都知道，301，302　使用不当，或者灵活使用会有不错的效果的，比如参看下面文章：
302转向与网址劫持
301转向和网址规范化
301重定向的实现方法
51window提供的301转向的代码
一个网站十几个域名的重定向经验谈
几个常用的301重定向
 
 
如果是运维人员，配置WEB服务器的一些设置就可以实现跳转，比如下面一些关于IIS实现重定向的文章
将请求重定向到文件、目录或程序 (IIS 6.0)
http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/fbcccfce-6695-4f92-bd55-869d85ff49fb.mspx?mfr=true
重定向参考 (IIS 6.0)
http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/41c238b2-1188-488f-bf2d-464383b1bb08.mspx?mfr=true
其他WEB服务器也可以通过设置实现跳转，我就不罗列了。
 
 
从技术人员来说我们比较常用的跳转方法有以下几种：
我们使用 Fiddler 工具来监控的下面提到的几种方法，看跳转过程中HTTP状态码是301？302？200？：
 
方法1：Response.Redirect(&#8220;Test.aspx&#8221;);
状态码 301 临时性跳转
 
方法2：&#60;meta http-equiv=&#8221;refresh&#8221; content=&#8221;5; URL=Test.aspx&#8221; /&#62;
meta fresh: 这在2000年前比较流行，不过现在已很少见。其具体是通过网页中的meta指令，在特定时间后重定向到新的网页，如果延迟的时间太短(约5秒之內)，会被判断为spam。这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。
 
方法3：Server.Transfer(&#8220;Test.aspx&#8221;);
这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。
 
方法4：URLRewrite
这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。
 
没有一种是301跳转。也就是上面几种跳转方式都用不到301跳转的好处。
 
使用301跳转有啥好处呢？
SEO（搜索引擎优化）中提到一点：如果我们把一个地址采用301跳转方式跳转的话，搜索引擎会把老地址的PageRank等信息带到新地址，同时在搜索引擎索引库中彻底废弃掉原先的老地址。

如何编码实现301跳转呢？
Response.Status = &#8220;301 Moved Permanently&#8221;;
Response.AddHeader(&#8220;Location&#8221;,&#8221;&#8230;&#8221;);
这里的 &#8230; 表示你要跳转去的页面。
302重定向和网址劫持（URL hijacking）有什么关系呢？
这要从搜索引擎如何处理302转向说起。从定义来说，从网址A做一个302重定向到网址B时，主机服务器的隐含意思是网址A随时有可能改主意，重新显示本身的内容或转向其他的地方。大部分的搜索引擎在大部分情况下，当收到302重定向时，一般只要去抓取目标网址就可以了，也就是说网址B。
实际上如果搜索引擎在遇到302转向时，百分之百的都抓取目标网址B的话，就不用担心网址URL劫持了。
问题就在于，有的时候搜索引擎，尤其是Google，并不能总是抓取目标网址。为什么呢？比如说，有的时候A网址很短，但是它做了一个302重定向到B网址，而B网址是一个很长的乱七八糟的URL网址，甚至还有可能包含一些问号之类的参数。很自然的，A网址更加用户友好，而B网址既难看，又不用户友好。这时Google很有可能会仍然显示网址A。
由于搜索引擎排名算法只是程序而不是人，在遇到302重定向的时候，并不能像人一样的去准确判定哪一个网址更适当，这就造成了网址URL劫持的可能性。也就是说，一个不道德的人在他自己的网址A做一个302重定向到你的网址B，出于某种原因， Google搜索结果所显示的仍然是网址A，但是所用的网页内容却是你的网址B上的内容，这种情况就叫做网址URL劫持。你辛辛苦苦所写的内容就这样被别人偷走了。
怎样做301转向
如果你用的是Unix/Linux主机，可以用文件(Unix/Linux中用于目录特定指令如密码，转向，错误处理等的文件)。
比如把/old.htm转到http://www.domain.com/new.htm，可以用这个指令：
redirect 301 /old.htm http://www.domain.com/new.htm
或
redirect permanent /old.htm http://www.domain.com/new.htm
如果要把所有http://domain.com形式的URL用301重定向转到 http://www.domain.com，包括：
http://domain.com/about.htm
转到 http://www.domain.com/about.htm
及
http://domain.com/dir/index.htm
转到 http://www.domain.com/dir/index.htm
等等，还要用到mod_rewrite：
Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule [...]]]></description>
			<content:encoded><![CDATA[<div id="blog_text" class="cnt"><strong>301和302 Http状态有啥区别？</strong></div>
<div class="cnt">301，302 都是HTTP状态的编码，都代表着某个URL发生了转移，不同之处在于：</div>
<p>301 redirect: 301 代表永久性转移(Permanently Moved)，</p>
<p>302 redirect: 302 代表暂时性转移(Temporarily Moved )，</p>
<p>当然　Http 状态 200 标示没有任何问题发生。</p>
<p> </p>
<p><strong>这两种转移在使用的时候有啥好处或者问题？</strong></p>
<p>301 重定向是网页更改地址后对搜索引擎友好的最好方法，只要不是暂时搬移的情况,都建议使用301来做转址。</p>
<p>302 重定向是临时性转移。</p>
<p>在前些年，不少Black Hat SEO曾广泛应用这项技术作弊，目前，各大主要搜索引擎均加强了打击力度，象Google前些年对Business.com以及近来对BMW德国网站的惩罚。即使网站客观上不是spam，也很容易被搜寻引擎容易误判为spam而遭到惩罚。</p>
<p><span id="more-463"></span></p>
<p>研究搜索引擎优化（SEO）的人，应该都知道，301，302　使用不当，或者灵活使用会有不错的效果的，比如参看下面文章：</p>
<p>302转向与网址劫持</p>
<p>301转向和网址规范化</p>
<p>301重定向的实现方法<br />
51window提供的301转向的代码<br />
一个网站十几个域名的重定向经验谈<br />
几个常用的301重定向</p>
<p> </p>
<p> </p>
<p><strong>如果是运维人员，配置WEB服务器的一些设置就可以实现跳转，比如下面一些关于IIS实现重定向的文章</strong></p>
<p>将请求重定向到文件、目录或程序 (IIS 6.0)</p>
<p><a href="http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/fbcccfce-6695-4f92-bd55-869d85ff49fb.mspx?mfr=true" target="blank">http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/fbcccfce-6695-4f92-bd55-869d85ff49fb.mspx?mfr=true</a></p>
<p>重定向参考 (IIS 6.0)</p>
<p><a href="http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/41c238b2-1188-488f-bf2d-464383b1bb08.mspx?mfr=true" target="blank">http://www.microsoft.com/technet/prodtechnol/windowsserver2003/zh-chs/library/iis/41c238b2-1188-488f-bf2d-464383b1bb08.mspx?mfr=true</a></p>
<p>其他WEB服务器也可以通过设置实现跳转，我就不罗列了。</p>
<p> </p>
<p> </p>
<p><strong>从技术人员来说我们比较常用的跳转方法有以下几种：</strong></p>
<p>我们使用 Fiddler 工具来监控的下面提到的几种方法，看跳转过程中HTTP状态码是301？302？200？：</p>
<p> </p>
<p>方法1：Response.Redirect(&#8220;Test.aspx&#8221;);</p>
<p>状态码 301 临时性跳转</p>
<p> </p>
<p>方法2：&lt;meta http-equiv=&#8221;refresh&#8221; content=&#8221;5; URL=Test.aspx&#8221; /&gt;</p>
<p>meta fresh: 这在2000年前比较流行，不过现在已很少见。其具体是通过网页中的meta指令，在特定时间后重定向到新的网页，如果延迟的时间太短(约5秒之內)，会被判断为spam。这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。</p>
<p> </p>
<p>方法3：Server.Transfer(&#8220;Test.aspx&#8221;);</p>
<p>这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。</p>
<p> </p>
<p>方法4：URLRewrite</p>
<p>这种跳转方式，整个跳转过程中，页面Http状态都是200，即，页面没有任何错误发生。</p>
<p> </p>
<p>没有一种是301跳转。也就是上面几种跳转方式都用不到301跳转的好处。</p>
<p> </p>
<p>使用301跳转有啥好处呢？</p>
<p>SEO（搜索引擎优化）中提到一点：如果我们把一个地址采用301跳转方式跳转的话，搜索引擎会把老地址的PageRank等信息带到新地址，同时在搜索引擎索引库中彻底废弃掉原先的老地址。<br />
<strong><br />
如何编码实现301跳转呢？</strong></p>
<p>Response.Status = &#8220;301 Moved Permanently&#8221;;<br />
Response.AddHeader(&#8220;Location&#8221;,&#8221;&#8230;&#8221;);</p>
<p>这里的 &#8230; 表示你要跳转去的页面。<br />
<strong>302重定向和网址劫持（URL hijacking）有什么关系呢？</strong></p>
<p>这要从搜索引擎如何处理302转向说起。从定义来说，从网址A做一个302重定向到网址B时，主机服务器的隐含意思是网址A随时有可能改主意，重新显示本身的内容或转向其他的地方。大部分的搜索引擎在大部分情况下，当收到302重定向时，一般只要去抓取目标网址就可以了，也就是说网址B。<br />
实际上如果搜索引擎在遇到302转向时，百分之百的都抓取目标网址B的话，就不用担心网址URL劫持了。<br />
问题就在于，有的时候搜索引擎，尤其是Google，并不能总是抓取目标网址。为什么呢？比如说，有的时候A网址很短，但是它做了一个302重定向到B网址，而B网址是一个很长的乱七八糟的URL网址，甚至还有可能包含一些问号之类的参数。很自然的，A网址更加用户友好，而B网址既难看，又不用户友好。这时Google很有可能会仍然显示网址A。<br />
由于搜索引擎排名算法只是程序而不是人，在遇到302重定向的时候，并不能像人一样的去准确判定哪一个网址更适当，这就造成了网址URL劫持的可能性。也就是说，一个不道德的人在他自己的网址A做一个302重定向到你的网址B，出于某种原因， Google搜索结果所显示的仍然是网址A，但是所用的网页内容却是你的网址B上的内容，这种情况就叫做网址URL劫持。你辛辛苦苦所写的内容就这样被别人偷走了。</p>
<p><strong>怎样做301转向</strong></p>
<p>如果你用的是Unix/Linux主机，可以用文件(Unix/Linux中用于目录特定指令如密码，转向，错误处理等的文件)。</p>
<p>比如把/old.htm转到http://www.domain.com/new.htm，可以用这个指令：</p>
<p>redirect 301 /old.htm http://www.domain.com/new.htm</p>
<p>或</p>
<p>redirect permanent /old.htm http://www.domain.com/new.htm</p>
<p>如果要把所有http://domain.com形式的URL用301重定向转到 http://www.domain.com，包括：</p>
<p>http://domain.com/about.htm</p>
<p>转到 http://www.domain.com/about.htm</p>
<p>及</p>
<p>http://domain.com/dir/index.htm</p>
<p>转到 http://www.domain.com/dir/index.htm</p>
<p>等等，还要用到mod_rewrite：</p>
<p>Options +FollowSymLinks<br />
RewriteEngine on<br />
RewriteCond %{HTTP_HOST} ^domain.com [NC]<br />
RewriteRule ^(.*)$ http://www.domain.com/$1 [L,R=301]</p>
<p>如果你用的是 Windows主机，应该在控制面板做301转向设定。</p>
<p>HTML无法做301转向。在HTML里只能做JS或META REFRESH，但不是301转向。HTML一被读取，就已经返回200 OK状态码了。</p>
<p>如果你的页面是ASP或PHP还可以做301转向：</p>
<p> </p>
<div class="code_title">代码</div>
<p class="alt"><span><span>ASP：   </span></span><span>  </span></p>
<p class="alt"><span>&lt;%   </span></p>
<p><span>Response.Status=</span><span class="string">&#8220;301 Moved Permanently&#8221;</span><span> Response.AddHeader </span><span class="string">&#8220;Location&#8221;</span><span>, </span><span class="string">&#8221; http://www.domain.com&#8221;</span><span>  </span></p>
<p class="alt"><span>%&gt;   </span></p>
<p><span>  </span></p>
<p class="alt"><span>&lt;?PHP:   </span><span>  </span></p>
<p class="alt"><span>Header( “HTTP/</span><span class="number">1.1</span><span> </span><span class="number">301</span><span> Moved Permanently” );   </span></p>
<p><span>Header( “Location: http:</span><span class="comment">//www.domain.com” ); </span><span>  </span></p>
<p class="alt"><span>?&gt;  </span></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/463.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flex让我郁闷了</title>
		<link>http://blog.jackrun.com/archives/150.html</link>
		<comments>http://blog.jackrun.com/archives/150.html#comments</comments>
		<pubDate>Fri, 26 Oct 2007 03:16:04 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[Flex]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=150</guid>
		<description><![CDATA[前端时间项目中要用到图表，折线图和柱状图，因为不想去用JFreeChart生成图片，一大堆图片管理起来麻烦。就选择在客户端绘图，找了个js的chart开源工具，效果不怎么理想。无意间看到了FusionCharts，可惜他们是收费的。。
不过倒是收到了点启发，打算用Flex自己做一套图表工具，通过参数才传递需要显示的图表数据，中间细节不表，弄了3、4天，终于搞定，结果一看编译好的文件大小，傻了，一个swf文件就有将近300KB，这搞什么啊，我一个页面上两个图表一加载就是600KB，这哪受得了，只好放弃了，等adobe解决了问题再说吧。
哎，东西再好，再漂亮也没用，高速度是最好的用户体验！
]]></description>
			<content:encoded><![CDATA[<p>前端时间项目中要用到图表，折线图和柱状图，因为不想去用JFreeChart生成图片，一大堆图片管理起来麻烦。就选择在客户端绘图，找了个js的chart开源工具，效果不怎么理想。无意间看到了FusionCharts，可惜他们是收费的。。</p>
<p>不过倒是收到了点启发，打算用Flex自己做一套图表工具，通过参数才传递需要显示的图表数据，中间细节不表，弄了3、4天，终于搞定，结果一看编译好的文件大小，傻了，一个swf文件就有将近300KB，这搞什么啊，我一个页面上两个图表一加载就是600KB，这哪受得了，只好放弃了，等adobe解决了问题再说吧。</p>
<p>哎，东西再好，再漂亮也没用，高速度是最好的用户体验！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/150.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>推荐一个Eclipse的数据库插件</title>
		<link>http://blog.jackrun.com/archives/153.html</link>
		<comments>http://blog.jackrun.com/archives/153.html#comments</comments>
		<pubDate>Mon, 09 Apr 2007 05:13:01 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[Eclipse]]></category>
		<category><![CDATA[数据库插件]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=153</guid>
		<description><![CDATA[Quantum DB
http://quantum.sourceforge.net/
eclipse可以直接在这里更新
http://quantum.sourceforge.net/update-site
需要GEF插件
]]></description>
			<content:encoded><![CDATA[<p><span class="pn-normal"><strong>Quantum DB</strong></span></p>
<p><span class="pn-normal"><strong><a href="http://quantum.sourceforge.net/" target="_blank">http://quantum.sourceforge.net/</a></p>
<p>eclipse可以直接在这里更新</p>
<p></strong></span><strong>http://quantum.sourceforge.net/update-site</p>
<p>需要</strong><strong>GEF插件</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/153.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一种常用的权限控制算法的实现</title>
		<link>http://blog.jackrun.com/archives/155.html</link>
		<comments>http://blog.jackrun.com/archives/155.html#comments</comments>
		<pubDate>Sat, 09 Dec 2006 06:57:51 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[权限算法]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=155</guid>
		<description><![CDATA[这里介绍一种很常用，也比较专业的权限控制思路。这里用java语言描述，其实都差不多的。要换成其他的语言主，自己转一下就可以了。为了方便起见，我们这里定义a^b为：a的b次方。这里，我们为每一个操作设定一个唯一的整数值，比如：
删除Ａ－－－0
修改Ａ－－－1
添加Ａ－－－2
删除Ｂ－－－3
修改Ｂ－－－4
添加Ｂ－－－5
……
理论上可以有Ｎ个操作，这取决于你用于储存用户权限值的数据类型了。

这样，如果用户有权限：添加Ａ－－－2；删除Ｂ－－－3；修 改Ｂ－－－4。那用户的权限值 purview =2^2+2^3+2^4＝28，也就是2的权的和了。化成二进制可以表示为11100。这样，如果要验证用户是否有删除Ｂ的权限，就可以通过位与运算来实现。在Ｊａｖａ里，位与运算运算符号为＆，即是：
int value = purview &#38;((int)Math.pow(2,3));
你会发现，当用户有操作权限时，运算出来的结果都会等于这个操作需要的权限值！
原理：
位与运算，顾名思义就是对位进行与运算：
以上面的式子为例：purview &#38; 2^3 也就是　28&#38;8
将它们化成二进制有
11100
＆ 01000
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-
01000 == 8(十进制)　＝＝　2^3
同理，如果要验证是否有删除Ａ－－－0的权限
可以用：purview &#38;((int)Math.pow(2,0));
即：
11100
＆ 00001
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;
00000 == 0(十进制)　　！＝　2^0
这种算法的一个优点是速度快。可以同时处理Ｎ个权限。如果想验证是否同时有删除Ａ－－－0和删除Ｂ－－－3的权限，可以用purview&#38;(2^0+2^3)==(2^0+2^3)?true:false;设置多角色用户。根据权限值判断用户的角色。
下面提供一个java的单操作权限判断的代码：
//userPurview是用户具有的总权限
//optPurview是一个操作要求的权限为一个整数（没有经过权的！）
public static boolean checkPower(int userPurview, int optPurview)
{
int purviewValue = (int)Math.pow(2, optPurview);
return (userPurview &#38; purviewValue) == purviewValue;
}
当然，多权限的验证只要扩展一下就可以了。
几点注意事项：首先，一个系统可能有很多的操作，因此，请建立数据字典，以便查阅，修改时使用。其次，如果用数据库储存用户权限，请注意数值的有效范围。操作权限值请用唯一的整数！
]]></description>
			<content:encoded><![CDATA[<p>这里介绍一种很常用，也比较专业的权限控制思路。这里用java语言描述，其实都差不多的。要换成其他的语言主，自己转一下就可以了。为了方便起见，我们这里定义a^b为：a的b次方。这里，我们为每一个操作设定一个唯一的整数值，比如：</p>
<p>删除Ａ－－－0</p>
<p>修改Ａ－－－1</p>
<p>添加Ａ－－－2</p>
<p>删除Ｂ－－－3</p>
<p>修改Ｂ－－－4</p>
<p>添加Ｂ－－－5</p>
<p>……</p>
<p>理论上可以有Ｎ个操作，这取决于你用于储存用户权限值的数据类型了。</p>
<p><span id="more-155"></span></p>
<p>这样，如果用户有权限：添加Ａ－－－2；删除Ｂ－－－3；修 改Ｂ－－－4。那用户的权限值 purview =2^2+2^3+2^4＝28，也就是2的权的和了。化成二进制可以表示为11100。这样，如果要验证用户是否有删除Ｂ的权限，就可以通过位与运算来实现。在Ｊａｖａ里，位与运算运算符号为＆，即是：</p>
<p>int value = purview &amp;((int)Math.pow(2,3));</p>
<p>你会发现，当用户有操作权限时，运算出来的结果都会等于这个操作需要的权限值！</p>
<p>原理：</p>
<p>位与运算，顾名思义就是对位进行与运算：</p>
<p>以上面的式子为例：purview &amp; 2^3 也就是　28&amp;8</p>
<p>将它们化成二进制有</p>
<p>11100</p>
<p>＆ 01000</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>01000 == 8(十进制)　＝＝　2^3</p>
<p>同理，如果要验证是否有删除Ａ－－－0的权限</p>
<p>可以用：purview &amp;((int)Math.pow(2,0));</p>
<p>即：</p>
<p>11100</p>
<p>＆ 00001</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</p>
<p>00000 == 0(十进制)　　！＝　2^0</p>
<p>这种算法的一个优点是速度快。可以同时处理Ｎ个权限。如果想验证是否同时有删除Ａ－－－0和删除Ｂ－－－3的权限，可以用purview&amp;(2^0+2^3)==(2^0+2^3)?true:false;设置多角色用户。根据权限值判断用户的角色。</p>
<p>下面提供一个java的单操作权限判断的代码：</p>
<p>//userPurview是用户具有的总权限</p>
<p>//optPurview是一个操作要求的权限为一个整数（没有经过权的！）</p>
<p>public static boolean checkPower(int userPurview, int optPurview)</p>
<p>{</p>
<p>int purviewValue = (int)Math.pow(2, optPurview);</p>
<p>return (userPurview &amp; purviewValue) == purviewValue;</p>
<p>}</p>
<p>当然，多权限的验证只要扩展一下就可以了。</p>
<p>几点注意事项：首先，一个系统可能有很多的操作，因此，请建立数据字典，以便查阅，修改时使用。其次，如果用数据库储存用户权限，请注意数值的有效范围。操作权限值请用唯一的整数！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/155.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>程序员是如何捕猎大象的</title>
		<link>http://blog.jackrun.com/archives/158.html</link>
		<comments>http://blog.jackrun.com/archives/158.html#comments</comments>
		<pubDate>Thu, 02 Nov 2006 03:01:49 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[幽默]]></category>
		<category><![CDATA[程序员]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=158</guid>
		<description><![CDATA[CLIPPER程序员不去真的捕猎大象，他们只是购买大象部分的库，然后花几年的时间试图综合他们。
DBASE程序员只在夜间捕猎大象，因为那时没人会注意到他们还在使用石弓。
FOXPRO程序员开始使用更新更好的步枪，这使他们花掉比实际狩猎更多的时间学习新的射击技术。
C程序员拒绝直接购买步枪，宁可带着钢管和一个移动式机器车间到非洲，意欲从零开始造一支完美的步枪。
PARADOX程序员去非洲是带着好莱坞关于捕猎大象的电影剧本，他们认为照剧本行事就会逮到一头大象。
ACCESS程序员在没有任何猎象经验的前提下就出发了，他们穿着华丽的猎装、带着全部装备，用漂亮的望远镜找到了大象，然后发觉忘了带扳机。

RBASE程序员比大象好稀少，事实上，如果一头大象看到了一个RBASE程序员，对它来说是个幸运日。
VISUALACCESS程序员装上了子弹，举起步枪，瞄准大象，这使大象感到可笑，究竟谁逃跑呢？他们无法抓住大象，因为由于他们对多重控制的偏爱，他们的吉普车有太多的方向盘因而无法驾驶。
ADA、APL和FORTRAN程序员与圣诞老人、仙女一样是虚构的。
COBOL程序员对和自己一样濒临灭绝的大象给予了深切的同情。
VISUALC++程序员捕猎大象的效率很好，可惜要想真正的捕获那头大象，他们不得不抓紧时间趁那头大象还没老死前先学会自创的那套复杂的捕猎技术。
ASP和PHP程序员捕猎队伍总是最浩大，只要会举枪都能参加他们的队伍，而且他们始终保持有非常好的友谊关系，有时甚至不惜自己的战利品，慷慨的馈赠给一同的队友。
JAVA程序员太喜欢追求完美了，把打猎的步枪拆了又装、装了又拆，他们称这个叫做重构。他们的打猎技术的确很高明，这让其他的猎人羡慕不已，因为这个世界有个很厉害叫开源的家伙总是喜欢给他们提供无偿的各式各样的步枪、机枪、手枪……
C#程序员有天生的优越感，因为他们每次打猎都开着一辆牌子叫做VS的超级装甲车，羡煞旁人。
VB和DELPHI程序员各扛着枪走在捕猎的路上，狭路相逢，开始争吵谁的捕猎技术高明谁的枪打得准，以至于忘了任务是来打猎大象。
]]></description>
			<content:encoded><![CDATA[<p>CLIPPER程序员不去真的捕猎大象，他们只是购买大象部分的库，然后花几年的时间试图综合他们。</p>
<p>DBASE程序员只在夜间捕猎大象，因为那时没人会注意到他们还在使用石弓。</p>
<p>FOXPRO程序员开始使用更新更好的步枪，这使他们花掉比实际狩猎更多的时间学习新的射击技术。</p>
<p>C程序员拒绝直接购买步枪，宁可带着钢管和一个移动式机器车间到非洲，意欲从零开始造一支完美的步枪。</p>
<p>PARADOX程序员去非洲是带着好莱坞关于捕猎大象的电影剧本，他们认为照剧本行事就会逮到一头大象。</p>
<p>ACCESS程序员在没有任何猎象经验的前提下就出发了，他们穿着华丽的猎装、带着全部装备，用漂亮的望远镜找到了大象，然后发觉忘了带扳机。</p>
<p><span id="more-158"></span></p>
<p>RBASE程序员比大象好稀少，事实上，如果一头大象看到了一个RBASE程序员，对它来说是个幸运日。</p>
<p>VISUALACCESS程序员装上了子弹，举起步枪，瞄准大象，这使大象感到可笑，究竟谁逃跑呢？他们无法抓住大象，因为由于他们对多重控制的偏爱，他们的吉普车有太多的方向盘因而无法驾驶。</p>
<p>ADA、APL和FORTRAN程序员与圣诞老人、仙女一样是虚构的。</p>
<p>COBOL程序员对和自己一样濒临灭绝的大象给予了深切的同情。</p>
<p>VISUALC++程序员捕猎大象的效率很好，可惜要想真正的捕获那头大象，他们不得不抓紧时间趁那头大象还没老死前先学会自创的那套复杂的捕猎技术。</p>
<p>ASP和PHP程序员捕猎队伍总是最浩大，只要会举枪都能参加他们的队伍，而且他们始终保持有非常好的友谊关系，有时甚至不惜自己的战利品，慷慨的馈赠给一同的队友。</p>
<p>JAVA程序员太喜欢追求完美了，把打猎的步枪拆了又装、装了又拆，他们称这个叫做重构。他们的打猎技术的确很高明，这让其他的猎人羡慕不已，因为这个世界有个很厉害叫开源的家伙总是喜欢给他们提供无偿的各式各样的步枪、机枪、手枪……</p>
<p>C#程序员有天生的优越感，因为他们每次打猎都开着一辆牌子叫做VS的超级装甲车，羡煞旁人。</p>
<p>VB和DELPHI程序员各扛着枪走在捕猎的路上，狭路相逢，开始争吵谁的捕猎技术高明谁的枪打得准，以至于忘了任务是来打猎大象。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/158.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>用POI输出Excel流到浏览器</title>
		<link>http://blog.jackrun.com/archives/161.html</link>
		<comments>http://blog.jackrun.com/archives/161.html#comments</comments>
		<pubDate>Tue, 17 Oct 2006 09:29:45 +0000</pubDate>
		<dc:creator>Peltason</dc:creator>
				<category><![CDATA[软件开发]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[POI]]></category>
		<category><![CDATA[浏览器]]></category>

		<guid isPermaLink="false">http://www.jackrun.com/?p=161</guid>
		<description><![CDATA[作者：东区一匹狼
时间：2006-10-17
最近用户要求添加功能把数据导出成Excel的.xls到用户的PC，由于导出的Excel数据对于服务端没有用处，不需要在服务端保留，如果在服务端硬盘生成文件，然后在让用户下载，这样就需要定时清理服务端数据，自己查了一下POI和WebWork的资料，实现了该功能，直接把POI生成的Excel 流输出到浏览器，让用户下载，关闭窗口就消失，不在服务端留痕迹，写出来大家分享一下。
用过WebWork的人应该知道，在Webwork的Action中，execute()方法最后返回的是一个Result对象，如 return SUCCESS 。在这里我们需要实现WebWork的Result接口，定义自己的一个输出Excel的Result。前提是你需要下载POI包，代码如下：

package com.test.excel;
import com.opensymphony.xwork.Result;
import com.opensymphony.xwork.ActionInvocation;
import com.opensymphony.webwork.ServletActionContext;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
public class ExcelResult implements Result{
private HSSFWorkbook workbook;
private String filename;
private String contenttype;
public void execute(ActionInvocation invocation) throws Exception {
if (contenttype == null)
contenttype = &#8220;application/msexcel&#8221;
if (workbook == null)
workbook = (HSSFWorkbook) invocation.getStack().findValue(&#8220;workbook&#8221;);
HttpServletResponse response = ServletActionContext.getResponse();
response.reset() ;
response.setContentType(contenttype);
response.setHeader(&#8220;Content-Disposition&#8221;, &#8220;attachment;Filename=&#8221; + filename + &#8220;.xls&#8221;);
OutputStream os = response.getOutputStream();
workbook.write(os);
os.flush();
os.close();
}
public void setWorkbook(HSSFWorkbook workbook) {
this.workbook [...]]]></description>
			<content:encoded><![CDATA[<p>作者：东区一匹狼</p>
<p>时间：2006-10-17</p>
<p>最近用户要求添加功能把数据导出成Excel的.xls到用户的PC，由于导出的Excel数据对于服务端没有用处，不需要在服务端保留，如果在服务端硬盘生成文件，然后在让用户下载，这样就需要定时清理服务端数据，自己查了一下POI和WebWork的资料，实现了该功能，直接把POI生成的Excel 流输出到浏览器，让用户下载，关闭窗口就消失，不在服务端留痕迹，写出来大家分享一下。</p>
<p>用过WebWork的人应该知道，在Webwork的Action中，execute()方法最后返回的是一个Result对象，如 return SUCCESS 。在这里我们需要实现WebWork的Result接口，定义自己的一个输出Excel的Result。前提是你需要下载POI包，代码如下：</p>
<p><span id="more-161"></span></p>
<p>package com.test.excel;</p>
<p>import com.opensymphony.xwork.Result;</p>
<p>import com.opensymphony.xwork.ActionInvocation;</p>
<p>import com.opensymphony.webwork.ServletActionContext;</p>
<p>import org.apache.poi.hssf.usermodel.HSSFWorkbook;</p>
<p>import javax.servlet.http.HttpServletResponse;</p>
<p>import java.io.OutputStream;</p>
<p>public class ExcelResult implements Result{</p>
<p>private HSSFWorkbook workbook;</p>
<p>private String filename;</p>
<p>private String contenttype;</p>
<p>public void execute(ActionInvocation invocation) throws Exception {</p>
<p>if (contenttype == null)</p>
<p>contenttype = &#8220;application/msexcel&#8221;</p>
<p>if (workbook == null)</p>
<p>workbook = (HSSFWorkbook) invocation.getStack().findValue(&#8220;workbook&#8221;);</p>
<p>HttpServletResponse response = ServletActionContext.getResponse();</p>
<p>response.reset() ;</p>
<p>response.setContentType(contenttype);</p>
<p>response.setHeader(&#8220;Content-Disposition&#8221;, &#8220;attachment;Filename=&#8221; + filename + &#8220;.xls&#8221;);</p>
<p>OutputStream os = response.getOutputStream();</p>
<p>workbook.write(os);</p>
<p>os.flush();</p>
<p>os.close();</p>
<p>}</p>
<p>public void setWorkbook(HSSFWorkbook workbook) {</p>
<p>this.workbook = workbook;</p>
<p>}</p>
<p>public void setFilename(String filename) {</p>
<p>this.filename = filename;</p>
<p>}</p>
<p>public void setContenttype(String contenttype) {</p>
<p>this.contenttype = contenttype;</p>
<p>}</p>
<p>}</p>
<p>可以看到，在execute()方法中通过参数invocation的 invocation.getStack().findValue(&#8220;workbook&#8221;)得到action中的workbook对象，当然，在你的 action中，对生成好的workbook要有get()方法，在后面的代码中会看到。然后workbook.write到response对象就可以了，在这之前，你需要设置html的头部，见上面的代码。</p>
<p>OK，写完上面自定义的Result，我们就可以写Action了，代码如下：</p>
<p>package test.action;</p>
<p>import org.apache.poi.hssf.usermodel.HSSFCell;</p>
<p>import org.apache.poi.hssf.usermodel.HSSFRow;</p>
<p>import org.apache.poi.hssf.usermodel.HSSFSheet;</p>
<p>import org.apache.poi.hssf.usermodel.HSSFWorkbook;</p>
<p>import com.opensymphony.xwork.ActionSupport;</p>
<p>public class ExcelTest extends ActionSupport {</p>
<p>private HSSFWorkbook workbook;</p>
<p>public String execute() throws Exception {</p>
<p>workbook = outputExcelFile();</p>
<p>return SUCCESS;</p>
<p>}</p>
<p>private HSSFWorkbook outputExcelFile() {</p>
<p>try {</p>
<p>HSSFWorkbook workbook = new HSSFWorkbook();</p>
<p>HSSFSheet sheet = workbook.createSheet();</p>
<p>workbook.setSheetName(0, &#8220;测试输出Excel&#8221;, HSSFWorkbook.ENCODING_UTF_16);</p>
<p>HSSFRow row = sheet.createRow((short) 0);</p>
<p>HSSFCell cell = row.createCell((short) 0);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;标题1&#8243;);</p>
<p>cell = row.createCell((short) 1);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;标题2&#8243;);</p>
<p>cell = row.createCell((short) 2);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;标题3&#8243;);</p>
<p>cell = row.createCell((short) 3);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;标题4&#8243;);</p>
<p>row = sheet.createRow(1);</p>
<p>cell = row.createCell((short) 0);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;内容1&#8243;);</p>
<p>cell = row.createCell((short) 1);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;内容2&#8243;);</p>
<p>cell = row.createCell((short) 2);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;内容3&#8243;);</p>
<p>cell = row.createCell((short) 3);</p>
<p>cell.setCellType(HSSFCell.CELL_TYPE_STRING);</p>
<p>cell.setEncoding(HSSFCell.ENCODING_UTF_16);</p>
<p>cell.setCellValue(&#8220;内容4&#8243;);</p>
<p>return workbook;</p>
<p>} catch (Exception e) {</p>
<p>e.printStackTrace();</p>
<p>return null;</p>
<p>}</p>
<p>}</p>
<p>public HSSFWorkbook getWorkbook() {</p>
<p>return workbook;</p>
<p>}</p>
<p>}</p>
<p>然后在xwork.xml里面配置result类型</p>
<p>&lt;!&#8211; 定义结果类型 &#8211;&gt;</p>
<p>&lt;result-types&gt;</p>
<p>&lt;result-type name=&#8221;dispatcher&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.ServletDispatcherResult&#8221; default=&#8221;true&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;redirect&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.ServletRedirectResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;velocity&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.VelocityResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;chain&#8221; class=&#8221;com.opensymphony.xwork.ActionChainResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;xslt&#8221; class=&#8221;com.opensymphony.webwork.views.xslt.XSLTResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;jasper&#8221; class=&#8221;com.opensymphony.webwork.views.jasperreports.JasperReportsResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;freemarker&#8221; class=&#8221;com.opensymphony.webwork.views.freemarker.FreemarkerResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;httpheader&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.HttpHeaderResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;stream&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.StreamResult&#8221;/&gt;</p>
<p>&lt;result-type name=&#8221;plaintext&#8221; class=&#8221;com.opensymphony.webwork.dispatcher.PlainTextResult&#8221; /&gt;</p>
<p>&lt;result-type name=&#8221;excel&#8221; class=&#8221;com.test.excel&#8221;/&gt;</p>
<p>&lt;/result-types&gt;</p>
<p>定义action</p>
<p>&lt;action name=&#8221;output_excel&#8221; class=&#8221;test.action.ExcelTest.ExcelResult&#8221;&gt;</p>
<p>&lt;result name=&#8221;success&#8221; type=&#8221;excel&#8221;&gt;</p>
<p>&lt;param name=&#8221;filename&#8221;&gt;ExcelTest&lt;/param&gt;</p>
<p>&lt;/result&gt;</p>
<p>&lt;/action&gt;</p>
<p>大功告成！</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.jackrun.com/archives/161.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
