<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>canofy</title>
    <description>什么都不用说，把真意传达给心灵～</description>
    <link>http://canofy.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>awk编程</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/233005" style="color:red;">http://canofy.javaeye.com/blog/233005</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          1. awk简介<br /><br />awk 是一种编程语言，用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件，或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能，是linux/unix下的一个强大编程工具。它在命令行中使用，但更多是作为脚本来使用。awk的处理文本和数据的方式是这样的，它逐行扫描文件，从第一行到最后一行，寻找匹配的特定模式的行，并在这些行上进行你想要的操作。如果没有指定处理动作，则把匹配的行显示到标准输出 (屏幕)，如果没有指定模式，则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。因为它的作者是三个人，分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本，它提供了Bell实验室和GNU的一些扩展。下面介绍的awk是以GUN的gawk为例的，在 linux系统中已把awk链接到gawk，所以下面全部以awk进行介绍。<br />2. awk命令格式和选项<br />2.1. awk的语法有两种形式<br /><br />    *<br /><br />      awk [options] 'script' var=value file(s)<br />    *<br /><br />      awk [options] -f scriptfile var=value file(s)<br /><br />2.2. 命令选项<br /><br />-F fs or --field-separator fs<br /><br />    指定输入文件折分隔符，fs是一个字符串或者是一个正则表达式，如-F:。<br />-v var=value or --asign var=value<br /><br />    赋值一个用户定义变量。<br />-f scripfile or --file scriptfile<br /><br />    从脚本文件中读取awk命令。<br />-mf nnn and -mr nnn<br /><br />    对nnn值设置内在限制，-mf选项限制分配给nnn的最大块数目；-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能，在标准awk中不适用。<br />-W compact or --compat, -W traditional or --traditional<br /><br />    在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样，所有的awk扩展都被忽略。<br />-W copyleft or --copyleft, -W copyright or --copyright<br /><br />    打印简短的版权信息。<br />-W help or --help, -W usage or --usage<br /><br />    打印全部awk选项和每个选项的简短说明。<br />-W lint or --lint<br /><br />    打印不能向传统unix平台移植的结构的警告。<br />-W lint-old or --lint-old<br /><br />    打印关于不能向传统unix平台移植的结构的警告。<br />-W posix<br /><br />    打开兼容模式。但有以下限制，不识别：\x、函数关键字、func、换码序列以及当fs是一个空格时，将新行作为一个域分隔符；操作符**和**=不能代替^和^=；fflush无效。<br />-W re-interval or --re-inerval<br /><br />    允许间隔正则表达式的使用，参考(grep中的Posix字符类)，如括号表达式[[:alpha:]]。<br />-W source program-text or --source program-text<br /><br />    使用program-text作为源代码，可与-f命令混用。<br />-W version or --version<br /><br />    打印bug报告信息的版本。<br /><br />3. 模式和操作<br /><br />awk脚本是由模式和操作组成的：<br /><br />    pattern {action} 如$ awk '/root/' test，或$ awk '$3 &lt; 100' test。<br /><br />两者是可选的，如果没有模式，则action应用到全部记录，如果没有action，则输出匹配全部记录。默认情况下，每一个输入行都是一条记录，但用户可通过RS变量指定不同的分隔符进行分隔。<br />3.1. 模式<br /><br />模式可以是以下任意一个：<br /><br />    *<br /><br />      /正则表达式/：使用通配符的扩展集。<br />    *<br /><br />      关系表达式：可以用下面运算符表中的关系运算符进行操作，可以是字符串或数字的比较，如$2>%1选择第二个字段比第一个字段长的行。<br />    *<br /><br />      模式匹配表达式：用运算符~(匹配)和~!(不匹配)。<br />    *<br /><br />      模式，模式：指定一个行的范围。该语法不能包括BEGIN和END模式。<br />    *<br /><br />      BEGIN：让用户指定在第一条输入记录被处理之前所发生的动作，通常可在这里设置全局变量。<br />    *<br /><br />      END：让用户在最后一条输入记录被读取之后发生的动作。<br /><br />3.2. 操作<br /><br />操作由一人或多个命令、函数、表达式组成，之间由换行符或分号隔开，并位于大括号内。主要有四部份：<br /><br />    *<br /><br />      变量或数组赋值<br />    *<br /><br />      输出命令<br />    *<br /><br />      内置函数<br />    *<br /><br />      控制流命令<br /><br />4. awk的环境变量<br /><br />Table 1. awk的环境变量<br />变量	描述<br />$n	当前记录的第n个字段，字段间由FS分隔。<br />$0	完整的输入记录。<br />ARGC	命令行参数的数目。<br />ARGIND	命令行中当前文件的位置(从0开始算)。<br />ARGV	包含命令行参数的数组。<br />CONVFMT	数字转换格式(默认值为%.6g)<br />ENVIRON	环境变量关联数组。<br />ERRNO	最后一个系统错误的描述。<br />FIELDWIDTHS	字段宽度列表(用空格键分隔)。<br />FILENAME	当前文件名。<br />FNR	同NR，但相对于当前文件。<br />FS	字段分隔符(默认是任何空格)。<br />IGNORECASE	如果为真，则进行忽略大小写的匹配。<br />NF	当前记录中的字段数。<br />NR	当前记录数。<br />OFMT	数字的输出格式(默认值是%.6g)。<br />OFS	输出字段分隔符(默认值是一个空格)。<br />ORS	输出记录分隔符(默认值是一个换行符)。<br />RLENGTH	由match函数所匹配的字符串的长度。<br />RS	记录分隔符(默认是一个换行符)。<br />RSTART	由match函数所匹配的字符串的第一个位置。<br />SUBSEP	数组下标分隔符(默认值是\034)。<br />5. awk运算符<br /><br />Table 2. 运算符<br />运算符	描述<br />= += -= *= /= %= ^= **=	赋值<br />?:	C条件表达式<br />||	逻辑或<br />&&	逻辑与<br />~ ~!	匹配正则表达式和不匹配正则表达式<br />&lt; &lt;= > >= != ==	关系运算符<br />空格	连接<br />+ -	加，减<br />* / &	乘，除与求余<br />+ - !	一元加，减和逻辑非<br />^ ***	求幂<br />++ --	增加或减少，作为前缀或后缀<br />$	字段引用<br />in	数组成员<br />6. 记录和域<br />6.1. 记录<br /><br />awk把每一个以换行符结束的行称为一个记录。<br /><br />记录分隔符：默认的输入和输出的分隔符都是回车，保存在内建变量ORS和RS中。<br /><br />$0变量：它指的是整条记录。如$ awk '{print $0}' test将输出test文件中的所有记录。<br /><br />变量NR：一个计数器，每处理完一条记录，NR的值就增加1。如$ awk '{print NR,$0}' test将输出test文件中所有记录，并在记录前显示记录号。<br />6.2. 域<br /><br />记录中每个单词称做“域”，默认情况下以空格或tab分隔。awk可跟踪域的个数，并在内建变量NF中保存该值。如$ awk '{print $1,$3}' test将打印test文件中第一和第三个以空格分开的列(域)。<br />6.3. 域分隔符<br /><br />内建变量FS保存输入域分隔符的值，默认是空格或tab。我们可以通过-F命令行选项修改FS的值。如$ awk -F: '{print $1,$5}' test将打印以冒号为分隔符的第一，第五列的内容。<br /><br />可以同时使用多个域分隔符，这时应该把分隔符写成放到方括号中，如$awk -F'[:\t]' '{print $1,$3}' test，表示以空格、冒号和tab作为分隔符。<br /><br />输出域的分隔符默认是一个空格，保存在OFS中。如$ awk -F: '{print $1,$5}' test，$1和$5间的逗号就是OFS的值。<br />7. gawk专用正则表达式元字符<br /><br />一般通用的元字符集就不讲了，可参考我的Sed和Grep学习笔记。以下几个是gawk专用的，不适合unix版本的awk。<br /><br />\Y<br /><br />    匹配一个单词开头或者末尾的空字符串。<br />\B<br /><br />    匹配单词内的空字符串。<br />\&lt;<br /><br />    匹配一个单词的开头的空字符串，锚定开始。<br />\><br /><br />    匹配一个单词的末尾的空字符串，锚定末尾。<br />\w<br /><br />    匹配一个字母数字组成的单词。<br />\W<br /><br />    匹配一个非字母数字组成的单词。<br />\‘<br /><br />    匹配字符串开头的一个空字符串。<br />\'<br /><br />    匹配字符串末尾的一个空字符串。<br /><br />8. POSIX字符集<br /><br />可参考我的Grep学习笔记<br />9. 匹配操作符(~)<br /><br />用来在记录或者域内匹配正则表达式。如$ awk '$1 ~/^root/' test将显示test文件第一列中以root开头的行。<br />10. 比较表达式<br /><br />conditional expression1 ? expression2: expression3，例如：$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一个域大于第三个域，$1就赋值给max，否则$3就赋值给max。<br /><br />$ awk '$1 + $2 &lt; 100' test。如果第一和第二个域相加大于100，则打印这些行。<br /><br />$ awk '$1 > 5 && $2 &lt; 10' test,如果第一个域大于5，并且第二个域小于10，则打印这些行。<br />11. 范围模板<br /><br />范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。如果有一个模板没出现，则匹配到开头或末尾。如$ awk '/root/,/mysql/' test将显示root第一次出现到mysql第一次出现之间的所有行。<br />12. 一个验证passwd文件有效性的例子<br /><br />1$ cat /etc/passwd | awk -F: '\<br />2NF != 7{\<br />3printf("line %d,does not have 7 fields:%s\n",NR,$0)}\<br />4$1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %s\n,NR,$0)}\<br />5$2 == "*" {printf("line %d, no password: %s\n",NR,$0)}'<br /><br />1 	<br /><br />cat把结果输出给awk，awk把域之间的分隔符设为冒号。<br />2 	<br /><br />如果域的数量(NF)不等于7，就执行下面的程序。<br />3 	<br /><br />printf打印字符串"line ?? does not have 7 fields"，并显示该条记录。<br />4 	<br /><br />如果第一个域没有包含任何字母和数字，printf打印“no alpha and numeric user id" ，并显示记录数和记录。<br />5 	<br /><br />如果第二个域是一个星号，就打印字符串“no passwd”，紧跟着显示记录数和记录本身。<br />13. 几个实例<br /><br />    *<br /><br />      $ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行。<br />    *<br /><br />      $ awk '/^[ns]/{print $1}' test-----如果记录以n或s开头，就打印这个记录。<br />    *<br /><br />      $ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一个域以两个数字结束就打印这个记录。<br />    *<br /><br />      $ awk '$1 == 100 || $2 &lt; 50' test-----如果第一个或等于100或者第二个域小于50，则打印该行。<br />    *<br /><br />      $ awk '$1 != 10' test-----如果第一个域不等于10就打印该行。<br />    *<br /><br />      $ awk '/test/{print $1 + 10}' test-----如果记录包含正则表达式test，则第一个域加10并打印出来。<br />    *<br /><br />      $ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果第一个域大于5则打印问号后面的表达式值，否则打印冒号后面的表达式值。<br />    *<br /><br />      $ awk '/^root/,/^mysql/' test----打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录，则继续打印直到下一个以正则表达式mysql开头的记录为止，或到文件末尾。
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/233005#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 21:46:07 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/233005</link>
        <guid>http://canofy.javaeye.com/blog/233005</guid>
      </item>
      <item>
        <title>awk编程</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/232997" style="color:red;">http://canofy.javaeye.com/blog/232997</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          14. awk编程<br />14.1. 变量<br /><br />    *<br /><br />      在awk中，变量不需要定义就可以直接使用，变量类型可以是数字或字符串。<br />    *<br /><br />      赋值格式：Variable = expression，如$ awk '$1 ~/test/{count = $2 + $3; print count}' test,上式的作用是,awk先扫描第一个域，一旦test匹配，就把第二个域的值加上第三个域的值，并把结果赋值给变量count，最后打印出来。<br />    *<br /><br />      awk可以在命令行中给变量赋值，然后将这个变量传输给awk脚本。如$ awk -F: -f awkscript month=4 year=2004 test，上式的month和year都是自定义变量，分别被赋值为4和2004。在awk脚本中，这些变量使用起来就象是在脚本中建立的一样。注意，如果参数前面出现test，那么在BEGIN语句中的变量就不能被使用。<br />    *<br /><br />      域变量也可被赋值和修改，如$ awk '{$2 = 100 + $1; print }' test,上式表示，如果第二个域不存在，awk将计算表达式100加$1的值，并将其赋值给$2，如果第二个域存在，则用表达式的值覆盖$2原来的值。再例如：$ awk '$1 == "root"{$1 ="test";print}' test，如果第一个域的值是“root”，则把它赋值为“test”，注意，字符串一定要用双引号。<br />    *<br /><br />      内建变量的使用。变量列表在前面已列出，现在举个例子说明一下。$ awk -F: '{IGNORECASE=1; $1 == "MARY"{print NR,$1,$2,$NF}'test，把IGNORECASE设为1代表忽略大小写，打印第一个域是mary的记录数、第一个域、第二个域和最后一个域。<br /><br />14.2. BEGIN模块<br /><br />BEGIN模块后紧跟着动作块，这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它通常用来改变内建变量的值，如OFS,RS和FS等，以及打印标题。如：$ awk 'BEGIN{FS=":"; OFS="\t"; ORS="\n\n"}{print $1,$2,$3} test。上式表示，在处理输入文件以前，域分隔符(FS)被设为冒号，输出文件分隔符(OFS)被设置为制表符，输出记录分隔符(ORS)被设置为两个换行符。$ awk 'BEGIN{print "TITLE TEST"}只打印标题。<br />14.3. END模块<br /><br />END不匹配任何的输入文件，但是执行动作块中的所有动作，它在整个输入文件处理完成后被执行。如$ awk 'END{print "The number of records is" NR}' test，上式将打印所有被处理的记录数。<br />14.4. 重定向和管道<br /><br />    *<br /><br />      awk可使用shell的重定向符进行重定向输出，如：$ awk '$1 = 100 {print $1 > "output_file" }' test。上式表示如果第一个域的值等于100，则把它输出到output_file中。也可以用>>来重定向输出，但不清空文件，只做追加操作。<br />    *<br /><br />      输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文件之外的其他输入文件获得输入。它负责从输入获得下一行的内容，并给NF,NR和FNR等内建变量赋值。如果得到一条记录，getline函数返回1，如果到达文件的末尾就返回0，如果出现错误，例如打开文件失败，就返回-1。如：<br /><br />      $ awk 'BEGIN{ "date" | getline d; print d}' test。执行linux的date命令，并通过管道输出给getline，然后再把输出赋值给自定义变量d，并打印它。<br /><br />      $ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test。执行shell的date命令，并通过管道输出给getline，然后getline从管道中读取并将输入赋值给d，split函数把变量d转化成数组mon，然后打印数组mon的第二个元素。<br /><br />      $ awk 'BEGIN{while( "ls" | getline) print}'，命令ls的输出传递给geline作为输入，循环使getline从ls的输出中读取一行，并把它打印到屏幕。这里没有输入文件，因为BEGIN块在打开输入文件前执行，所以可以忽略输入文件。<br /><br />      $ awk 'BEGIN{printf "What is your name?"; getline name &lt; "/dev/tty" } $1 ~name {print "Found" name on line ", NR "."} END{print "See you," name "."} test。在屏幕上打印”What is your name?",并等待用户应答。当一行输入完毕后，getline函数从终端接收该行输入，并把它储存在自定义变量name中。如果第一个域匹配变量name的值，print函数就被执行，END块打印See you和name的值。<br /><br />      $ awk 'BEGIN{while (getline &lt; "/etc/passwd" > 0) lc++; print lc}'。awk将逐行读取文件/etc/passwd的内容，在到达文件末尾前，计数器lc一直增加，当到末尾时，打印lc的值。注意，如果文件不存在，getline返回-1，如果到达文件的末尾就返回0，如果读到一行，就返回1，所以命令 while (getline &lt; "/etc/passwd")在文件不存在的情况下将陷入无限循环，因为返回-1表示逻辑真。<br />    *<br /><br />      可以在awk中打开一个管道，且同一时刻只能有一个管道存在。通过close()可关闭管道。如：$ awk '{print $1, $2 | "sort" }' test END {close("sort")}。awd把print语句的输出通过管道作为linux命令sort的输入,END块执行关闭管道操作。<br />    *<br /><br />      system函数可以在awk中执行linux的命令。如：$ awk 'BEGIN{system("clear")'。<br />    *<br /><br />      fflush函数用以刷新输出缓冲区，如果没有参数，就刷新标准输出的缓冲区，如果以空字符串为参数，如fflush(""),则刷新所有文件和管道的输出缓冲区。<br /><br />14.5. 条件语句<br /><br />awk中的条件语句是从C语言中借鉴过来的，可控制程序的流程。<br />14.5.1. if语句<br /><br />格式：<br />        {if (expression){<br />                   statement; statement; ...<br />                     }<br />        }<br /><br />$ awk '{if ($1 &lt;$2) print $2 "too high"}' test。如果第一个域小于第二个域则打印。<br /><br />$ awk '{if ($1 &lt; $2) {count++; print "ok"}}' test.如果第一个域小于第二个域，则count加一，并打印ok。<br />14.5.2. if/else语句，用于双重判断。<br /><br />格式：<br />        {if (expression){<br />                   statement; statement; ...<br />                       }<br />        else{<br />                   statement; statement; ...<br />                       }<br />        }<br /><br />$ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test。如果$1大于100则打印$1 bad,否则打印ok。<br /><br />$ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test。如果$1大于100，则count加一，并打印$1，否则count减一，并打印$1。<br />14.5.3. if/else else if语句，用于多重判断。<br /><br />格式：<br />        {if (expression){<br />                    statement; statement; ...<br />                   }<br />        else if (expression){<br />                    statement; statement; ...<br />                   }<br />        else if (expression){<br />                    statement; statement; ...<br />                   }<br />        else {<br />                   statement; statement; ...<br />             }<br />        }<br /><br />14.6. 循环<br /><br />    *<br /><br />      awk有三种循环:while循环；for循环；special for循环。<br />    *<br /><br />      $ awk '{ i = 1; while ( i &lt;= NF ) { print NF,$i; i++}}' test。变量的初始值为1，若i小于可等于NF(记录中域的个数),则执行打印语句，且i增加1。直到i的值大于NF.<br />    *<br /><br />      $ awk '{for (i = 1; i&lt;NF; i++) print NF,$i}' test。作用同上。<br />    *<br /><br />      breadkcontinue语句。break用于在满足条件的情况下跳出循环；continue用于在满足条件的情况下忽略后面的语句，直接返回循环的顶端。如：<br /><br />      {for ( x=3; x&lt;=NF; x++) <br />                  if ($x&lt;0){print "Bottomed out!"; break}}<br />      {for ( x=3; x&lt;=NF; x++)<br />                  if ($x==0){print "Get next item"; continue}}<br />            <br /><br />    *<br /><br />      next语句从输入文件中读取一行，然后从头开始执行awk脚本。如：<br /><br />      {if ($1 ~/test/){next}<br />          else {print}<br />      }<br />           <br /><br />    *<br /><br />      exit语句用于结束awk程序，但不会略过END块。退出状态为0代表成功，非零值表示出错。<br /><br />14.7. 数组<br /><br />awk中的数组的下标可以是数字和字母，称为关联数组。<br />14.7.1. 下标与关联数组<br /><br />    *<br /><br />      用变量作为数组下标。如：$ awk {name[x++]=$2};END{for(i=0;i&lt;NR;i++) print i,name[i]}' test。数组name中的下标是一个自定义变量x，awk初始化x的值为0，在每次使用后增加1。第二个域的值被赋给name数组的各个元素。在END 模块中，for循环被用于循环整个数组，从下标为0的元素开始，打印那些存储在数组中的值。因为下标是关健字，所以它不一定从0开始，可以从任何值开始。<br />    *<br /><br />      special for循环用于读取关联数组中的元素。格式如下：<br /><br />      {for (item in arrayname){<br />               print arrayname[item]<br />               }<br />      }<br /><br />      $ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test。打印有值的数组元素。打印的顺序是随机的。<br />    *<br /><br />      用字符串作为下标。如：count["test"]<br />    *<br /><br />      用域值作为数组的下标。一种新的for循环方式，for (index_value in array) statement。如:$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test。该语句将打印$1中字符串出现的次数。它首先以第一个域作数组count的下标，第一个域变化，索引就变化。<br />    *<br /><br />      delete函数用于删除数组元素。如：$ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test。分配给数组line的是第一个域的值，所有记录处理完成后，special for循环将删除每一个元素。<br /><br />14.8. awk的内建函数<br />14.8.1. 字符串函数<br /><br />    *<br /><br />      sub函数匹配记录中最大、最靠左边的子字符串的正则表达式，并用替换字符串替换这些字符串。如果没有指定目标字符串就默认使用整个记录。替换只发生在第一次匹配的时候。格式如下：<br /><br />                  sub (regular expression, substitution string):<br />                  sub (regular expression, substitution string, target string)<br /><br />      实例：<br /><br />                  $ awk '{ sub(/test/, "mytest"); print }' testfile<br />                  $ awk '{ sub(/test/, "mytest"); $1}; print }' testfile<br /><br />      第一个例子在整个记录中匹配，替换只发生在第一次匹配发生的时候。如要在整个文件中进行匹配需要用到gsub<br /><br />      第二个例子在整个记录的第一个域中进行匹配，替换只发生在第一次匹配发生的时候。<br />    *<br /><br />      gsub函数作用如sub，但它在整个文档中进行匹配。格式如下：<br /><br />                  gsub (regular expression, substitution string)<br />                  gsub (regular expression, substitution string, target string)<br /><br />      实例：<br /><br />                  $ awk '{ gsub(/test/, "mytest"); print }' testfile<br />                  $ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile<br /><br />      第一个例子在整个文档中匹配test，匹配的都被替换成mytest。<br /><br />      第二个例子在整个文档的第一个域中匹配，所有匹配的都被替换成mytest。<br />    *<br /><br />      index函数返回子字符串第一次被匹配的位置，偏移量从位置1开始。格式如下：<br /><br />                index(string, substring)<br /><br />      实例：<br /><br />                  $ awk '{ print index("test", "mytest") }' testfile<br /><br />      实例返回test在mytest的位置，结果应该是3。<br />    *<br /><br />      length函数返回记录的字符数。格式如下：<br /><br />                  length( string )<br />                  length<br /><br />      实例：<br /><br />                  $ awk '{ print length( "test" ) }' <br />                  $ awk '{ print length }' testfile<br /><br />      第一个实例返回test字符串的长度。<br /><br />      第二个实例返回testfile文件中第条记录的字符数。<br />    *<br /><br />      substr函数返回从位置1开始的子字符串，如果指定长度超过实际长度，就返回整个字符串。格式如下：<br /><br />                  substr( string, starting position )<br />                  substr( string, starting position, length of string )<br /><br />      实例：<br /><br />                  $ awk '{ print substr( "hello world", 7,11 ) }' <br /><br />      上例截取了world子字符串。<br />    *<br /><br />      match函数返回在字符串中正则表达式位置的索引，如果找不到指定的正则表达式则返回0。match函数会设置内建变量RSTART为字符串中子字符串的开始位置，RLENGTH为到子字符串末尾的字符个数。substr可利于这些变量来截取字符串。函数格式如下：<br /><br />                  match( string, regular expression )<br /><br />      实例：<br /><br />                  $ awk '{start=match("this is a test",/[a-z]+$/); print start}'<br />                  $ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'<br /><br />      第一个实例打印以连续小写字符结尾的开始位置，这里是11。<br /><br />      第二个实例还打印RSTART和RLENGTH变量，这里是11(start)，11(RSTART)，4(RLENGTH)。<br />    *<br /><br />      toupper和tolower函数可用于字符串大小间的转换，该功能只在gawk中有效。格式如下：<br /><br />                  toupper( string )<br />                  tolower( string )<br /><br />      实例：<br /><br />                  $ awk '{ print toupper("test"), tolower("TEST") }'<br /><br />    *<br /><br />      split函数可按给定的分隔符把字符串分割为一个数组。如果分隔符没提供，则按当前FS值进行分割。格式如下：<br /><br />                  split( string, array, field separator )<br />                  split( string, array )<br /><br />      实例：<br /><br />                  $ awk '{ split( "20:18:00", time, ":" ); print time[2] }'<br /><br />      上例把时间按冒号分割到time数组内，并显示第二个数组元素18。<br /><br />14.8.2. 时间函数<br /><br />    *<br /><br />      systime函数返回从1970年1月1日开始到当前时间(不计闰年)的整秒数。格式如下：<br /><br />                  systime()<br /><br />      实例：<br /><br />                  $ awk '{ now = systime(); print now }'<br /><br />    *<br /><br />      strftime函数使用C库中的strftime函数格式化时间。格式如下：<br /><br />                  systime( [format specification][,timestamp] )<br /><br />      Table 3. 日期和时间格式说明符<br />      格式 	描述<br />      %a 	星期几的缩写(Sun)<br />      %A 	星期几的完整写法(Sunday)<br />      %b 	月名的缩写(Oct)<br />      %B 	月名的完整写法(October)<br />      %c 	本地日期和时间<br />      %d 	十进制日期<br />      %D 	日期 08/20/99<br />      %e 	日期，如果只有一位会补上一个空格<br />      %H 	用十进制表示24小时格式的小时<br />      %I 	用十进制表示12小时格式的小时<br />      %j 	从1月1日起一年中的第几天<br />      %m 	十进制表示的月份<br />      %M 	十进制表示的分钟<br />      %p 	12小时表示法(AM/PM)<br />      %S 	十进制表示的秒<br />      %U 	十进制表示的一年中的第几个星期(星期天作为一个星期的开始)<br />      %w 	十进制表示的星期几(星期天是0)<br />      %W 	十进制表示的一年中的第几个星期(星期一作为一个星期的开始)<br />      %x 	重新设置本地日期(08/20/99)<br />      %X 	重新设置本地时间(12：00：00)<br />      %y 	两位数字表示的年(99)<br />      %Y 	当前月份<br />      %Z 	时区(PDT)<br />      %% 	百分号(%)<br /><br />      实例：<br /><br />                  $ awk '{ now=strftime( "%D", systime() ); print now }'<br />                  $ awk '{ now=strftime("%m/%d/%y"); print now }'<br /><br />14.8.3. 内建数学函数<br /><br />Table 4. <br />函数名称 	返回值<br />atan2(x,y) 	y,x范围内的余切<br />cos(x) 	余弦函数<br />exp(x) 	求幂<br />int(x) 	取整<br />log(x) 	自然对数<br />rand() 	随机数<br />sin(x) 	正弦<br />sqrt(x) 	平方根<br />srand(x) 	x是rand()函数的种子<br />int(x) 	取整，过程没有舍入<br />rand() 	产生一个大于等于0而小于1的随机数<br />14.8.4. 自定义函数<br /><br />在awk中还可自定义函数，格式如下：<br /><br />        function name ( parameter, parameter, parameter, ... ) {<br />                        statements<br />                        return expression                  # the return statement and expression are optional<br />        }<br /><br />15. How-to<br /><br />    *<br /><br />      如何把一行竖排的数据转换成横排？<br /><br />      awk '{printf("%s,",$1)}' filename
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/232997#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 21:11:56 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/232997</link>
        <guid>http://canofy.javaeye.com/blog/232997</guid>
      </item>
      <item>
        <title>Struts标签</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/232983" style="color:red;">http://canofy.javaeye.com/blog/232983</a>&nbsp;
          发表时间: 2008年08月26日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          Struts是Apache Jakarta的一个著名的开源项目，目标是为构建基于Java的web应用程序提供一个框架。<br /><br />Struts提供了非常多的标签，依据功能和使用习惯的不同被分到了五个标签库中:<br /><br />    * Bean Tags:该标签库包含的标签可以用来创建bean、访问bean和访问bean的属性。同时提供了依据cookies、headers和parameters的值创建相关bean的能力。<br />    * HTML Tags:该标签库包含的标签可以用来创建Struts输入表单。<br />    * Logic Tags:该标签库包含的标签可以用来进行逻辑判断、集合迭代和流程控制。<br />    * Nested Tags:该标签库建立在前三个标签库的基础上，具有前三个标签库的所有功能，只是允许标签间的嵌套。<br />    * Tiles Tags:该标签库包含的标签可以用来创建tiles样式的页面。<br /><br />这篇指南主要介绍前三个标签库中的标签。<br />bean:cookie<br /><br />cookie最早是由Netscape公司提出来的，用来存储客户的少量状态信息。<br /><br />bean:cookie标签取回请求中名称为name的cookie的值。如果没有指定multiple属性则依据刚取回的值创建一个Cookie 类型的bean。如果指定了multiple属性则依据刚取回的值创建一个Cookie[]类型的数组。然后用id属性值将Cookie或 Cookie[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值)，并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。<br /><br />下面的代码片段示例了如何使用bean:cookie标签读取名为JSESSIONID的cookie的值，并且使用了两种方式进行了输出：<br /><br />&lt;logic:present cookie="JSESSIONID"><br />&lt;bean:cookie id="jSession" name="JSESSIONID"/><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />这个cookie的名称是&lt;bean:write name="jSession" property="name"/>，值为&lt;bean:write name="jSession" property="value"/>。&lt;br/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />String name = jSession.getName();<br />String value = jSession.getValue();<br />out.println("这个cookie的名称是"+name+"，值为"+value+"。&lt;br/>");<br />%><br />&lt;/logic:present><br /><br /> <br />bean:define<br /><br />bean:define标签在toScope(如果没有指定值就使用page作用域)指定的作用域中创建一个新属性，同时创建一个 scripting变量。我们可以通过id值使用它们。新创建的属性可以由其它标签使用，而新创建的scripting变量可以由JSP脚本使用。<br /><br />我们可以使用三种方式为新创建的属性和scripting变量赋值：<br /><br />    * 通过该标签的name、property和scope取回值，并且保持类型的一致性，除非取回的值为Java的原始类型，这时会使用适合的包装器类对这些值进行包装。<br />    * 通过该标签的value指定值，这时新创建的属性和scripting变量的类型为java.lang.String。<br />    * 通过在该标签的体中嵌入值，这时新创建的属性和scripting变量的类型为java.lang.String。<br /><br /> <br /><br />下面的代码片段示例了如何使用bean:define标签创建新属性values和新scripting变量values，它将listForm中persons的值取出来赋给values:<br /><br />&lt;bean:define id="values" name="listForm" property = "persons" type="java.util.List"/><br /><br />下面给出ListForm的代码片段以帮助您更好的理解，其中Person是一个只有id和name两个属性的简单bean：<br /><br />public class ListForm extends ActionForm {<br />private List&lt;Person> persons = null;<br />public List&lt;Person> getPersons() {<br />return persons;<br />}<br />public void setPersons(List&lt;Person> persons) {<br />this.persons = persons;<br />}<br />public void reset(ActionMapping mapping, HttpServletRequest request) {<br />persons = null;<br />}<br />}<br /><br />下面的代码片段示例了logic:iterate标签如何使用bean:define标签创建的新属性values:<br /><br />&lt;logic:iterate id="person" name="values"><br />&lt;bean:write name="person" property="id"/>&lt;br/><br />&lt;/logic:iterate><br /><br />下面的代码片段示例了JSP脚本如何使用bean:define标签创建的新scripting变量values:<br /><br />&lt;%<br />Person p = new Person();<br />for(int i=0;i&lt;values.size();i++){<br />p = (Person)values.get(i);<br />out.println(p.getId());<br />out.println("&lt;br/>");<br />}<br />%><br /><br /> <br />bean:header<br /><br />bean:header标签取回请求中名称为name的header的值。如果没有指定multiple属性则依据刚取回的值创建一个String 类型的bean。如果指定了multiple属性则依据刚取回的值创建一个String[]类型的数组。然后用id属性值将String或 String[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值)，并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。<br /><br />下面是我的浏览器发送的header的内容，这些内容和浏览器有关，因此您的浏览器发送的内容可能和下面列出的不同。不过这没有关系，因为要理解bean:header标签您只要对这些内容有一个大概的认识就足够了。<br /><br />accept: */*<br />accept-language: zh-cn<br />accept-encoding: gzip, deflate<br />user-agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)<br />host: localhost:8080<br />connection: Keep-Alive<br /><br />下面的代码片段示例了如何使用bean:header标签读取名为User-Agent的header的值，并且使用了两种方式进行了输出：<br /><br />&lt;logic:present header="User-Agent"><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />您的浏览器是&lt;bean:header id="userAgent" name="User-Agent"/><br />&lt;bean:write name="userAgent"/>。&lt;br/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />out.println("您的浏览器是"+userAgent+"。&lt;br/>");<br />%><br />&lt;/logic:present><br /><br /> <br />bean:include<br /><br />bean:include标签对指定url(由forward、href或page确定)处的资源做一个请求，将响应数据作为一个String类型的bean绑定到page作用域，同时创建一个scripting变量。我们可以通过id值访问它们。<br /><br />下面的代码片段示例了bean:include标签的用法，其中include.txt文件包含要include的内容，然后将这些内容输出:<br /><br />&lt;bean:include id="value" page="/include.txt"/><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />&lt;bean:write name="value"/>&lt;br/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />out.println(value);<br />%><br /><br /> <br />bean:message<br /><br />bean:message标签用来从指定的locale中取回国际化的消息并输出，在这个过程中我们还可以传递五个以内的参数。message key可以通过key直接指定，也可以通过name和property间接的指定。<br /><br />bean:message标签有两种指定message key的方式，一是通过key属性直接指定；二是通过name和property属性间接的指定，其中message key是在message resources文件中定义的。<br /><br />我们可以在struts-config.xml文件中使用&lt;message-resources>来设置message resources文件。<br /><br />为了介绍该标签我使用了三个message resources文件，三个文件的名字分别为Resources.properties、Resources_en.properties和 Resources_zh.properties。在struts-config.xml文件中的设置(这里不用设置三个，struts会依据 locale自动找到对应的文件)如下：<br /><br />&lt;message-resources parameter="Resources" /><br /><br />三个message resources文件中定义的message key为：<br /><br />&lt;!-- Resources.properties --><br />resource=Resources.properties.<br />from=Resources.properties.<br />&lt;!-- Resources_en.properties --><br />from=Resources_en.properties.<br />&lt;!-- Resources_zh.properties<br />因为文件的编码被限制为ISO8859所以要有汉字必须用jdk的native2ascii提前转换<br />--><br />from=Resources_zh.properties.<br /><br />下面的代码片段示例了bean:message标签的用法:<br /><br />&lt;bean:message key="from"/>&lt;br/><br />&lt;bean:message key="resource"/>&lt;br/><br />&lt;html:link action="/locale?language=en">English&lt;/html:link><br />&lt;html:link action="/locale?language=zh">Chinese&lt;/html:link><br /><br />上面的代码中含有改变locale的两个html:link标签，要使它们工作您的struts-config.xml文件中必须含有下面定义的form和action:<br /><br />&lt;form-bean name="localeForm" type="org.apache.struts.action.DynaActionForm"><br />&lt;form-property name="language" type="java.lang.String" /><br />&lt;form-property name="country" type="java.lang.String" /><br />&lt;!--action成功后要跳到那里--><br />&lt;form-property name="page"  type="java.lang.String" initial="/message.jsp"/><br />&lt;/form-bean><br />&lt;action path="/locale" type="org.apache.struts.actions.LocaleAction" name="localeForm" scope="request">&lt;/action><br /><br />在不同的locale下我们得到了如下的两个结果：<br /><br />在locale为zh时的结果：<br />Resources_zh.properties.<br />Resources.properties.<br />在locale为en时的结果：<br />Resources_en.properties.<br />Resources.properties.<br /><br />让我们来看一下在locale为zh时如何得到的是上面的结果。因为locale为zh所以&lt;bean:message key="from"/>&lt;br/>先找Resources_zh.properties这个文件从中得到form键的值。而&lt; bean:message key="resource"/>&lt;br/>也会先找Resources_zh.properties这个文件但这次没有找到 resource键，这时Struts会到Resources.properties这个文件中找，很幸运这里找到了。如果还没有找到，或message resource文件不存在就会抛出异常。当locale为en时类似，您可以自己试试。<br /> <br />bean:page<br /><br />bean:page标签将页上下文中的application、config、request、response 或 session取出，然后用id属性值将它们绑定到page作用域中(这种绑定是为了其它标签能够使用该值)，并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。<br /><br />下面的代码片段示例了bean:page标签取出response，然后使用bean:write标签将response的characterEncoding和contentType属性输出：<br /><br />&lt;bean:page id="res" property="response"/><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />&lt;bean:write name="res" property="characterEncoding"/>&lt;br/><br />&lt;bean:write name="res" property="contentType"/>&lt;br/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />String characterEncoding = res.getCharacterEncoding();<br />String contentType = res.getContentType();<br />out.println(characterEncoding+"&lt;br/>");<br />out.println(contentType+"&lt;br/>");<br />%><br /><br />您可以用和上面类似的代码访问application、config、request 或 session中的任何一个对象。<br /> <br />bean:parameter<br /><br />bean:parameter标签取回请求中的参数值。如果没有指定multiple属性则依据刚取回的值创建一个String类型的bean。如果指定了multiple属性则依据刚取回的值创建一个String[]类型的数组。然后用id属性值将String或String[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值)，并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。<br /><br />下面的两个代码片段使用相同的url传递参数，url的形式为http://127.0.0.1:8080/struts-demo /parameter.jsp?param=1&param=2&param=3。前面的代码片段中没有指定multiple属性，因此 p是String类型而且仅仅读取了参数的第一个值。后面的代码片段中指定了multiple属性的值，因此ps是String[]类型的包含所有参数的值。<br /><br />&lt;bean:parameter id="p" name="param"/><br />&lt;bean:write name="p"/><br /><br />&lt;bean:parameter id="ps" multiple="true" name="param"/><br />&lt;logic:iterate id="p" name="ps"><br />&lt;bean:write name="p"/>&lt;br/><br />&lt;/logic:iterate><br /><br /> <br />bean:resource<br /><br />bean:resource标签取回指定的web应用程序的资源，以InputStream或String的形式保存到page作用域中并且创建 scripting变量。采用什么形式取决于标签的input属性，如果指定input则以InputStream的形式保存，如果没有指定input则以String的形式保存。<br /><br />下面的两个代码片段示例了bean:resource标签，其中resource.txt是要使用的资源文件。前面的代码片段中没有指定input 属性，因此以String的形式处理资源文件，bean:write标签输出资源文件的内容。后面的代码片段中指定了input属性的值，因此以 InputStream的形式使用资源文件，两个bean:write标签分别输出InputStream对象的实例名(如 java.io.ByteArrayInputStream@16dadf9)和类名(如class java.io.ByteArrayInputStream)。<br /><br />&lt;bean:resource id="str" name="/resource.txt"/><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />&lt;bean:write name="str"/>&lt;br/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />out.println(str+"&lt;br/>");<br />%><br /><br />&lt;bean:resource id="is" input="true" name="/resource.txt"/><br />&lt;!-- 其它标签通过绑定到page作用域中的属性使用该值 --><br />&lt;bean:write name="is"/>&lt;br/><br />&lt;bean:write name="is" property="class"/><br />&lt;!-- JSP脚本通过scripting变量使用该值 --><br />&lt;%<br />out.println(is+"&lt;br/>");<br />out.println(is.getClass()+"&lt;br/>");<br />%><br /><br /> <br />bean:size<br /><br />bean:size标签创建一个java.lang.Integer类型的bean，这个bean的值为该标签指定的Collection或Map 中所含元素的个数。这可以和logic:iterate标签配合使用，因为logic:iterate标签不能得到所叠代的集合的元素的个数，这有时候很不方便。<br /><br />下面的代码片段示例了bean:size标签取出persons中还有元素的个数，其中listForm和persons的定义参见bean:define标签部分：<br /><br />&lt;logic:notEmpty name="listForm" property = "persons"><br />&lt;bean:size id="size" name="listForm" property = "persons"/><br />&lt;bean:write name="size"/><br />&lt;/logic:notEmpty><br /><br /> <br />bean:struts<br /><br />bean:struts标签取回Struts的内部对象formBean、forward或mapping的值，然后用id绑定到page作用域中(这种绑定是为了其它标签能够使用该值)，并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。<br /><br />下面的代码片段示例了bean:struts标签取出listForm对象，让我们先来看一下listForm的定义在读代码：<br /><br />&lt;!-- listForm的定义&lt;form-bean name="listForm" type="org.solo.struts.form.ListForm" /> --><br />&lt;bean:struts id="listFormBean" formBean="listForm"/><br />name:&lt;bean:write name="listFormBean" property="name"/>&lt;br/><br />type:&lt;bean:write name="listFormBean" property="type"/>&lt;br/><br />dynamic:&lt;bean:write name="listFormBean" property="dynamic"/>&lt;br/><br /><br />上面代码运行的结果为：<br /><br />name:listForm<br />type:org.solo.struts.form.ListForm<br />dynamic:false<br /><br /> <br />bean:write<br /><br />bean:write标签将指定的bean的属性值写到当前的JspWriter中，并且可以对输出进行格式化。<br /><br />下面的代码片段示例了bean:write标签输出User-Agent：<br /><br />&lt;logic:present header="User-Agent"><br />&lt;bean:header id="header" name="User-Agent"/><br />&lt;bean:write name="header"/><br />&lt;/logic:present><br /><br />下面的代码片段示例了bean:write标签格式化输出当前日期，其中now是在DataForm中定义的一个java.util.Date类型的域(值为new Date())，format.date.standard是在资源文件中的一个键(format.date.standard=yyyy-MM- dd)：<br /><br />&lt;bean:define id="date" name="dataForm" property="now"/><br />&lt;br/>&lt;bean:write name="date"/><br />&lt;br/>&lt;bean:write name="date" format="MM/dd/yyyy"/><br />&lt;br/>&lt;bean:write name="date" formatKey="format.date.standard"/><br /><br />上面代码运行的结果为：<br /><br />Sun Jun 04 17:04:05 CST 2006<br />06/04/2006<br />2006-06-04<br /><br /> <br />html:base<br /><br />虽然这里的标题是html:base标签，但是这里也是这篇指南要介绍的第一个Struts html标签。因此我想在这里从整体上简单的介绍一下，最后给出一个对照表。其中的绝大多数标签就不一一介绍了，要介绍的也不会在这里介绍，而是将其独立出来以显重要性。<br /><br />从用户处收集数据是动态web应用非常重要的一个方面，因此构建输入表单也就自然而然的成为struts框架的一个重要内容。Struts html标签库含有创建Struts输入表单的标签，和其它标签库(bean、logic、nested和tiles)中的标签一起协作就可以产生基于 html的用户界面。<br /><br />下面的对照表会使您对Struts html标签库有一个整体的印象：<br /><br />图示 1. Struts HTML标签和HTML元素对照表<br />Struts HTML标签和HTML元素对照表<br /><br /> <br /> <br />html:cancel<br /><br />html:cancel标签生成一个取消按钮。当点击该按钮后action servlet会绕过相应的form bean的validate()方法，同时将控制权交给相应的action。在该action中可以使用 Action.isCancelled(HttpServletRequest)方法判断是否被取消了。如果返回true表示这个action被取消了，否则表示这个action没有被取消。<br /><br />请注意，如果您修改了html:cancel标签的property属性值，那么struts提供的cancel探测机制就失效了，您自己必须提供类似的机制。<br /><br />下面是可取消的action的配置文件，注意&lt;set-property property="cancellable" value="true"/>这一行，如果不添加Struts会抛出 org.apache.struts.action.InvalidCancelException异常。这是我在完成本指南的过程中发现的唯一向下不兼容的地方。<br /><br />&lt;action path="/cancel"<br />type="org.solo.struts.action.CancelAction" name="cancelForm" scope="request"><br />&lt;set-property property="cancellable" value="true"/><br />&lt;forward name="success" path="/cancel.jsp" /><br />&lt;/action><br /><br />下面是html:cancel标签的代码：<br /><br />&lt;html:cancel>取消&lt;/html:cancel><br /><br />下面是对应的action中的代码：<br /><br />if(isCancelled(request)){<br />//action被取消时要做的事情写在这里<br />return mapping.findForward("cancel");<br />}else{<br />//action没有被取消时要做的事情写在这里<br />return mapping.findForward("success");<br />}<br /><br /> <br />html:select<br /><br />html:select标签生成一个select元素。是单选还是多选取决于该标签的multiple属性。如果指定了 multiple="true"则为多选，此时对应的属性应该是一个数组。如果没有指定multiple="true"则为单选，此时对应的属性应该是标量。<br /><br />注意：为了正确的处理没有做任何的选择的情况，在ActionForm中的reset()方法中必须将标量属性设置为默认值而将数组的长度置为0。<br /><br />另外的一个重要问题就是struts如何生成option元素了，这个任务struts交给了html:option、html:options和html:optionsCollection三个标签。<br /><br />html:option标签<br /><br />html:option标签生成一个HTML的option元素。该标签必须嵌在html:select标签中。它的显示文本来自其标签体，也可以来自于资源文件。它的value属性用来指定什么值将要被提交。<br /><br />&lt;html:option value="one">one&lt;/html:option><br />&lt;html:option value="two">two&lt;/html:option><br /><br />html:options标签<br /><br />html:options标签生成多个HTML的option元素。该标签必须嵌在html:select标签中。而且工作方式有些特殊，它的name与property属性和其它标签的name与property属性意义不一致，让我们具体看一下它的工作方式。<br /><br />    * 指定collection属性<br />    * 没有指定collection属性<br /><br />指定collection属性<br /><br />让我通过示例来介绍在指定collection属性时该标签的工作方式，首先要说明selectForm中的persons和listForm中的persons完全一致。请参见bean:define标签。<br /><br />下面的代码先利用bean:define标签将selectForm中的persons取到page作用域中，然后html:options标签再依据collection="personCollection"选中这个persons并将其中的每一个对象(Person类型)生成一个option 元素。该标签的property="id"表示persons中的对象(Person类型)的id属性将作为option元素的value值。该标签的 labelProperty="name"表示persons中的对象(Person类型)的name属性将作为option元素的label值。<br /><br />当这个select提交时所选择的值将被提交到selectForm(name="selectForm")中的person对象(这是在 SelectForm中声明的一个Person类型的域专门用来接收提交的值)的id属性中(property="person.id")。<br /><br />&lt;bean:define id="personCollection" name="selectForm"  property="persons"/><br />&lt;html:select name="selectForm" property="person.id" size="1"><br />&lt;html:options collection="personCollection" property="id" labelProperty="name"/><br />&lt;/html:select><br /><br />没有指定collection属性<br /><br />让我通过示例来介绍没有指定collection属性时该标签的工作方式，先来看看ids和names的定义：<br /><br />  private List&lt;String> ids = null;<br />private List&lt;String> names = null;<br /><br />上面的代码来自SelectForm，其中ids是一个String的列表，names也是一个String的列表。我们暂时假定这两个列表含有相同数目的元素。有了这些让我们开始介绍下面的代码。html:options标签用ids中的第i个值作为option元素的value值同时使用 names中相同位置的值(第i个值)作为option元素的label值。如果ids比names长那么多出的ids中的值将即作为option的 value又作为option的label。如果ids比names短那么多出的names的值会被丢掉。<br /><br />当这个select提交时所选择的值将被提交到selectForm(name="selectForm")中的person对象(这是在 SelectForm中声明的一个Person类型的域专门用来接收提交的值)的id属性中(property="person.id")。<br /><br />&lt;html:select name="selectForm" property="person.id" size="1"><br />&lt;html:options property="ids" labelProperty="names"/><br />&lt;/html:select><br /><br />html:optionsCollection标签<br /><br />html:optionsCollection标签生成多个HTML的option元素。该标签必须嵌在html:select标签中。它的功能和 html:options标签的相同，但是它的name与property属性和其它标签的name与property属性意义一致，理解起来比较自然。<br /><br />让我通过示例来介绍html:optionsCollection标签的用法。首先依据name="selectForm"和 property="persons"取到selectForm中的persons列表，然后将列表中的对象(Person类型)的id属性作为 option元素的value值(value="id")，将列表中的对象(Person类型)的name属性作为option元素的label值 (label="name")。<br /><br />&lt;html:select name="selectForm" property="person.id" size="1"><br />&lt;html:optionsCollection name="selectForm" property="persons" label="name" value="id"/><br />&lt;/html:select><br /><br />下面是一个多选的示例，虽然示例中使用了html:options标签，但是html:option和 html:optionsCollection也能够用来多选。而且您还必须意识到html:option、html:options和 html:optionsCollection这三个标签可以同时使用。代码中的personIds是SelectForm中声明的一个String[] 类型的数组用来接收提交的多个值。<br /><br />&lt;html:select name="selectForm" property="personIds" multiple="true" size="2"><br />&lt;html:options property="ids" labelProperty="names"/><br />&lt;/html:select><br /><br /> <br />html:checkbox<br /><br />html:check标签生成一个checkbox。这里的value值可以是true，yes或on。如果您要提交其它的值(如某种形式的标识)应该考虑使用html:multibox标签。<br /><br />注意:为了正确的处理没有选中的checkbox您必须在reset()中设置对应的属性为false。<br /><br />下面的代码示例了html:checkbox标签的用法，其中CheckboxForm中声明了三个boolean类型的域，如下：<br /><br />  &lt;!-- 略掉了get方法(也可以是isXXX形式)和set方法 --><br />private boolean one = false;<br />private boolean two = false;<br />private boolean three = false;<br /><br />&lt;html:checkbox name="checkboxForm" property="one">One&lt;/html:checkbox><br />&lt;html:checkbox name="checkboxForm" property="two">Two&lt;/html:checkbox><br />&lt;html:checkbox name="checkboxForm" property="three">Three&lt;/html:checkbox><br /><br />如果选中后被提交则相应的属性的值为true。<br /> <br />html:radio<br /><br />html:radio标签生成一个radio。主要的用法有两种，下面我们通过代码来示例。<br /><br />下面的代码示例了html:radio标签的一般用法，如果被提交则选中的radio的value值将被提交到radioForm中的id中。<br /><br />&lt;html:radio name="radioForm" property="id" value="00001">One&lt;/html:radio><br />&lt;html:radio name="radioForm" property="id" value="00002">Two&lt;/html:radio><br /><br />下面的代码示例了html:radio标签的典型用法，其中的persons和bean:define标签中的一致，您可以参考 bean:define标签。我只介绍这个&lt;html:radio idName="person" property="id" value="id">，idName指定html:radio要使用的bean(这里为person)，value="id"表示person的 id属性将作为radio元素的value值而property="id"表示提交时选中的radio的值将被提交给radioForm中的id属性。<br /><br />&lt;logic:notEmpty name="radioForm" property="persons"><br />&lt;logic:iterate id="person" name="radioForm" property="persons"><br />&lt;html:radio idName="person" property="id" value="id"><br />&lt;bean:write name="person" property="name"/><br />&lt;/html:radio><br />&lt;/logic:iterate><br />&lt;/logic:notEmpty><br /><br /> <br />html:multibox<br /><br />html:multibox标签生成多个checkbox。当您要使用大量的checkbox时使用这个标签非常方便，可以使您避免在ActionForm中声明大量的boolean类型的变量，带之以一个数组就行了。<br /><br />注意:为了正确的处理没有选中的checkbox您必须在reset()中设置数组的长度为0。<br /><br />下面的代码示例了html:multibox标签的一般用法，如果被提交则选中的所有checkbox的value值将被提交到multiboxForm中的selectedItems中，这是一个String[]数组。<br /><br />&lt;html:multibox name="multiboxForm" property="selectedItems" value="00001"/><br />&lt;html:multibox name="multiboxForm" property="selectedItems" value="00002"/><br /><br />下面的代码示例了html:multibox标签的典型用法：<br /><br />&lt;logic:iterate id="person" name="multiboxForm" property="persons"><br />&lt;html:multibox property="selectedItems"><br />&lt;bean:write name="person" property="id"/><br />&lt;/html:multibox><br />&lt;bean:write name="person" property="name"/><br />&lt;/logic:iterate><br /><br /> <br />html:link<br /><br />html:link标签生成一个锚点(&lt;a>)元素。我从html:link标签如何构造基本url和如何构造query参数两个方面来介绍这个标签。<br /><br />构造基本url是依据该标签的如下四个属性进行的，这四个属性一次只能出现一个。让我们看看它们：<br /><br />    * forward，指定一个全局ActionForward的名称。另外如果forward是module相关的则该forward必须指向一个action而不能是一个页面。<br />    * action，指定一个Action的名称。<br />    * href，struts会直接使用这个值而不会对其进行任何处理。<br />    * page，指定一个页面的路径，必须以/开始。<br /><br /> <br /><br />构造query参数，下面列举了可能的形式，其中baseurl只是一个占位符：<br /><br />    * baseurl?p=00001(单参单值)<br />    * baseurl?p1=00001&p2=00002&p3=00003(多参单值)<br />    * baseurl?p=00001&p=00002&p=00003(单参多值)<br />    * baseurl?p1=00001&p2=00002&p=00001&p=00002&p=00003(混合)<br /><br /> <br /><br />下面我们以代码示例来说明每一种html:link的用法，首先让我们花点时间看看相关action中的代码：<br /><br />&lt;!-- 下面所有代码的数据都是在这里构造的 --><br />public ActionForward execute(ActionMapping mapping,ActionForm form,HttpServletRequest request,HttpServletResponse response) {<br />DataForm dataForm = (DataForm) form;<br />dataForm.setParam("00001");<br />HashMap paramSingleMap = new HashMap();<br />paramSingleMap.put("p1","00001");<br />paramSingleMap.put("p2","00002");<br />paramSingleMap.put("p3","00003");<br />dataForm.setParamSingleMap(paramSingleMap);<br />HashMap paramMultiMap = new HashMap();<br />paramMultiMap.put("p",new String[]{"00001","00002","00003"});<br />dataForm.setParamMultiMap(paramMultiMap);<br />HashMap paramSMMap = new HashMap();<br />paramSMMap.put("p1","00001");<br />paramSMMap.put("p2","00002");<br />paramSMMap.put("p",new String[]{"00001","00002","00003"});<br />dataForm.setParamSMMap(paramSMMap);<br />List&lt;Person> persons = new ArrayList&lt;Person>();<br />Person person1 = new Person();<br />person1.setId("00001");<br />person1.setName("赵辰");<br />Person person2 = new Person();<br />person2.setId("00002");<br />person2.setName("李为芳");<br />Person person3 = new Person();<br />person3.setId("00003");<br />person3.setName("王微");<br />persons.add(person1);<br />persons.add(person2);<br />persons.add(person3);<br />dataForm.setPersons(persons);<br />return mapping.findForward("success");<br />}<br /><br />&lt;!-- 这用来设置一个位置 --><br />&lt;html:link linkName="top"/><br />&lt;!-- 这用来定位到上面的那个位置 --><br />&lt;html:link page="/link.do" anchor="top">Go Top&lt;/html:link><br /><br />&lt;html:link page="/link.do" paramId="p" paramName="dataForm" paramProperty="param">单参单值&lt;/html:link>&lt;br/><br />&lt;html:link page="/link.do" name="dataForm" property="paramSingleMap">多参单值&lt;/html:link>&lt;br/><br />&lt;html:link page="/link.do" name="dataForm" property="paramMultiMap">单参多值&lt;/html:link>&lt;br/><br />&lt;html:link page="/link.do" name="dataForm" property="paramSMMap">混合&lt;/html:link><br /><br />下面的代码示例了html:link标签的indexed属性和indexId属性的用法，这两个属性只有html:link标签嵌套在logic:iterate标签中时才可用。<br /><br />&lt;logic:iterate id="person" name="dataForm" property="persons"><br />&lt;html:link action="/link.do" paramId="person" paramName="person" paramProperty="id" indexed="true" indexId="number">person&lt;/html:link><br />&lt;br/><br />&lt;/logic:iterate><br />&lt;!-- 下面是上面代码的运行结果(产生的html)<br />&lt;a href="/struts-demo/link.do?person=00001&number=0">赵辰&lt;/a>&lt;br/><br />&lt;a href="/struts-demo/link.do?person=00002&number=1">李为芳&lt;/a>&lt;br/><br />&lt;a href="/struts-demo/link.do?person=00003&number=2">王微&lt;/a>&lt;br/><br />其中的number是由indexId="number"确定的，而该参数的值为元素在集合中的位置。<br />--><br /><br />html:rewrite标签和html:link标签类似只是不生成锚点(&lt;a>)，而是简单的输出字符串。<br /> <br />html:errors<br /><br />html:errors标签和html:messages标签的功能相似，所以我们放到一起来介绍。<br /><br />html:errors标签将由name属性指定的ActionMessages、ActionErrors、String和String[]直接输出到页面中。<br /><br />html:messages标签将用由name属性(注意message属性值对它的影响)指定的ActionMessages、ActionErrors、String和String[]创建一个新的属性和scripting变量，使用id属性值作为名称。<br /><br />html:errors标签和html:messages标签的property属性是用来为errors和messages分类的。我们可以给这两个标签指定property属性，以便只显示某一类的错误或消息。<br /><br />在资源文件增加了如下的内容：<br /><br /># -- standard errors --<br />errors.header=&lt;ul><br />errors.prefix=&lt;li><br />errors.suffix=&lt;/li><br />errors.footer=&lt;/ul><br />error=error with none value .<br />error1=error1 with one value is {0} .<br />error2=error2 with two values are {0} , {1} .<br />error3=error3 with three values are {0} , {1} , {2} .<br />error4=error4 with four values are {0} , {1} , {2} ,{3} .<br /><br />下面的代码示例了actionErrors的构造：<br /><br />public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {<br />ActionErrors actionErrors = new ActionErrors();<br />actionErrors.add("property1",<br />new ActionMessage("error"));<br />actionErrors.add("property2",<br />new ActionMessage("error1","value0"));<br />actionErrors.add("property2",new ActionMessage("error2","value0","value1"));<br />actionErrors.add("property3",new ActionMessage("error3","value0","value1","value2"));<br />actionErrors.add("property3",new ActionMessage("error4","value0","value1","value2","value3"));<br />actionErrors.add("property4", new ActionMessage("error1",new Object[]{"value0"}));<br />actionErrors.add("property4", new ActionMessage("error2",new Object[]{"value0","value1"}));<br />actionErrors.add("property4", new ActionMessage("error3",new Object[]{"value0","value1", "value2"}));<br />actionErrors.add("property5",new ActionMessage("error4",new Object[]{"value0","value1", "value2","value3"}));<br />actionErrors.add("notBundle",new ActionMessage("not a bundle key",false));<br />return actionErrors;<br />}<br /><br />errors标签代码示例：<br /><br />&lt;html:errors/><br />&lt;br/><br />&lt;html:errors property="property4"/><br /><br />messages标签代码示例：<br /><br />&lt;logic:messagesPresent><br />&lt;ul><br />&lt;html:messages id="message"><br />&lt;li>&lt;bean:write name="message"/>&lt;/li><br />&lt;/html:messages><br />&lt;/ul><br />&lt;/logic:messagesPresent><br />&lt;br/><br />&lt;logic:messagesPresent><br />&lt;ul><br />&lt;html:messages id="message" property="property4"><br />&lt;li>&lt;bean:write name="message"/>&lt;/li><br />&lt;/html:messages><br />&lt;/ul><br />&lt;/logic:messagesPresent><br /><br />图示 2. 上面的两段代码示例运行结果相同，如下所示：<br />运行结果<br /><br /> <br /> <br />html:javascript<br /><br />html:javascript标签生成用于校验的javascript脚本代码。<br /><br />下面的代码片段示例了html:javascript标签的基本用法，其中formName属性的值是在validation.xml文件的&lt;formset>中定义的form的名称。有一点值得注意的是在确定&lt;formset>时要使用合适的language属性值。<br /><br />&lt;html:javascript formName="dataForm"/><br /><br /> <br />html:xhtml<br /><br />html:xhtml标签在页面中一出现就是告诉该页的所有其它的Struts html标签以XHTML1.0兼容的形式输出。这和将html:html标签的xhtml属性值指定为true有些类似。如果上述情况都没有出现，Struts html标签将以html4.01兼容的形式输出。<br /> <br />logic:iterate<br /><br />logic:iterate标签用来迭代集合，您可以使用如下方式来为这个标签指定其要叠代的集合：<br /><br />    * 使用一个运行时表达式，这个表达式的值是一个集合。<br />    * 用name属性引用一个JSP Bean，这个JSP Bean本身就是一个集合。<br />    * 用name属性引用一个JSP Bean，这个JSP Bean的一个属性是一个集合，这时可以联合使用property来指定这个集合。<br /><br />上面所提到的集合可以是：<br /><br />    * 对象类型或原子类型的数组(Array)。<br />    * java.util.Collection的实现，包括ArrayList，Vector。<br />    * java.util.Enumeration的实现。<br />    * java.util.Iterator的实现。<br />    * java.util.Map的实现，包括HashMap，Hashtable和TreeMap。<br /><br />如果您叠代的集合中含有null的值，这时需要采取一定的措施，因为这时logic:iterate不会在page作用域中创建对象。一般是使用&lt;logic:present>标签或&lt;logic:notPresent>标签来判断一下。<br /><br />下面是logic:iterate叠代ArrayList的示例的对象引用关系和部分代码：<br /><br />图示 3. logic:iterate中对象的引用关系<br />logic:iterate中对象的引用关系<br /><br /> <br /><br />图中的persons列表是在ListAction中填充的，在这里只是简单的加入了三个Person对象，在实际的应用中这些数据应该取自数据库。具体的代码如下：<br /><br />public ActionForward execute(ActionMapping mapping,ActionForm form, HttpServletRequest request,	HttpServletResponse response) {<br />ListForm listForm = (ListForm) form;<br />List&lt;Person> persons = new ArrayList&lt;Person>();<br />Person person1 = new Person();<br />person1.setId("00001");<br />person1.setName("赵辰");<br />Person person2 = new Person();<br />person2.setId("00002");<br />person2.setName("李为芳");<br />Person person3 = new Person();<br />person3.setId("00003");<br />person3.setName("王微");<br />persons.add(person1);<br />persons.add(person2);<br />persons.add(person3);<br />listForm.setPersons(persons);<br />return mapping.findForward("success");<br />}<br /><br />标签输出的结果为：<br /><br />00001-->赵辰<br />00002-->李为芳<br />00003-->王微<br /><br /> <br />logic:present<br /><br />如果指定的值出现该标签就会创建其标签体内的内容。该标签用于以下情况：<br /><br />    * 检查具有指定名称的cookie是否出现。<br />    * 检查具有指定名称的header是否出现。<br />    * 检查具有指定名称的JSP Bean是否出现 或 检查具有指定名称的JSP Bean中的property属性是否出现。<br />    * 检查request中指定名称的参数是否出现。<br />    * 检查当前的认证用户是否与指定的安全角色相关联。<br />    * 检查当前认证的主体是否具有指定的名字。<br /><br />下面的代码示例了logic:present标签检查具有指定名称User-Agent的header是否出现：<br /><br />&lt;logic:present header="User-Agent"><br />您的浏览器是&lt;bean:header id="userAgent" name="User-Agent"/> &lt;bean:write name="userAgent"/>。&lt;br/><br />&lt;/logic:present><br /><br />logic:notPresent标签的应用正好和logic:present标签相反。<br /> <br />logic:messagesPresent<br /><br />logic:messagesPresent标签用于以下情况：<br /><br />    * 在request作用域中存在一个ActionMessages对象，标签的property属性和ActionMessages中的property对应。<br />    * 在request作用域中存在一个ActionErrors对象，标签的property属性和ActionErrors中的property对应。<br />    * 存在一个String对象，将其转换(构造)成ActionMessage然后在添加到ActionMessages中。<br />    * 存在一个String Array对象，将数组中的每一个String转换成一个ActionMessage，在将其添加到ActionMessages中。<br /><br />标签的message属性值为true时将以Globals.MESSAGE_KEY为key在request作用域中查找Message，其它情况下，将name的值作为key查找，如果name 没有出现，默认值为Globals.ERROR_KEY。<br /><br />下面的代码示例了logic:messagesPresent标签的典型用法：<br /><br />&lt;logic:messagesPresent><br />&lt;ul><br />&lt;html:messages id="message"><br />&lt;li>&lt;bean:write name="message"/>&lt;/li><br />&lt;/html:messages><br />&lt;/ul><br />&lt;/logic:messagesPresent><br /><br />标签logic:messagesNotPresent的应用正好和logic:messagesPresent的应用相反。<br /> <br />logic:empty<br /><br />logic:empty标签是用来判断是否为空的。如果为空，该标签体中嵌入的内容就会被处理。该标签用于以下情况：<br /><br />    * 当Java对象为null时<br />    * 当String对象为""时<br />    * 当java.util.Collection对象中的isEmpty()返回true时<br />    * 当java.util.Map对象中的isEmpty()返回true时<br /><br />下面的代码示例了logic:empty标签判断集合persons是否为空：<br /><br />&lt;logic:empty name="listForm" property = "persons"><br />&lt;div>集合persons为空!&lt;/div><br />&lt;/logic:empty><br /><br />logic:notEmpty标签的应用正好和logic:empty标签相反。<br /> <br />logic:match<br /><br />logic:match标签用来处理子串匹配问题。<br /><br />如果指定的值匹配该标签就会创建其标签体内的内容。该标签用于以下情况：<br /><br />    * 检查具有指定名称的cookie是否与该标签的value匹配。<br />    * 检查具有指定名称的header是否与该标签的value匹配。<br />    * 检查具有指定名称的JSP Bean是否与该标签的value匹配 或 检查具有指定名称的JSP Bean中的property属性值是否与该标签的value匹配。<br />    * 检查request中指定名称的参数值是否与该标签的value匹配。<br /><br /> <br /><br />下面的代码示例了logic:match标签的典型用法：<br /><br />&lt;logic:present header="User-Agent"><br />&lt;logic:match header="User-Agent" value="MSIE 6.0">MS IE 6.0&lt;/logic:match><br />&lt;/logic:present><br /><br />logic:notMatch标签的应用正好和logic:match标签相反。<br /> <br />logic:equal<br /><br />这里要介绍的不只是logic:equal(=)标签，而是要介绍一类标签，这类标签完成比较运算，包括：<br /><br />    * logic:equal(=)<br />    * logic:notEqual(!=)<br />    * logic:greaterEqual(>=)<br />    * logic:lessEqual(&lt;=)<br />    * logic:graterThan(>)<br />    * logic:lessThan(&lt;)<br /><br />该类标签的用法类似，我们只介绍logic:equal标签，其它的留给您自己去完成。<br /><br />logic:equal是用来判断是否相等的。如果相等，该标签体中嵌入的内容就会被处理。该标签用于以下情况：<br /><br />    * 比较由该标签的cookie属性指定的cookie的值是否与该标签的value属性值相等。<br />    * 比较由该标签的header属性指定的header的值是否与该标签的value属性值相等。<br />    * 比较由该标签的name属性指定的JSP Bean是否与该标签的value属性值相等(property属性不出现)或比较由该标签的name属性指定的JSP Bean中的property属性值是否与该标签的value属性值相等。<br />    * 比较由该标签的parameter属性指定的参数值(request中)是否与该标签的value属性值相等。<br /><br /> <br />logic:forward<br /><br />我觉得将forward和redirect这两个动作放到一起对比着介绍更加有利于理解，基于此原因也就将logic:forward和logic:redirect这两个标签也拿到这里一起介绍了。<br /><br />让我们看看这两个动作的区别：<br /><br />    * forward是在servlet内部执行，浏览器完全不会感知到这个动作，原始的url也不会改变，浏览器重新装载的话也只是对原始的请求进行简单的重复。<br />    * redirect则分成两个步骤：第一步是web应用程序告诉浏览器第二个url，然后浏览器向第二个url发送请求。<br /><br /> <br /><br />redirect比forward慢，因为浏览器要做二次请求。还有就是要注意，在第一次的请求作用域(request作用域)内的bean对于第二次请求是不可见的。<br /><br />理解了上面描述的区别也就知道了什么时候该选用logic:forward标签什么时候该选用logic:redirect标签了。 logic:forward标签完成PageContext.forward()或 HttpServletResponse.sendRedirect()，如何选择由控制器决定。logic:redirect标签完成 HttpServletResponse.sendRedirect()。<br /><br />在使用logic:redirect标签时我们可以向使用html:link一样构造baseurl和query参数。如果您感兴趣可以参考html:link标签。
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/232983#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 26 Aug 2008 20:29:09 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/232983</link>
        <guid>http://canofy.javaeye.com/blog/232983</guid>
      </item>
      <item>
        <title>struts请求</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/210962" style="color:red;">http://canofy.javaeye.com/blog/210962</a>&nbsp;
          发表时间: 2008年07月03日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          从Struts源码看action调用过程，以下代码片断来自struts1.1<br /><br />struts中所有的请求都是通过ActionServlet转发的，一个action请求首先会传给 ActionServlet，ActionServlet会将其委托给RequestProcessor，RequestProcessor进行一些处理后将调用对应的Action类来执行该请求。<br /><br />ActionServlet、RequestProcessor、Action的职责<br />ActionServlet负责通过Struts配置文件初始化Struts应用程序的配置，并负责接受用户请求。<br />RequestProcessor负责与请求相关的各方面，如选择与请求相关联的Form Bean、用数据填充Form<br />Bean、验证Form Bean的有效性及选择正确的Action类来执行该请求。<br />Action是Struts框架的终点和你的应用程序代码的起点。<br /><br />以下为Action执行过程的详细分析：<br />ActionServlet继承自HttpServlet它重写了其doGet、doPost方法，这两个方法执行时都会调用ActionServlet 的process(HttpServletRequest request, HttpServletResponse response)方法，这里将会获取一个RequestProcessor的实例，并调用RequestProcessor的process (HttpServletRequest request, HttpServletResponse response)方法，这样用户请求就转到了RequestProcessor<br />以下为RequestProcessor类的process(HttpServletRequest request, HttpServletResponse response)方法的片断<br />        // Create or acquire the Action instance to process this request<br />        Action action = processActionCreate(request, response, mapping);<br />        if (action == null) {<br />            return;<br />        }<br /><br />        // Call the Action instance itself<br />        ActionForward forward =<br />            processActionPerform(request, response,<br />                                 action, form, mapping);<br /><br />        // Process the returned ActionForward instance<br />        processForwardConfig(request, response, forward);<br /><br />这里用户请求的Action被实例化后传给processActionPerform(request, response,action, form, mapping)方法，此方法将调用Action的execute(HttpServletRequest request,<br />                             HttpServletResponse response,<br />                             ActionForm form,<br />                             ActionMapping mapping)方法并返回一个ActionForward，<br />processForwardConfig(request, response, forward)方法将用户界面转到ActionForward指定的url。<br />至此用户请求的action就执行完毕了。
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/210962#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Thu, 03 Jul 2008 11:21:54 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/210962</link>
        <guid>http://canofy.javaeye.com/blog/210962</guid>
      </item>
      <item>
        <title>网上找到一个分页存储过程</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/210097" style="color:red;">http://canofy.javaeye.com/blog/210097</a>&nbsp;
          发表时间: 2008年07月01日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          /*<br />  经测试，在 14483461 条记录中查询第 100000 页，每页 10 条记录按升序和降序第一次时间均为 0.47 秒，第二次时间均为 0.43 秒，测试语法如下：<br />  exec GetRecordFromPage news,newsid,10,100000<br />  news 为 表名, newsid 为关键字段, 使用时请先对 newsid 建立索引。<br />*/<br /><br />/*<br />  函数名称: GetRecordFromPage<br />  函数功能: 获取指定页的数据<br />  参数说明: @tblName      包含数据的表名<br />           @fldName      关键字段名<br />           @PageSize     每页记录数<br />           @PageIndex    要获取的页码<br />           @OrderType    排序类型, 0 - 升序, 1 - 降序<br />           @strWhere     查询条件 (注意: 不要加 where)<br />  作　　者: 铁拳<br />  邮　　箱: sunjianhua_kki@sina.com<br />  创建时间: 2004-07-04<br />  修改时间: 2004-07-04<br />*/<br />CREATE PROCEDURE GetRecordFromPage<br />    @tblName      varchar(255),       -- 表名<br />    @fldName      varchar(255),       -- 字段名<br />    @PageSize     int = 10,           -- 页尺寸<br />    @PageIndex    int = 1,            -- 页码<br />    @OrderType    bit = 0,            -- 设置排序类型, 非 0 值则降序<br />    @strWhere     varchar(2000) = ''  -- 查询条件 (注意: 不要加 where)<br />AS<br /><br />declare @strSQL   varchar(6000)       -- 主语句<br />declare @strTmp   varchar(1000)       -- 临时变量<br />declare @strOrder varchar(500)        -- 排序类型<br /><br />if @OrderType != 0<br />begin<br />    set @strTmp = '&lt;(select min'<br />    set @strOrder = ' order by [' + @fldName + '] desc'<br />end<br />else<br />begin<br />    set @strTmp = '>(select max'<br />    set @strOrder = ' order by [' + @fldName +'] asc'<br />end<br /><br />set @strSQL = 'select top ' + str(@PageSize) + ' * from ['<br />    + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['<br />    + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['<br />    + @fldName + '] from [' + @tblName + ']' + @strOrder + ') as tblTmp)'<br />    + @strOrder<br /><br />if @strWhere != ''<br />    set @strSQL = 'select top ' + str(@PageSize) + ' * from ['<br />        + @tblName + '] where [' + @fldName + ']' + @strTmp + '(['<br />        + @fldName + ']) from (select top ' + str((@PageIndex-1)*@PageSize) + ' ['<br />        + @fldName + '] from [' + @tblName + '] where ' + @strWhere + ' '<br />        + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrder<br /><br />if @PageIndex = 1<br />begin<br />    set @strTmp = ''<br />    if @strWhere != ''<br />        set @strTmp = ' where (' + @strWhere + ')'<br /><br />    set @strSQL = 'select top ' + str(@PageSize) + ' * from ['<br />        + @tblName + ']' + @strTmp + ' ' + @strOrder<br />end<br /><br />exec (@strSQL)<br /><br />GO
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/210097#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Tue, 01 Jul 2008 11:54:32 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/210097</link>
        <guid>http://canofy.javaeye.com/blog/210097</guid>
      </item>
      <item>
        <title>文件读取 </title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/206355" style="color:red;">http://canofy.javaeye.com/blog/206355</a>&nbsp;
          发表时间: 2008年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
package cn.test;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import org.apache.commons.lang.StringUtils;

public class FileUtils {
	 public static final String TEMPLATE_PATH  = "c:\\FileUtils.java";
	 public static final String TEMPLATE_OUTPATH  = "c:\\out.txt";
	 public static final String TEMPLATE_INPATH  = "cn/test.txt";
	
	public  String getFileContent(String path,String charset){
		StringBuffer sb=new StringBuffer();
		String line;
		BufferedReader br=null;
		try {
			br=new BufferedReader(new InputStreamReader(new FileInputStream(path),charset));
			
			while((line=br.readLine())!=null){
				sb.append(line);
				sb.append("\n");
			}
		} catch (UnsupportedEncodingException e) {
			System.out.println("读取文件有误！");
			//e.printStackTrace();
		} catch (IOException e) {
			System.out.println("读取文件有误！");
			//e.printStackTrace();
		}finally{
			
			if(!StringUtils.isEmpty(br.toString())){
				try {
					br.close();
				} catch (IOException e) {
					System.out.println("关闭文件有误");
					e.printStackTrace();
				}
			}
			
		}
		
		return sb.toString();
		
	}
	public String fileReadToString(String path){
		StringBuffer sb=new StringBuffer();
		String line;
		BufferedReader br=null;
		try {
			//ClassLoader.getSystemResourceAsStream(path)中的path路径是类路径下的文件
			//如包cn下有test.txt文件，则路径是"cn/test.txt"。
			br=new BufferedReader(new InputStreamReader(ClassLoader.getSystemResourceAsStream(path),"UTF-8"));
			while((line=br.readLine())!=null){
				sb.append(line);
				sb.append("\n");
			}
		} catch (UnsupportedEncodingException e) {
			System.out.println("读取文件有误！");
			//e.printStackTrace();
		} catch (IOException e) {
			System.out.println("读取文件有误！");
			//e.printStackTrace();
		}finally{
			
			if(!StringUtils.isEmpty(br.toString())){
				try {
					br.close();
				} catch (IOException e) {
					System.out.println("关闭文件有误");
					e.printStackTrace();
				}
			}
			
		}
		
		return sb.toString();
	}
	
	public void stringWriteToTxt(String str,String path){
		BufferedWriter bw=null;
		try {
			bw=new BufferedWriter(new FileWriter(path));
			bw.write(str);
		} catch (IOException e) {
			System.out.println("写文件时有错误！");
			e.printStackTrace();
		}finally{
			if(bw!=null){
				try {
					bw.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
	
	public static void main(String[] args) throws FileNotFoundException{
		FileUtils fileUtils=new FileUtils();
		String str=fileUtils.fileReadToString(TEMPLATE_INPATH);
		System.out.println(str);
		fileUtils.stringWriteToTxt(str, TEMPLATE_OUTPATH);
		File file=new File(TEMPLATE_OUTPATH);
		FileInputStream is=new FileInputStream(file);
		ClassLoader.getSystemResourceAsStream(TEMPLATE_INPATH);
		
	}
}

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/206355#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 20 Jun 2008 16:24:58 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/206355</link>
        <guid>http://canofy.javaeye.com/blog/206355</guid>
      </item>
      <item>
        <title>request处理</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/206352" style="color:red;">http://canofy.javaeye.com/blog/206352</a>&nbsp;
          发表时间: 2008年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">
package cn.test;


import java.io.UnsupportedEncodingException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;


public class RequestUtil {

	static Logger logger=Logger.getLogger(RequestUtil.class);
	
	
	/**
	 * 获取request中的数据
	 * @param request
	 * @param parameter
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String getStringParameter(HttpServletRequest request,String parameter) throws UnsupportedEncodingException{
		String stringParameter = request.getParameter(parameter).trim();
		if ( StringUtils.isEmpty(stringParameter) ) return "";		
		parameter = new String((stringParameter).getBytes("ISO-8859-1"),"UTF-8"); 		
		return parameter;
	}
	
	/**
	 * 带有默认值的获取request中的数据
	 * @param request
	 * @param parameter
	 * @param defaultValue
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public static String getStringParameter(HttpServletRequest request,String parameter,String defaultValue) throws UnsupportedEncodingException{
		String stringParameter = request.getParameter(parameter).trim();
		if ( StringUtils.isEmpty(stringParameter) ) return defaultValue;		
		parameter = new String((stringParameter).getBytes("ISO-8859-1"),"UTF-8"); 		
		return parameter;
	}
	
	/**
	 * 获取request中的int型数据
	 * @param request
	 * @param parameter
	 * @return
	 */
	public static int getIntParameter(HttpServletRequest request,String parameter){		
		String stringParameter = request.getParameter(parameter).trim();
		int intParameter=0;
		try{
			if(StringUtils.isNumeric(stringParameter)){
				intParameter=Integer.parseInt(stringParameter);			
			}
		}catch(Exception e){
			logger.error("String转换成int有误", e);
		}
		
		return intParameter;
	}
	
	/**
	 * 获取request中带有默认值的int型数据
	 * @param request
	 * @param parameter
	 * @param defaultValue
	 * @return
	 */	
	public static int getIntParameter(HttpServletRequest request,String parameter,int defaultValue){		
		String stringParameter = request.getParameter(parameter).trim();
		int intParameter=defaultValue;
		try{
			if(StringUtils.isNumeric(stringParameter)){
				intParameter=Integer.parseInt(stringParameter);			
			}
		}catch(Exception e){
			logger.error("String转换成int有误", e);
		}
		
		return intParameter;
	}
	
	/**
	 * 获取Date型的数据
	 * @param request
	 * @param parameter
	 * @param format
	 * @return
	 */
	public static Date getDateParameter(HttpServletRequest request,String parameter,String format){
		Date date=new Date();
		String stringParameter=request.getParameter(parameter).trim();
		DateFormat df=new SimpleDateFormat(format);
		try {
			date=df.parse(stringParameter);
		} catch (ParseException e) {
			logger.error("日期转换有误",e);
		}
		return date;
	}
	
	/**
	 * 字符串的编码转换
	 * @param parameter
	 * @return
	 */
	public static String codingConvert(String parameter){
		String param="";
		try {
			param = new String(parameter.getBytes("ISO-8859-1"),"UTF8");
		} catch (UnsupportedEncodingException e) {
			logger.error("字符编码转换有误",e);
		}
		return param;
	}
	
	public static String getUTF(HttpServletRequest request,String parameter) throws UnsupportedEncodingException{
       	String param = request.getParameter(parameter);
       	if ( param == null ) return null;       	
       	param = new String(param.getBytes("ISO-8859-1"),"UTF-8");       
       	return param;
	}
	public static String getGB(HttpServletRequest request,String parameter) throws UnsupportedEncodingException{
       	parameter = request.getParameter(parameter);
       	if ( parameter == null ) return null;       	
       	parameter = new String(parameter.getBytes("ISO-8859-1"),"GBK"); 
       	
       	return parameter;
	}
	
	
}

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/206352#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 20 Jun 2008 16:21:30 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/206352</link>
        <guid>http://canofy.javaeye.com/blog/206352</guid>
      </item>
      <item>
        <title>分页的类</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/206349" style="color:red;">http://canofy.javaeye.com/blog/206349</a>&nbsp;
          发表时间: 2008年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          pageBean:<br /><pre name="code" class="java">
package cn.yicha.advertiser.model;

/**
 * yicha Jun 28, 2008 分页使用
 */

public class Pagination {
	private int start; // 当前页是从哪条记录开始的
	private int end; // 当前页是从哪条记录结束的
	private int currentPage;// 当前页
	private int pageSize;// 每页显示多少条数据
	private int totalSize;// 总的记录数
	private int totalPage; // 共有多少页

	public int getStart() {
		return start;
	}

	public void setStart(int start) {
		this.start = start;
	}

	public int getEnd() {
		return end;
	}

	public void setEnd(int end) {
		this.end = end;
	}

	public int getCurrentPage() {
		return currentPage;
	}

	public void setCurrentPage(int currentPage) {
		this.currentPage = currentPage;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getTotalSize() {
		return totalSize;
	}

	public void setTotalSize(int totalSize) {
		this.totalSize = totalSize;
	}

	public int getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

}
</pre><br />数据库连接：<br /><pre name="code" class="java">
package cn.yicha.advertiser.dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.apache.log4j.Logger;

/**
 * yicha 
 * Jun 28, 2008 
 */

public class ConnDB {
	
	private Logger logger=Logger.getLogger(ConnDB.class);
	private Connection conn=null;
	private Statement stmt=null;
	private ResultSet rs=null;
	
	/**
	 * 获取数据库连接
	 * @return
	 */
	public Connection getConn(){
		try {
			Class.forName("org.logicalcobwebs.proxool.ProxoolDriver");
			conn=DriverManager.getConnection("proxool.link");
		} catch (ClassNotFoundException e) {
			logger.error("getConn()", e);
		} catch (SQLException e) {
			logger.error("getConn()获取数据库连接池时出错!", e);
		}
		return conn;
	}
	
	/**
	 * 执行查询语句sql
	 * @param sql
	 * @return
	 */
	public ResultSet getResultSet(String sql){
		try {
			if(conn==null||conn.isClosed()) conn=this.getConn();
			stmt=conn.createStatement();
			rs=stmt.executeQuery(sql);
		} catch (SQLException e) {
			logger.error("执行查询语句"+sql+"出错:",e);
		}
		return rs;
	}
	
	/**
	 * 更新sql语句
	 * @param sql
	 * @return  整数，更新的条数
	 */
	public int excuteUpdate(String sql){
		int result=0;
		try {
			if(conn==null||conn.isClosed()) conn=this.getConn();
			result=conn.createStatement().executeUpdate(sql);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * 关闭连接
	 */
	public void closeConn(){
		try{
			if(rs!=null){
				rs.close();
				rs=null;
			}
			if(stmt!=null){
				stmt.close();
				stmt=null;
			}
			if(conn!=null){
				conn.close();
				conn=null;
			}
		}catch (SQLException e) {
			logger.error("关闭数据库连接出错", e);
		}
		
	}
}
</pre><br />分页：<br /><pre name="code" class="java">
package cn.yicha.advertiser.util;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.log4j.Logger;

import cn.yicha.advertiser.dao.ConnDB;
import cn.yicha.advertiser.model.Pagination;

/**
 * yicha 
 * Jun 28, 2008 
 */

public class PageUtil {
	
	private static Logger logger=Logger.getLogger(PageUtil.class);
	
	/**
	 * 获取分页的所有信息
	 * @param countSql
	 * @param pagination 只含有currentPage和pageSize
	 * @return 返回的pagination含有start、end、pageSize、totalSize、totalPage、currentPage
	 */
	public static Pagination getPage(String countSql,Pagination pagination){		
		//SELECT * --分页 sqlserver2005特有，与oracle类似
		//FROM (select *,ROW_NUMBER() Over(order by id) as rowNum from t_basicAdData ) as myTable
		//where rowNum between 10000 and 10200
		
		int totalSize=getTotalSize(countSql); //总的记录条数
		int start = 0;   //当前页是从哪条记录开始的
		int end = 0;     //当前页是从哪条记录结束的
		int totalPage = 0;//总的页数
		int currentPage=pagination.getCurrentPage(); //当前页
		int pageSize=pagination.getPageSize(); //每页的条数		
		
		totalPage=(int)Math.ceil((double)totalSize/pageSize);
		//如果当前小于1,则显示第一页
		if(currentPage&lt;1)         currentPage=1;	
		//如果当前页大于总页数,则显示最后一页
		if(currentPage>totalPage) currentPage=totalPage;
		if(end>totalSize) end = totalSize;		
		//得到开始和结束记录号		
		start = pageSize*(currentPage-1)+1;  //sqlserver2005中是从第一条数据开始
	 	end = start + pageSize; 
	 	//设置返回的bean
	 	pagination.setEnd(end);
	 	pagination.setStart(start);
	 	pagination.setTotalPage(totalPage);
	 	pagination.setTotalSize(totalSize);
		return pagination;
	}
	
	/**
	 * 获取总的记录条数
	 * @param countSql  sql语句
	 * @return
	 */
	public static int getTotalSize(String countSql){
		int totalSize=0;
		ConnDB connDB=new ConnDB();
		ResultSet rs=connDB.getResultSet(countSql);
		try {
			if(rs!=null&&rs.next()){
				totalSize=rs.getInt(1);
			}
		} catch (SQLException e) {
			logger.error("getTotalSize()",e);
		}
		return totalSize;
	}
}

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/206349#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 20 Jun 2008 16:18:34 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/206349</link>
        <guid>http://canofy.javaeye.com/blog/206349</guid>
      </item>
      <item>
        <title>Excell操作</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/206348" style="color:red;">http://canofy.javaeye.com/blog/206348</a>&nbsp;
          发表时间: 2008年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          excel文件生成代码：<br /><pre name="code" class="java">
package cn.excel;

import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFHeader;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * yicha 
 * Jun 17, 2008 
 */

public class CreateXLS {
	 
    HSSFRow row = null;
    HSSFCell cell=null;
	
	/**
	 * 创建新的excel和新的sheet
	 * @return
	 */
	public HSSFSheet getSheet(){
		// 创建新的Excel工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet();//创建默认的sheet
        return sheet;
	}
	
	/**
	 * 创建表头
	 * @param tableHeader
	 */
	public void createTableHeader(HSSFSheet sheet,String[] tableHeader){
//		HSSFSheet sheet=this.getSheet();
		HSSFHeader header=sheet.getHeader();
		header.setCenter("世界五百强企业名次表");
		row=sheet.createRow(0);
		for(int i=0;i&lt;tableHeader.length;i++){
			cell=row.createCell((short)i);
			cell.setCellValue(tableHeader[i]);
		}
	}
	
	/**
	 * 创建行 
	 * @param outputFile
	 * @param tableHeaderk
	 * @param list
	 */
	public void createTableRow(HSSFSheet sheet,String[] tableHeader,List list){
		
//		HSSFSheet sheet=this.getSheet();
		 for(int i=1;i&lt;list.size()+1;i++){//创建行
         	row=sheet.createRow((short)i);             	
         	for(int j=0;j&lt;tableHeader.length;j++){//创建列
                 cell = row.createCell((short) j);
                 // 定义单元格为字符串类型
                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                 // 在单元格中输入一些内容
                 cell.setCellValue(list.get(i-1).toString());
                  // 应用格式                 
                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                 //cell.setCellValue("标题");
              } 
         }		
	}
	
	/**
	 * 创建指定某行的数据
	 * @param sheet
	 * @param tableHeader
	 * @param list  存放的是具体的数据，string类型或者为基本数据类型
	 * @param rowIndex
	 */
	public void createTalbeRow2(HSSFSheet sheet,List list,int rowIndex){		
         	row=sheet.createRow((short)rowIndex);             	
         	for(int i=0;i&lt;list.size();i++){//创建列
                 cell = row.createCell((short) i);
                 // 定义单元格为字符串类型
                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                 // 在单元格中输入一些内容
                 cell.setCellValue(list.get(i).toString());
                  // 应用格式                 
                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                 //cell.setCellValue("标题");
              }         
	}
	
	/**
	 * 导出到excel表中
	 * @param outputFile
	 * @param workbook
	 */
	public void exportExcel(String outputFile,String[] tableHeader,List list){
		// 创建新的Excel工作薄
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet();//创建默认的sheet
        this.createTableHeader(sheet, tableHeader);
        this.createTableRow(sheet, tableHeader, list);
        
//        for(int i=0;i&lt;list.size();i++){
//        	this.createTalbeRow2(sheet, list, i+1);
//        }
        System.out.println("文件正在生成......");
		try{
			 // 新建输出文件流
	        FileOutputStream fOut = new FileOutputStream(outputFile);
	        // 把相应的Excel工作薄存盘
	        workbook.write(fOut);
	        fOut.flush();
	        // 操作结束，关闭文件
	        fOut.close();
	        
	    } catch (Exception e) {
	        System.out.println("已运行CreateXLS();" + e);
	    }
	    System.out.println("文件已生成......");
	}

    /**
     *  写入到excel中
     * @param outputFile	输出保存的文件名，包括路径
     * @param tableHeaderk   每一列的名称，即第一行
     * @param list	 每行的数据
     */
    public void writeToExcel(String outputFile,String[] tableHeaderk,List list){
        try {
            // 创建新的Excel工作薄
            HSSFWorkbook workbook = new HSSFWorkbook();

            // 在Excel工作薄中建一工作表，其名为缺省值
            // 如要新建一名为“效益指标”的工作表，其语句为：
//            HSSFSheet sheet = workbook.createSheet("效益指标");//用来创建指定的sheet
            HSSFSheet sheet = workbook.createSheet();//创建默认的sheet
            HSSFHeader header=sheet.getHeader();
            header.setCenter("世界五百强企业名次表");
            // 在索引0的位置创建行（最顶端的行）
            HSSFRow row = null;
            // 在索引0的位置创建单元格（左上端）
            HSSFCell cell=null;
            
            // 创建字体，设置其为红色、粗体
            HSSFFont font = workbook.createFont();
            font.setColor(HSSFFont.COLOR_RED);
            font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
            // 创建格式
            HSSFCellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setFont(font);
            //创建的第一行，标题
            row=sheet.createRow((short)0); 
            for(int i=0;i&lt;tableHeaderk.length;i++){//创建列
            	cell = row.createCell((short) i);
                // 定义单元格为字符串类型
                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                // 在单元格中输入一些内容
                cell.setCellValue(tableHeaderk[i]);
                // 应用格式
                cell.setCellStyle(cellStyle);
                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                //cell.setCellValue("标题");
            }
            for(int j=1;j&lt;list.size()+1;j++){//创建行
            	row=sheet.createRow((short)j);             	
            	for(int i=0;i&lt;tableHeaderk.length;i++){//创建列
                    cell = row.createCell((short) i);
                    // 定义单元格为字符串类型
                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                    // 在单元格中输入一些内容
                    cell.setCellValue(list.get(j-1).toString());
                     // 应用格式
                    cell.setCellStyle(cellStyle);
                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                    //cell.setCellValue("标题");
                 }
            	
            	
            } 
            // 新建输出文件流
            FileOutputStream fOut = new FileOutputStream(outputFile);
            // 把相应的Excel工作薄存盘
            workbook.write(fOut);
            fOut.flush();
            // 操作结束，关闭文件
            fOut.close();
            System.out.println("文件生成......");
        } catch (Exception e) {
            System.out.println("已运行CreateXLS();" + e);
        }
    }
    
    public static void main(String[] args) {
    	String[] tableHeader={ "企业中文名","所属国家"};
    	String outputFile = "c:/test.xls";
    	List list=new ArrayList();
    	list.add("one");
    	list.add("two");
    	list.add("three");
    	CreateXLS create=new CreateXLS();
//    	create.writeToExcel(outputFile,tableHeader,list);
    	create.exportExcel(outputFile, tableHeader, list);
    }
}

</pre><br />读取excel代码<br /><pre name="code" class="java">
package cn.excel;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

/**
 * yicha 
 * Jun 17, 2008 
 */

public class ReadinXLS {
	/**
	 * 读取xls数据
	 * @return
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
    public String getData(String fileToBeRead) throws FileNotFoundException, IOException{
    	/** Excel文件存放位置。注意是正斜线 */
//        String fileToBeRead = "c:/test.xls";
    	// 创建对Excel工作薄文件的引用
        HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(fileToBeRead));
        // 创建对工作表的引用
        // 本例是按名引用，（让我们假定那张表有着缺省名"Sheet1"）
//        HSSFSheet sheet = workbook.getSheet("效益指标");
//        HSSFSheet sheet=workbook.getSheetAt(0);
        // 也可用getSheetAt(int index)按索引引用
        // 在Excel文档中，第一张工作表的缺省索引是0
        // 其语句为：HSSFSheet sheet=workbook.getSheetAt(0);
        int currSheet=0;// 在Excel文档中，第一张工作表的缺省索引是0
      return this.readLine(workbook, currSheet);
    }
    
    /**
     * 获取一个excel的数据
     * @param workbook
     * @param currSheet
     * @return
     */
    public String readLine(HSSFWorkbook workbook,int currSheet){ 
    	StringBuffer result=new StringBuffer();
    	String EXCEL_LINE_DELIMITER=";";
		// 根据currSheet值获得当前的sheet  
    	HSSFSheet sheet = workbook.getSheetAt(currSheet);
//    	HSSFCell cell=null;
//    	HSSFRow rowline = null;
    	int rowCount=sheet.getLastRowNum()+1;//获取行数,是从零开始计算的，因此要+1    	
    	for(int i=0;i&lt;rowCount;i++){
    		result.append(this.getLine(sheet, i)).append(EXCEL_LINE_DELIMITER);    		
    	}  
//    	System.out.println(rowCount);
    	return result.toString();
    }
    
    /**
     * 获取某一行的数据
     * @param sheet
     * @param row  某一行
     * @return
     */
    public String  getLine(HSSFSheet sheet,int row){
    	String EXCEL_LINE_DELIMITER=",";
    	StringBuffer result = new StringBuffer();
    	// 根据行数取得Sheet的一行       
    	HSSFRow rowline = sheet.getRow(row);//某行  
    	HSSFCell cell=null;
    	int cellCount=rowline.getLastCellNum()+1;//获取某行的列数,是从零开始计算的，因此要+1
    	for(int i=0;i&lt;cellCount;i++){
    		cell=rowline.getCell((short)i);
//    		System.out.println(cell.getStringCellValue());
    		result.append(cell.getStringCellValue()).append(EXCEL_LINE_DELIMITER);
    	}    	
    	return result.toString();
    }

    public static void main(String[] args) throws FileNotFoundException, IOException {
    	ReadinXLS read=new ReadinXLS();
    	/** Excel文件存放位置。注意是正斜线 */
        String fileToBeRead = "c:/test.xls";
    	System.out.println(read.getData(fileToBeRead));
    }

}

</pre>
          <br/>
          <span style="color:red;">
            <a href="http://canofy.javaeye.com/blog/206348#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Fri, 20 Jun 2008 16:14:55 +0800</pubDate>
        <link>http://canofy.javaeye.com/blog/206348</link>
        <guid>http://canofy.javaeye.com/blog/206348</guid>
      </item>
      <item>
        <title>一个时间类</title>
        <author>canofy</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://canofy.javaeye.com">canofy</a>&nbsp;
          链接：<a href="http://canofy.javaeye.com/blog/206341" style="color:red;">http://canofy.javaeye.com/blog/206341</a>&nbsp;
          发表时间: 2008年06月20日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <pre name="code" class="java">

	/**
	 * 从字符串类型获取日期Date
	 * @param dateStr  日期字符串，如：20080321
	 * @param format  格式化模式，如yyyymmdd 和dateStr保持一致的格式
	 * @return 返回一个Date类型日期
	 * @throws Exception
	 */
	public static Date getDateFromString(String dateStr, String format) {

		if (dateStr == null || format == null) {
			try {
				throw new Exception("数据类型异常" + dateStr + "|" + format);
			} catch (Exception e) {
				System.err.println("数据类型异常");
			}
		}

		SimpleDateFormat df = new SimpleDateFormat(format);
		Date date;
		try {
			date = df.parse(dateStr);
			return date;
		} catch (Exception ex) {
			return new Date();
		}
	}

	/**
	 * Calendar类型转换成Date类型日期
	 * 
	 * @param calendar
	 * @return
	 */
	public static Date getDateFromCalendar(Calendar calendar) {
		return calendar.getTime();
	}

	/**
	 * Timestamp类型转换成Date类型日期
	 * 
	 * @param timestamp
	 * @param format
	 * @return
	 */
	public static Date getDateFromTimestamp(Timestamp timestamp, String format) {
		return getDateFromString(timestamp.toString(), format);
	}

	/**
	 * String类型转换成Timestamp类型日期
	 * 
	 * @param dateStr
	 *            日期字符串
	 * @return
	 * @throws Exception
	 */
	public static Timestamp getTimestampFromString(String dateStr)
			throws Exception {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00.000");
		return Timestamp.valueOf(sdf.format(getDateFromString(dateStr,
				"yyyyMMdd")));
	}

	/**
	 * Calendar类型转换Timestamp类型的日期
	 * 
	 * @param calendar
	 *            参数是Calendar类型
	 * @return
	 */
	public static Timestamp getTimestampFromCalendar(Calendar calendar) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00.000");
		return Timestamp.valueOf(sdf.format(calendar.getTime()));
	}

	/**
	 * Date类型转换Timestamp类型的日期
	 * 
	 * @param date
	 * @return
	 */
	public static Timestamp getTimestampFromDate(Date date) {
		try {
			return getTimestampFromString(getStringFromDate(date, "yyyy-MM-dd"));
		} catch (Exception e) {
			// System.out.println("获取日期出错");
			return null;
		}
	}

	/**
	 * String(字符串类型)转换成Calendar类型的日期
	 * 
	 * @param dateStr
	 * @return
	 */
	public static Calendar getCalendarFromString(String dateStr) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(getDateFromString(dateStr, "yyyymmdd"));
		return calendar;
	}

	/**
	 * Date类型转换成Calendar类型日期
	 * 
	 * @param date
	 * @return
	 */
	public static Calendar getCalendarFromDate(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar;
	}

	/**
	 * Timestamp类型转换成Calendar类型日期
	 * 
	 * @param timestamp
	 * @return
	 */
	public static Calendar getCalendarFromTimestamp(Timestamp timestamp) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(getDateFromTimestamp(timestamp, "yyyymmdd"));
		return calendar;
	}

	/**
	 * Date类型转换成String(字符串)类型的日期
	 * 
	 * @param date
	 * @return
	 */
	public static String getStringFromDate(Date date, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(date);
	}

	/**
	 * Calendar类型转换成String类型的日期
	 * 
	 * @param celendar
	 * @return
	 */
	public static String getStringFromCalendar(Calendar celendar, String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		return sdf.format(celendar.getTime());
	}

	/**
	 * Timestamp类型转换成String类型的日期
	 * 
	 * @param timestamp
	 * @return
	 */
	public static String getStringFromTimestamp(Timestamp timestamp) {
		return timestamp.toString();
	}

	/**
	 * 格式化format
	 * 
	 * @param dateStr
	 * @param format
	 * @return
	 */
	public static String getStringFormat(String dateStr, String format) {

		SimpleDateFormat sdf = new SimpleDateFormat(format);
		String result = "";

		try {
			result = sdf.format(dateStr);
		} catch (Exception e) {
			System.out.println("出现错误");
		}

		return result;

	}

	/**
	 * 是否为某个月的最后一天
	 * 
	 * @param days
	 * @param month
	 * @param year
	 * @return
	 */
	public static boolean isLastDayOfMonth(int days, int month, int year) {
		month = month - 1;
		int monthCompare = month;
		Calendar calendar = Calendar.getInstance();
		// calendar.set(year, month, days);
		calendar.set(Calendar.DAY_OF_MONTH, days);
		calendar.set(Calendar.MONTH, month);
		calendar.set(Calendar.YEAR, year);
		// System.out.println("月份："+(calendar.get(Calendar.MONTH)+1));
		// System.out.println("几号："+calendar.get(Calendar.DAY_OF_MONTH));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		// System.out.println("月份："+(calendar.get(Calendar.MONTH)+1));
		// System.out.println("几号："+calendar.get(Calendar.DAY_OF_MONTH));
		if (monthCompare != calendar.getInstance().MONTH) {
			return true;
		}
		return false;
	}

	//	
	// /**
	// * @param args
	// * @throws ParseException
	// */
	// public static void main(String[] args) throws ParseException {
	// DateTool dateTool=new DateTool();
	// //测试是否为最后一天。。。
	// boolean b=dateTool.isLastDayOfMonth(29, 02, 2007);
	// if(b){s
	// System.out.println("最后一天");
	// }else{
	// System.out.println("不是最后一天");
	// }
	// Date date=new Date();
	// SimpleDateFormat sdf=new SimpleDateFormat("yyyy-mm-dd");
	// sdf.format(date);
	//		
	// Date date1=new Date();
	//		
	// Date date2=new Date();
	//		
	// System.out.println(getTimestampFromDate(date1).toString());
	// }

	/**
	 * 获取当前的月份的几号
	 * 
	 * @return
	 */
	public static int getCurrentDayOfMonth() {
		return Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 获取当前的月份
	 * 
	 * @return
	 */
	public static int getCurrentMonth() {
		return Calendar.getInstance().get(Calendar.MONTH);
	}

	/**
	 * 获取当前的年
	 * 
	 * @return
	 */
	public static int getCurrentYear() {
		return Calendar.getInstance().get(Calendar.YEAR);
	}

	/**
	 * 获取当前的日期是一年中的第几天
	 * 
	 * @return
	 */
	public static int getCurrentDayOfYear() {
		return Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * 获取当前的日期在当前月中是第几周
	 * 
	 * @return
	 */
	public static int getCurrentWeekOfMonth() {
		return Calendar.getInstance().get(Calendar.WEEK_OF_MONTH);
	}

	/**
	 * 获取当前的日期在当前年里的第几周
	 * 
	 * @return
	 */
	public static int getCurrentWeekOfYear() {
		return Calendar.getInstance().get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 获取指定calendar的月中的几号
	 * 
	 * @param calendar
	 * @return 返回月份值，是一个int型数据
	 */
	public static int getDayOfMonth(Calendar calendar) {
		return calendar.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * 获取指定calendar的月份
	 * 
	 * @param calendar
	 * @return 返回月份值，是一个int型数据
	 */
	public static int getMonth(Calendar calendar) {
		return calendar.get(Calendar.MONTH) + 1;
	}

	/**
	 * 获取指定calendar的年
	 * 
	 * @param calendar
	 * @return 返回年值，是一个int型数据
	 */
	public static int getYear(Calendar calendar) {
		return calendar.get(Calendar.YEAR);
	}

	/**
	 * 获取指定calendar中年份中的第几天
	 * 
	 * @param calendar
	 * @return
	 */
	public static int getDayOfYear(Calendar calendar) {
		return calendar.get(Calendar.DAY_OF_YEAR);
	}

	/**
	 * 获取指定calendar的月中的第几周
	 * 
	 * @param calendar
	 * @return
	 */
	public static int getWeekOfMonth(Calendar calendar) {
		return calendar.get(Calendar.WEEK_OF_MONTH);
	}

	/**
	 * 获取指定calendar的年中的第几周
	 * 
	 * @param calendar
	 * @return
	 */
	public static int getWeekOfYear(Calendar calendar) {
		return calendar.get(Calendar.WEEK_OF_YEAR);
	}

	/**
	 * 得到两个日期之间相差多少天 
	 * @param beginDate  开始日期
	 * @param endDate    结束日期
	 * @return
	 */
	public static int dateDiff(String beginDate,String endDate){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date date = null;
		try {
			date = sdf.parse(endDate);
		} catch (ParseException e) {
			date = new Date();
			e.printStackTrace();
		}
		
		
		long end 	= date.getTime();
		try {
			date = sdf.parse(beginDate);
		} catch (ParseException e) {
			date = new Date();
			e.printStackTrace();
		}
		long  begin 	= date.getTime();
		
		long day = (end-begin)/(1000*3600*24);		//除1000是把毫秒变成秒
		
		return Integer.parseInt(Long.toString(day));		
	}

	/**
	 * 日期推迟
	 * 
	 * @param date
	 *            需要推迟的日期
	 * @param dayNumber
	 *            需要推迟的天数
	 * @return 返回新的日期
	 */
	public static Date dateAdd(Date date, int dayNumber) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar.add(Calendar.DAY_OF_MONTH, dayNumber);
		return calendar.getTime();
	}
/**
	 * 得到某种类型的中间的所有日期.格式为"yyyy-MM-dd"	
	 * @param beginDate
	 * @param endDate
	 * @return
	 */
	public static String[] getDaysByRang(String beginDate,String endDate){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		
		//得到两个日期间相差多少天
		int num = dateDiff(beginDate,endDate);
		if(num&lt;0){
			//颠倒一下日期
			String tmp = beginDate;
			beginDate = endDate;
			endDate = tmp;
			num = 0-num;
		}
		
		String[] result = {} ;
		Calendar cal = Calendar.getInstance() ;
		try {
			cal.setTime(sdf.parse(beginDate));
		} catch (ParseException e) {
			e.printStackTrace();
		}
		
		num = num + 1;	//把开始和结束日期都包含进去
		
		result = new String[num];
		for(int i=0;i&lt;num;i++){
			if(i>0)	cal.add(Calendar.DAY_OF_YEAR, 1);
			result[i] = sdf.format(new Date(cal.getTimeInMillis()));
		}
		
		return result;
	}
	
	/**
	 * 得到最近num天的全部日期
	 * 说明:	
	 * 	1.日期是从昨天开始算的.
	 *  2.如果num=2 , 今天的日期是2008-03-14 ,则返回的结果为 2008-03-12、2008-03-13
	 * @param num
	 * @return
	 */
	public static String[] getDaysByNum(int num){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String[] result = {} ;
		Calendar cal = Calendar.getInstance() ;
		
		//最近一周
		result = new String[num];
		for(int i=num;i>0;i--){
			cal.add(Calendar.DAY_OF_YEAR, -1);
			result[i-1] = sdf.format(new Date(cal.getTimeInMillis()));
		}
		
		return result;
	}
	
	
	
	/**
	 * 得到最近num天的全部日期
	 * 说明:	
	 * 	1.日期是从昨天开始算的.
	 *  2.如果num=2 , 今天的日期是2008-03-14 ,则返回的结果为 2008-03-12、2008-03-13
	 * @param num
	 * @return
	 */
	public static String[] getDaysByNum(int num,String date){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String[] result = {} ;
		Calendar cal = Calendar.getInstance() ;
		cal.setTime(getDateFromString(date, "yyy