1、源代码包的安装
gzip -d apache_1.3.20.tar.gz (解压)
tar xvf apache_1.3.20.tar (解包)
cd apache_1.3.20
./configure (配置) ----./configure --help(查看configure选项)
make (编译)
make install (安装)
make clean (卸载)
注:典型的源代码包可以这样安装,但不都是这样,如webmin
要执行其目录下./setup.sh进入交互式配置安装
卸载用uninstall程序
具体如果不清楚看要安装的包下的README文件
2、RPM包的安装
RPM软件包的一个例子:
foo-1.0-1.i386.rpm
其中包括软件包的名称(foo),版本号(1.0),发行号(1),和硬件平台(i386)。
(1)安装
# rpm -ivh foo-1.0-1.i386.rpm
foo
#######################
A. 软件包已被安装
# rpm -ivh foo-1.0-1.i386.rpm
foo package foo-1.0-1 is already installed
error: foo-1.0-1.i386.rpm cannot be installed
如果你仍旧要安装该软件包,你可以在命令行上使用--replacepkgs 选项,这将忽略该错误信息。
B. 文件冲突
如果要安装的软件包中有一个文件已在安装其它软件包时安装,会出现以下错误信息:
# rpm -ivh foo-1.0-1.i386.rpm
foo /usr/bin/foo conflicts with file from bar-1.0-1
error: foo-1.0-1.i386.rpm cannot be installed
要想让RPM 忽略该错误信息, 请使用--replacefiles 命令行选项
C.未解决依赖关系
RPM软件包可能依赖于其它软件包, 在安装了特定的软件包之后才能安装该软件包。
# rpm -ivh bar-1.0-1.i386.rpm
failed dependencies:
foo is needed by bar-1.0-1
你必须安装完所依赖的软件包,才能解决这个问题。如果想强制安装 (但是,这样安装后的软件包未必能正常运行),请使用-nodeps 命令行选项。
(2) 卸载
# rpm -e foo
注意:这里使用软件包的名字foo,而不是软件包文件的名字“foo-1.0-1.i386.rpm”.
如果其它软件包依赖于你要卸载的软件包,卸载时则会产生错误信息。如:
# rpm -e foo
removing these packages would break dependencies:
foo is needed by bar-1.0-1
要想RPM忽略该错误信息继续卸载的话 (但是,依赖于该软件包的程序可能无法运行), 请使用-nodeps 命令行选项。
(3)升级
# rpm -Uvh foo-2.0-1.i386.rpm
foo
###############################
当使用旧版本的软件包来升级新版本的软件时,会产生以下错误信息:
# rpm -Uvh foo-1.0-1.i386.rpm
foo package foo-2.0-1 (which is newer) is already installed
error: foo-1.0-1.i386.rpm cannot be installed
要使RPM 坚持这样“升级”,可使用--oldpackage 命令行参数。
(4)查询
# rpm -q foo
foo-2.0-1
软件包指定选项:
-a 查询所有已安装的软件包.
-f <file> 将查询包含有文件<file>的软件包
-p <packagefile>
查询软件包文件名为<packagefile>的软件包
信息选择选项:
-i 显示软件包信息,如描述, 发行号, 尺寸, 构建日期, 安装日期, 平台, 以及其它各类信息。
-l 显示软件包中的文件列表。
-s 显示软件包中所有文件的状态。
-d 显示被标注为文档的文件列表(man 手册, info 手册, README's, etc).
-c 显示被标注为配置文件的文件列表。这些是要在安装完毕以后加以定制的文件(sendmail.cf, passwd, inittab, etc)。
对于那些要显示文件列表的文件,可以增加-v 命令行选项以获得如同 ls -l 格式的输出。
(5)验证
验证软件包是通过比较软件包中安装的文件和软件包中的原始文件信息来进行的。除了其它一些东西,验证主要是比较文件的尺寸, MD5 校验码, 文件权限, 类型, 属主和用户组等。
rpm -V命令用来验证一个软件包,如
rpm -V foo
验证包含特定文件的软件包:
rpm -Vf /bin/vi
验证所有已安装的软件包:
rpm -Va
根据一个RPM来验证某个软件包:
rpm -Vp foo-1.0-1.i386.rpm
如果你担心RPM数据库已被破坏,就可以使用这种方式。如果一切校验均正常将不会产生任何输出。如果有不一致的地方,就会显示出来。
输出格式是8位长字符串,c 用以指配置文件,接着是文件名. 8位字符的每一个用以表示文件与RPM数据库中一种属性的比较结果。“.” (点)表示测试通过。
以下字符表示某种测试的失败:
5 MD5 校验码
S 文件尺寸
L 符号连接
T 文件修改日期
D 设备
U 用户
G 用户组
M 模式e (包括权限和文件类型)
如果有信息输出,应当认真加以考虑,是删除,重新安装,还是修正出现的问题。
(6)RPM应用的几个例子
A. 如你误删了一些文件, 但是不能肯定到底删除了哪些文件。如果你想验证一下整个系统看看都丢失了哪些文件的话,可以键入:
rpm –Va
B.若是一些文件丢失了或已被损坏, 就可以重新安装或先卸载再安装该软件包。如果碰到了一个自己不认识的文件,要想查处它属于哪个软件包,可以输入以下命令:
rpm -qf /usr/X11R6/bin/xjewel
而输出的结果会是:
xjewel-1.6-1
C. 如果发生综合以上两个例子的情况,如文/usr/bin/paste出了问题。你想验证一下拥有该文件的软件包,可又不知道软件包的名字,这时可以简单的键入:
rpm -Vf /usr/bin/paste
这样相应的软件包就会被验证。
D. 如果你想了解一个正在使用的程序的详细信息,可以键入如下命令来获得拥有该程序的软件包中的文档信息:
rpm -qdf /usr/bin/ispell
输出结果为:
/usr/man/man4/ispell.4
/usr/man/man4/english.4
…………………………………………………………
E. 如果你发现了一个新的koules RPM,但是不知道它是什么东西,可以键入如下命令:
rpm -qip koules-1.2-2.i386.rpm
F. 现在你想了解koules RPM 所安装的文件。可以键入:
rpm -qlp koules-1.2-2.i386.rpm
图形管理工具:kpackage
3、shell或java脚本安装
基于图形界面的安装,一般基于SHELL或Java语言编写,主要应用于一些办公软件和制图软件及安装程序,如staroffice、oracle的安装,很容易,和windows一样
LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE]
INTO TABLE tbl_name
[FIELDS
[TERMINATED BY '\t']
[OPTIONALLY] ENCLOSED BY '']
[ESCAPED BY '\\' ]]
[LINES TERMINATED BY '\n']
[IGNORE number LINES]
[(col_name,...)]
LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。如果指定LOCAL关键词,从客户主机读文件。如果LOCAL没指定,文件必须位于服务器上。(LOCAL在MySQL3.22.6或以后版本中可用。)
为了安全原因,当读取位于服务器上的文本文件时,文件必须处于数据库目录或可被所有人读取。另外,为了对服务器上文件使用LOAD DATA INFILE,在服务器主机上你必须有file的权限。见6.5 由MySQL提供的权限。
如果你指定关键词LOW_PRIORITY,LOAD DATA语句的执行被推迟到没有其他客户读取表后。
使用LOCAL将比让服务器直接存取文件慢些,因为文件的内容必须从客户主机传送到服务器主机。在另一方面,你不需要file权限装载本地文件。
你也可以使用mysqlimport实用程序装载数据文件;它由发送一个LOAD DATA INFILE命令到服务器来运作。 --local选项使得mysqlimport从客户主机上读取数据。如果客户和服务器支持压缩协议,你能指定--compress在较慢的网络上获得更好的性能。
当在服务器主机上寻找文件时,服务器使用下列规则:
如果给出一个绝对路径名,服务器使用该路径名。
如果给出一个有一个或多个前置部件的相对路径名,服务器相对服务器的数据目录搜索文件。
如果给出一个没有前置部件的一个文件名,服务器在当前数据库的数据库目录寻找文件。
注意这些规则意味着一个像“./myfile.txt”给出的文件是从服务器的数据目录读取,而作为“myfile.txt”给出的一个文件是从当前数据库的数据库目录下读取。也要注意,对于下列哪些语句,对db1文件从数据库目录读取,而不是db2:
mysql> USE db1;
mysql> LOAD DATA INFILE "./data.txt" INTO TABLE db2.my_table;
REPLACE和IGNORE关键词控制对现有的唯一键记录的重复的处理。如果你指定REPLACE,新行将代替有相同的唯一键值的现有行。如果你指定IGNORE,跳过有唯一键的现有行的重复行的输入。如果你不指定任何一个选项,当找到重复键键时,出现一个错误,并且文本文件的余下部分被忽略时。
如果你使用LOCAL关键词从一个本地文件装载数据,服务器没有办法在操作的当中停止文件的传输,因此缺省的行为好像IGNORE被指定一样。
LOAD DATA INFILE是SELECT ... INTO OUTFILE的逆操作,
SELECT句法。为了将一个数据库的数据写入一个文件,使用SELECT ... INTO OUTFILE,为了将文件读回数据库,使用LOAD DATA INFILE。两个命令的FIELDS和LINES子句的语法是相同的。两个子句是可选的,但是如果指定两个,FIELDS必须在LINES之前。
如果你指定一个FIELDS子句,它的每一个子句(TERMINATED BY, [OPTIONALLY] ENCLOSED BY和ESCAPED BY)也是可选的,除了你必须至少指定他们之一。
如果你不指定一个FIELDS子句,缺省值与如果你这样写的相同:
FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'
如果你不指定一个LINES子句,缺省值与如果你这样写的相同:
LINES TERMINATED BY '\n'
换句话说,缺省值导致读取输入时,LOAD DATA INFILE表现如下:
在换行符处寻找行边界
在定位符处将行分进字段
不要期望字段由任何引号字符封装
将由“\”开头的定位符、换行符或“\”解释是字段值的部分字面字符
相反,缺省值导致在写入输出时,SELECT ... INTO OUTFILE表现如下:
在字段之间写定位符
不用任何引号字符封装字段
使用“\”转义出现在字段中的定位符、换行符或“\”字符
在行尾处写换行符
注意,为了写入FIELDS ESCAPED BY '\\',对作为一条单个的反斜线被读取的值,你必须指定2条反斜线值。
IGNORE number LINES选项可被用来忽略在文件开始的一个列名字的头:
mysql> LOAD DATA INFILE "/tmp/file_name" into table test IGNORE 1 LINES;
当你与LOAD DATA INFILE一起使用SELECT ... INTO OUTFILE将一个数据库的数据写进一个文件并且随后马上将文件读回数据库时,两个命令的字段和处理选项必须匹配,否则,LOAD DATA INFILE将不能正确解释文件的内容。假定你使用SELECT ... INTO OUTFILE将由逗号分隔的字段写入一个文件:
mysql> SELECT * FROM table1 INTO OUTFILE 'data.txt'
FIELDS TERMINATED BY ','
FROM ...
为了将由逗号分隔的文件读回来,正确的语句将是:
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
FIELDS TERMINATED BY ',';
相反,如果你试图用下面显示的语句读取文件,它不会工作,因为它命令LOAD DATA INFILE在字段之间寻找定位符:
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2
FIELDS TERMINATED BY '\t';
可能的结果是每个输入行将被解释为单个的字段。
LOAD DATA INFILE能被用来读取从外部来源获得的文件。例如,以dBASE格式的文件将有由逗号分隔并用双引号包围的字段。如果文件中的行由换行符终止,下面显示的命令说明你将用来装载文件的字段和行处理选项:
mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
LINES TERMINATED BY '\n';
任何字段或行处理选项可以指定一个空字符串('')。如果不是空,FIELDS [OPTIONALLY] ENCLOSED BY和FIELDS ESCAPED BY值必须是一个单个字符。FIELDS TERMINATED BY和LINES TERMINATED BY值可以是超过一个字符。例如,写入由回车换行符对(CR+LF)终止的行,或读取包含这样行的一个文件,指定一个LINES TERMINATED BY '\r\n'子句。
FIELDS [OPTIONALLY] ENCLOSED BY控制字段的包围字符。对于输出(SELECT ... INTO OUTFILE),如果你省略OPTIONALLY,所有的字段由ENCLOSED BY字符包围。对于这样的输出的一个例子(使用一个逗号作为字段分隔符)显示在下面:
"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"
如果你指定OPTIONALLY,ENCLOSED BY字符仅被用于包围CHAR和VARCHAR字段:
1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20
注意,一个字段值中的ENCLOSED BY字符的出现通过用ESCAPED BY字符作为其前缀来转义。也要注意,如果你指定一个空ESCAPED BY值,可能产生不能被LOAD DATA INFILE正确读出的输出。例如,如果转义字符为空,上面显示的输出显示如下。注意到在第四行的第二个字段包含跟随引号的一个逗号,它(错误地)好象要终止字段:
1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20
对于输入,ENCLOSED BY字符如果存在,它从字段值的尾部被剥去。(不管是否指定OPTIONALLY都是这样;OPTIONALLY对于输入解释不起作用)由ENCLOSED BY字符领先的ESCAPED BY字符出现被解释为当前字段值的一部分。另外,出现在字段中重复的ENCLOSED BY被解释为单个ENCLOSED BY字符,如果字段本身以该字符开始。例如,如果ENCLOSED BY '"'被指定,引号如下处理:
"The ""BIG"" boss" -> The "BIG" boss
The "BIG" boss -> The "BIG" boss
The ""BIG"" boss -> The ""BIG"" boss
FIELDS ESCAPED BY控制如何写入或读出特殊字符。如果FIELDS ESCAPED BY字符不是空的,它被用于前缀在输出上的下列字符:
FIELDS ESCAPED BY字符
FIELDS [OPTIONALLY] ENCLOSED BY字符
FIELDS TERMINATED BY和LINES TERMINATED BY值的第一个字符
ASCII 0(实际上将后续转义字符写成 ASCII'0',而不是一个零值字节)
如果FIELDS ESCAPED BY字符是空的,没有字符被转义。指定一个空转义字符可能不是一个好主意,特别是如果在你数据中的字段值包含刚才给出的表中的任何字符。
对于输入,如果FIELDS ESCAPED BY字符不是空的,该字符的出现被剥去并且后续字符在字面上作为字段值的一个部分。例外是一个转义的“0”或“N”(即,\0或\N,如果转义字符是“\”)。这些序列被解释为ASCII 0(一个零值字节)和NULL。见下面关于NULL处理的规则。
对于更多关于“\”- 转义句法的信息,在某些情况下,字段和行处理选项相互作用:
如果LINES TERMINATED BY是一个空字符串并且FIELDS TERMINATED BY是非空的,行也用FIELDS TERMINATED BY终止。
如果FIELDS TERMINATED BY和FIELDS ENCLOSED BY值都是空的(''),一个固定行(非限定的)格式被使用。用固定行格式,在字段之间不使用分隔符。相反,列值只用列的“显示”宽度被写入和读出。例如,如果列被声明为INT(7),列的值使用7个字符的字段被写入。对于输入,列值通过读取7个字符获得。固定行格式也影响NULL值的处理;见下面。注意如果你正在使用一个多字节字符集,固定长度格式将不工作。
NULL值的处理有多种,取决于你使用的FIELDS和LINES选项:
对于缺省FIELDS和LINES值,对输出,NULL被写成\N,对输入,\N被作为NULL读入(假定ESCAPED BY字符是“\”)。
如果FIELDS ENCLOSED BY不是空的,包含以文字词的NULL作为它的值的字段作为一个NULL值被读入(这不同于包围在FIELDS ENCLOSED BY字符中的字NULL,它作为字符串'NULL'读入)。
如果FIELDS ESCAPED BY是空的,NULL作为字NULL被写入。
用固定行格式(它发生在FIELDS TERMINATED BY和FIELDS ENCLOSED BY都是空的时候),NULL作为一个空字符串被写入。注意,在写入文件时,这导致NULL和空字符串在表中不能区分,因为他们都作为空字符串被写入。如果在读回文件时需要能区分这两者,你应该不使用固定行格式。
一些不被LOAD DATA INFILE支持的情况:
固定长度的行(FIELDS TERMINATED BY和FIELDS ENCLOSED BY都为空)和BLOB或TEXT列。
如果你指定一个分隔符与另一个相同,或是另一个的前缀,LOAD DATA INFILE不能正确地解释输入。例如,下列FIELDS子句将导致问题:
FIELDS TERMINATED BY '"' ENCLOSED BY '"'
如果FIELDS ESCAPED BY是空的,一个包含跟随FIELDS TERMINATED BY值之后的FIELDS ENCLOSED BY或LINES TERMINATED BY的字段值将使得LOAD DATA INFILE过早地终止读取一个字段或行。这是因为LOAD DATA INFILE不能正确地决定字段或行值在哪儿结束。
下列例子装载所有persondata表的行:
mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;
没有指定字段表,所以LOAD DATA INFILE期望输入行对每个表列包含一个字段。使用缺省FIELDS和LINES值。
如果你希望仅仅装载一张表的某些列,指定一个字段表:
mysql> LOAD DATA INFILE 'persondata.txt'
INTO TABLE persondata (col1,col2,...);
如果在输入文件中的字段顺序不同于表中列的顺序,你也必须指定一个字段表。否则,MySQL不能知道如何匹配输入字段和表中的列。
如果一个行有很少的字段,对于不存在输入字段的列被设置为缺省值。
如果字段值缺省,空字段值有不同的解释:
对于字符串类型,列被设置为空字符串。
对于数字类型,列被设置为0。
对于日期和时间类型,列被设置为该类型的适当“零”值。
如果列有一个NULL,或(只对第一个TIMESTAMP列)在指定一个字段表时,如果TIMESTAMP列从字段表省掉,TIMESTAMP列只被设置为当前的日期和时间。
如果输入行有太多的字段,多余的字段被忽略并且警告数字加1。
LOAD DATA INFILE认为所有的输入是字符串,因此你不能像你能用INSERT语句的ENUM或SET列的方式使用数字值。所有的ENUM和SET值必须作为字符串被指定!
如果你正在使用C API,当LOAD DATA INFILE查询完成时,你可通过调用API函数mysql_info()得到有关查询的信息。信息字符串的格式显示在下面:
Records: 1 Deleted: 0 Skipped: 0 Warnings: 0
当值通过INSERT语句插入时,在某些情况下出现警告,除了在输入行中有太少或太多的字段时,LOAD DATA INFILE也产生警告。警告没被存储在任何地方;警告数字仅能用于表明一切是否顺利。如果你得到警告并且想要确切知道你为什么得到他们,一个方法是使用SELECT ... INTO OUTFILE到另外一个文件并且把它与你的原版输入文件比较。
1. 我和超人的唯一区别是:我把内裤穿在里面.
2. 我不是随便的人, 但随便了起来就不是人了.
3. 我身在江湖, 江湖却没有我的传说.
4. 走别人的路, 让别人无路可走.
5. 穿别人的鞋, 走自己的路, 让他们找去吧.
6. 走NB的路, 让SB说去吧.
7. 听说女人如衣服, 兄弟如手足. 回想起来, 我竟然七手八脚的裸奔了19年.
8. 宁愿相信世间有鬼, 也不相信男人那张嘴.
9. 水至清则无鱼, 人至贱则无敌.
10. 树不要皮, 必死无疑. 人不要脸, 天下无敌.
11. 一山不能容二虎, 除非一公一母.
12. 对流血一周仍然不死的动物千万不能大意.
13. 我, 一个大学生的人生目标:农妇, 山泉, 有点田.
14. 女人谨记:一定要吃好玩好睡好喝好. 一旦累死了, 就别的女人花咱的钱, 住咱的房子, 睡咱的老公, 泡咱的男朋友, 还打咱的娃.
15. 有一天, 我梦见自己的钱花光了, 醒来一看, 口袋真的空空的.
16. 我减肥已取得了很大的成功, 你看, 我三个下巴都尖了.
17. 千万别等到人人都说你丑的时候才发现自己真的丑.
18. 如果朋友可以出卖, 每个值五元的话, 我也能发笔小财了.
19. 肚子大不可怕, 可怕的是大而无料.
20. 女人先表现自己大方, 男人就不敢小气了.
21. 人, 生在床上, 死在床上, 欲生欲死, 也在床上.
22. 巫师, 请转告公主, 老子还在披荆斩刺的路上, 还有雪山未翻, 大河未过, 巨龙未杀, 美女未泡. 叫她继续死睡吧.
23. 无所为而无所谓, 无所谓而无所不为.
24. 铁饭碗的真正含义不是在一个地方有饭吃, 而是一辈子到哪儿都有饭吃.
25. 骚归骚, 骚有骚的贞操. 贱归贱, 贱有贱的尊严.
26. 人生的成功不在于拿到一副好牌, 而是怎样将坏牌打好.
27. 0岁出场亮相, 10岁天天向上, 20岁远大理想, 30岁发奋图墙, 40岁基本定向, 50岁处处吃香, 60岁打打麻将, 70岁处处闲逛, 80岁拉拉家常, 90岁挂在墙上.
28. 再过几十年, 我们都来相会, 送到火葬场, 全部烧成灰, 你一堆, 我一堆, 谁也不认识谁, 全部送到农村做化肥.
29. 自从我变成了狗屎, 就再也没有人踩在我头上了.
30. 路边的野花不要, 踩.
31. 也许似乎大概是, 然而未必不见得.
32. 说过的话可以不算, 喜欢的人天天要换.
33. 本人中科院高级潜水院院士, 诺贝尔长期掉线奖, 奥斯卡终身隐身奖.
34. 你放心, 看到你我连食欲都没有了, 还谈什么性欲.
35. 生活真他妈好玩, 因为生活老他妈玩我.
36. 佛曰:"前世的500次回眸才换来今生的一次擦肩而过." 我宁愿用来世的一次擦肩而过换得今生的500次回眸.
37. 黑夜给了我一双黑色的眼睛, 可我却用它来翻白眼.
38. 我想早恋, 但是已经晚了.
39. 天啊, 我的衣服又瘦了.
40. 这个世界上我只相信两个人, 一个是我, 一个不是你.
41. 思想有多远, 你就给我滚多远.
42. 流氓不可怕, 就怕流氓有文化.
43. 客官请自重, 小女子只卖身不卖艺.
44. 男人的谎言可以骗女人一夜, 女人的谎言可以骗男人一辈子.
45. 如果不能给你的女人幸福, 请停下你解开她衣扣的手.
46. 如果不能给你的女人穿上嫁衣, 那么千万别停下你解开她衣扣的手.
47. 水能载舟, 亦能煮粥.
48. 开车无难事, 只怕有新人.
49. 一见钟情, 再而衰, 三而竭.
50. 生, 容易. 活, 容易. 生活不容易.
51. 如果我能看到我的背影, 我想它一定很忧伤, 因为我把快乐都留在了前面.
52. 出问题先从自己身上找原因, 别一便秘就怪地球引力不够.
53. 给我织一条围巾, 我愿以一生关怀相报. 否则, 你就用围巾勒死我吧.
54. 男人在不懂的时候装懂, 女人则恰好相反.
55. 春色满园关不住, 我拉红杏出墙来.
56. 你以为我会眼睁睁看着你去送死吗? 我会闭上眼睛的. -_-
57. 我以为我很颓废, 今天我才知道, 原来我早报废了.
58. 我视金钱如粪土, 我爸视我为粪池.
59. 我喝酒想把痛苦溺死, 但这该死的痛苦却学会了游泳.
60. 我是你的风筝, 线在你手上, 可陪伴我的只有风.
61. 别人都在假装正经, 那我就只有假装不正经了.
本文将介绍在JSP页面中包含一些JavaScript这样一个简单而有效的方法来结合AJAX和Struts。在此我们介绍如何重新使用已经存在的Struts actions,但此技术同样可用于你选择的其他Java-Web 框架。本方法同样可平移到Struts或者JSF的下一个版本。
AJAX是“异步的JavaScript和XML”的缩写。这是一项技术,而不是一个如Struts一样的框架。为什么在AJAX周围会有这么多的关注呢?这是因为AJAX使web页面看起来并不像一个平面的文档,而更像用户所期望的如桌面应用的动态GUI应用程序。AJAX技术能在很多的浏览器上使用(包括IE和Netscape/Mozilla)。它已经为Microsoft(用于Outlook的web客户端)和Google(用户Google Maps和Gmail)所使用。
未使用AJAX之前
目前大多数的Struts应用都是标准的“如同一个平面文档的web页面”的结构。如果你想模仿一些桌面应用程序(比如那些使用Java Swing,Visual Basic,或者Delphi建立的应用程序),那么你有两个选择:你可以发送所有的可能作为页面的一部分被请求的信息,使用大量的JavaScript来操作其动态的显示(一个很慢并且非企业级Java的方法);或者你可以不改变形式地提交到后台服务器(一种有效的方法) 。AJAX提高给你了融合前面的最佳解决方案:动态的页面,但是大多数的应用是在你的web服务器的Java程序来处理的。
AJAX 101
AJAX和现有的动态HTML技术非常相似,并在其上增加了一个发送到“后台”服务器的请求来获取需要的新的或者更新的信息。AJAX的机制在其他地方已经有详细的说明――请查看本文后的Resources来获取更多。但是你至少需要知道:
- 1. XMLHttpRequest (如果你使用的是IE浏览器的话,则是Microsoft.XMLHTTP的ActiveX的对象)。这些对象,你可以在web页面中使用JavaScript调用。他们允许你作为后台的调用方式来请求web服务器的内容(例如,在表单提交后,屏幕并不像平时一样显示“空白”)。
- 2. XMLHttpRequest 和Microsoft.XMLHTTP 返回的内容可以作为XML或者文本来处理。JavaScript(在你页面上的)可以使用请求的新内容来更新页面。
- 3. 整个处理过程可以由普通的JavaScript事件来触发:onclick,onchange,onblur,等。
在你的Struts应用中使用AJAX
你阅读了本文,然后你会对使用AJAX来创建动态的web页面感兴趣,并且想知道如何将它加入到你的Struts应用中。这只是选择之一。那么你会如何选择呢?
- · 等待,知道Struts的下一个版本融合了AJAX技术。如果Struts开发者准备开发一个新的应用,这或许会是一个好的选择。再后面,可能会是要求JSF也这样做――对其本身并不一件坏事,但是对于已经存在的系统这将会带来最根本的改变。
- · 你也可以直接采用新的方法,比如Direct Web Remoting (DWR) 和Ruby on Rails,这些都是专为建立AJAX应用的。如果你考虑不使用Struts来开发web的话,那么这些都是很又用的框架,并且值得一试。但是,这也同时意味着你必须要重写你的应用。
- · 在你已经存在的Struts应用中增加AJAX。既然AJAX只是一项技术而并非框架,那么它就很容易融入到Struts中。作为现有的系统,其稳定性(如,保持现有的库文件)是相当重要的。所以这个方法被推荐,并且我们将在后面详细介绍。
我们选择在Struts应用中增加AJAX的优势是:
- 1. 它并不需要任何新的库文件或者服务器代码;只需要使用现有的Struts库文件和action。
- 2. 解决方案中所有部分――JavaScript,XML,Java和Struts――早已为广泛所知。
- 3. 此应用可以一块一块地移植到AJAX;我们可以确定哪些部分对用户有益,并首先将它们更新到动态AJAX显示。
实现方案
我们如何真正的贯彻我们的选择呢?我们首先应该注意一个“标准的”(没有AJAX)Struts应用是如何工作的。在此应用中,一个一般的事件流程如下:
- 1. 使用点击超链接或者表单的提交按钮,用户发送请求。
- 2. web服务器运行处理请求的Struts Action来生成一个web页面。
- 3. 浏览器显示web页面。
- 4. 当用户点击保存的时候,信息由Struts框架中一个ActionForm类来转换并发送到服务器。
- 5. 然后,Struts框架调用Struts Action来出来请求(如,保存数据到数据库中)。
- 6. 页面再一次回传,处理流程继续。
现有的Struts应用
一个演示事件流程的简单Struts应用可以在以下地址下载: struts-non-ajax.zip。此基于Struts的应用,是基于用户的输入显示或者隐藏蓝色和绿色的表格。图1显示了载入初始页面的画面。图2显示了用户输入值并点击了提交后的画面。虽然简单,但它已经足以表示一个Struts的工作流程。

图 1. 没有AJAX的例子:初始屏幕

图 2. 没有AJAX的例子:输入值并点击了提交
服务器端的代码是:一个Struts Action使用struts-config.xml 中定义的值转发到(相同的)JSP。这个例子代码中一些需要注意的地方是:
- ·struts-config.xml文件将所有的请求重定向到http://localhost:8080/struts-non-ajax/(或者和你自己的服务器相同)的index.jsp。
- · index.jsp 包含了一个两个文本框的Struts form(showBlue和showGreen)。该页面同样包含了标签,但是如同两个文本框被初始化为空,标签之间的内容并不显示。
- · 用户输入值(true或者false)并点击提交按钮,处理控制(经过Struts框架,读取struts-config.xml)提交到SampleAction类中。
- ·SampleAction记录下值,然后转发到index.jsp。一个成熟的Struts应用可能会处理更多的事情,不如保存或者查询数据库等。
- · index.jsp 现在重新处理请求;如果ShowBlue或者ShowGreen的值是true,这些表格就显示出来。
该应用并没有任何“错误”。类似的Struts项目好多年都是这样做的。但是,我们如何在不添加复杂的JavaScript或者频繁的表单提交的前提下,为此应用增加动态的元素呢?
我们的第一个Struts AJAX应用
观察下下面的图3和图4。第一眼看上去,它们和前面的例子没有说明区别。它们的不同之处在于,页面载入后(图3)然后文本框中的值改变了,窗体自动提交而不显示空白的,然后在图4中显示结果。普通的提交按钮仍然在,你也可以选择使用它。

图 3. 页面载入后的AJAX例子

图 4. AJAX调用后的AJAX例子
添加AJAX是出奇的容易。服务器端的代码和前面的例子是一样的: 一个Struts的ActionForm来后去数据,一个Struts的Action来执行需要的任务(例如,存储数据库)然后转发到适当的JSP页面来显示结果。
继续
如果你希望就此停止阅读(跳过这个例子的工作说明),但是这里的是和你需要转换你的Struts应用到一个Struts-AJAX应用同样的风格:
- 1. 在你的web页面中引入一个Ajax.js (该文件是struts-ajax.zip 例文件中的一部分)。Ajax.js 包含了所有需要发送和接收AJAX调用的JavaScript方法。
- 2. 确保你希望在AJAX调用中更新的web页面的部分包含在标签中,并且给每个标签一个id。
- 3. 当一些事件触发的时候就更新页面(例如,文本框的the onchange()方法),调用retrieveURL()方法,通过URL传递到需要执行服务器端处理的Struts Action。
- 4. 为了页面的显示/更新,最简单的方法是Struts Action转发回同样的页面。在本例中,showGreen/showBlue 文本框中的onchange()方法来触发AJAX调用。
JavaScript方法retrieveURL()调用服务器的Struts(通过URL),获取JSP响应,然后更新显示页面中的 标签中的部分。就是这么简单!
AJAX解决方案的细节
我们将例子变为AJAX-Struts应用的时候,需要三个变化:
- 1. 增加一个JavaScript方法来完成到服务器的“背后的”AJAX调用。
- 2. 增加JavaScript代码来接收服务器的响应并更新页面。
- 3. 在JSP页面增加标签标签,这个标签中内容将在AJAX调用中更新。
我们将详细的说明上面的每一步。
发送AJAX请求到服务器
有两个方法(在下面列出)用于发送请求到服务器。
· retrieveURL()方法获得服务器的URL和Struts form。URL用于使用AJAX,form的值用于传递到服务器。
· getFormAsString()方法用于将retrieveURL()中form命名的值组装成查询字符串,并发送到服务器。
使用方法很简单,使用onclick()/onChange()事件来触发retrieveURL()更新显示。
在这两个方法中有一些有趣的东西。
在retrieveURL()方法中,req.onreadystatechange = processStateChange (注意,没有括号)这一行来告诉浏览器在服务器响应到达的时候调用processStateChange()方法(该方法将在后面介绍)。retrieveURL()方法中(现在已经是AJAX的标准了)同样决定是使用IE浏览器(ActiveX)还是使用Netscape/Mozilla (XmlHttpRequest) 来实现跨浏览器兼容。
getFormAsString()方法将HTML form转换成字符串连接在URL后面(这样就允许我们发送HTTP GET请求)。这个字符串是经过转换的(比如,空格转换成%20等),并且是一个Struts能将其组装成ActionForm的格式(并不需要Struts清楚的明白这个是来之AJAX的请求)。注意,在本例中我们使用HTTP GET,使用HTTP POST的方法也是类似的。
function retrieveURL(url,nameOfFormToPost) {
//将url转换成字符串
url=url+getFormAsString(nameOfFormToPost);
//调用AJAX
if (window.XMLHttpRequest) {
// 非IE浏览器
req = new XMLHttpRequest();
req.onreadystatechange = processStateChange;
try {
req.open("GET", url, true);
} catch (e) {
alert("Server Communication Problem\n"+e);
}
req.send(null);
} else if (window.ActiveXObject) {
// IE
req = new ActiveXObject("Microsoft.XMLHTTP");
if (req) {
req.onreadystatechange=processStateChange;
req.open("GET", url, true);
req.send();
}
}
}
getFormAsString() 是一个“私有” 方法,在retrieveURL()中使用。
function getFormAsString(formName){
//设置返回字符串
returnString ="";
//取得表单的值
formElements=document.forms[formName].elements;
//循环数组,组装url
//像'/strutsaction.do&name=value'这样的格式
for(var i=formElements.length-1;i>=0; --i ){
//转化每一个值
returnString+="&"
+escape(formElements[i].name)+"="
+escape(formElements[i].value);
}
//返回字符串
return returnString;
}
根据AJAX的响应更新web页面
到现在为止,我们学习过了使用JavaScript来完成AJAX调用(前面列出),Struts Action,ActionForm以及JSP(基本没有变化,只是增加了标签)。为了完善我们对Struts-AJAX项目的了解,我们需要了解三个用于根据服务器返回的结果而更新页面的JavaScript方法。
- · processStateChange(): 该方法在AJAX调用前设定。它在服务器响应到达后由XMLHttpRequest/Microsoft.XMLHTTP 对象调用。
- ·splitTextIntoSpan(): 根据响应,循环取出数组中的元素组装成NewContent。
- ·replaceExistingWithNewHtml(): 根据span元素数组,循环搜索,将里面的元素调换掉页面中和它的'someName'相同的中的内容。注意,我们使用的是req.responseText 方法来获得返回的内容(它允许我们操作任何文本的响应)。与此相对于的是req.responseXml (它的作用更大,但是要求服务器返回是XHTML或者XML)。
function processStateChange() {
if (req.readyState == 4) { // 完成
if (req.status == 200) { // 响应正常
//将响应的文本分割成Span元素
spanElements =
splitTextIntoSpan(req.responseText);
//使用这些Span元素更新页面
replaceExistingWithNewHtml(spanElements);
} else {
alert("Problem with server response:\n "
+ req.statusText);
}
}
}
replaceExistingWithNewHtml() 是为processStateChange()使用的“私有”方法。
function replaceExistingWithNewHtml
(newTextElements){
//循环newTextElements
for(var i=newTextElements.length-1;i>=0;--i){
//判断是否以 if(newTextElements[i].
indexOf("-1){
//获得span的名字- 设置在第一和第二个引号之间
//确认span元素是以下的格式
//NewContent
startNamePos=newTextElements[i].
indexOf('"')+1;
endNamePos=newTextElements[i].
indexOf('"',startNamePos);
name=newTextElements[i].
substring(startNamePos,endNamePos);
//获得内容-在第一个>标记后的所有内容
startContentPos=newTextElements[i].
indexOf('>')+1;
content=newTextElements[i].
substring(startContentPos);
//现在更新现有的Document中的元素,
// 确保文档存在该元素
if(document.getElementById(name)){
document.getElementById(name).
innerHTML = content;
}
}
}
splitTextIntoSpan() 是为processStateChange() 使用的“私有”方法。
function splitTextIntoSpan(textToSplit){
//分割文档
returnElements=textToSplit.
split("")
//处理每个元素
for(var i=returnElements.length-1;i>=0;--i){
//删除掉第一个span后面的元素
spanPos = returnElements[i].
indexOf("
//如果找到匹配的,获得span前的内容
if(spanPos>0){
subString=returnElements[i].
substring(spanPos);
returnElements[i]=subString;
}
}
return returnElements;
}
新的控制流
添加以下的JavaScript代码到我们的应用中,以下的步骤将在服务器和浏览器中执行。
- 1. 如同一个普通Struts应用装载页面。
- 2. 用户改变文本框的值,触发一个onChange() 事件,调用retrieveURL() 方法。
- 3. 该JavaScript方法通过发送Struts明白的表单变量(后台)请求到服务器的Struts Action。
- 4. 该JavaScript方法同样设定了第二个JavaScript方法的名字,此方法将到服务器响应完毕后调用。本例子中,设定为processStateChange() 方法。
- 5. 如我们所预期的,服务器响应完毕,调用processStateChange() 方法。
- 6. JavaScript在(新的)服务器响应中循环取出所有元素。将页面上存在与获得元素名字相同的 中的元素替换掉。
在你的应用中设计AJAX
以上描述的JavaScript方法能在大多数的应用中使用,包括比我们的例子复杂得多的。但是,在使用之前,你需要注意以下几点:
· 避免复制代码,最好在初始化请求(如,显示完整的页面)和AJAX(更新部分页面)请求中使用相同的Struts Action和JSP。
·在公共的Action(控制器)中,决定JSP页面(所有的JSP页面或者其中的一部分)中的一个区域需要传送到浏览器。通过在web服务器的session或者ActionForm中设定标记来让JSP页面知道哪些部分需要提交。
· 在JSP中,使用Struts 或者JSTL标签来决定提交的HTML区域。
使用AJAX的本例子,可以在以下下载: struts-Ajax.zip
结语
AJAX技术允许我们在创建和使用web应用的时候完全的改变。本文介绍了一个简单的技术,在现有的Struts应用中增加Struts的处理。它允许我们利用我们已有的东西,不仅仅是代码,还包括了开发的技能。作为一个好的产品,它同样允许我们写出更清晰,更具移植性的Java Struts应用。
版权声明:Techtarget获Matrix授权发布,如需转载请联系Matrix
作者:作者:Paul Browne;pawenwen(作者的blog:http://blog.matrix.org.cn/page/pawenwen)
译文:点击
随着企业intranet和国际internet的迅速发展,越来越多的工作流程,商务交易,教育、培训、会议和讲座,以及个人消费娱乐都被转移到所谓的万维网(World Wide Web,以下简称WEB)上来了。与此相对应的是交互操作的复杂性越来越高。
随着Browser/Server模式的日渐流行,很多操作都是在浏览器环境下的网页上完成的,并不是只有失效的链接和意外的出错才会使操作者感到烦恼,即便是一次完整的成功操作过程,也可能因为操作的繁复性过高或者使用上的不方便而给操作者带来不愉快的体验。
本文试图阐述WEB交互页面设计的一些指导性原则,这些原则有利于避免发生不愉快的操作体验。这些原则是用户友好性的,是在完成同一种操作要求下,使用户最感到轻松、简单、舒适的WEB交互界面设计原则。我们假定我们讨论的WEB页面都是功能正常的,符合美学观点的。需要说明我们讨论的原则可能会和设计上的美学观点以及既有的功能设计有所冲突。如果发生这种情况,基于“实用的就是美的”观点,我们会建议您酌情放弃原先的美学观点与功能设计。
1. 输入控件的自动聚焦和可用键盘切换输入焦点
使用JavaScript实现页面加载完成后立即自动聚焦(focus)到第一个输入控件。可用TAB键(IE缺省实现)或方向键切换聚焦到下一个输入控件。
输入控件指WEB页面表单(<form>)中显式的,需要用户进行修改、编辑操作的表单元素。对于这些控件,如果没有自动聚焦操作,不可避免的出现一次用户鼠标定位操作(如果用户此前处于键盘输入操作状态或鼠标定位后需要进行键盘输入操作,实际上是键盘鼠标切换操作)。如果鼠标定位后需要进行键盘输入操作,如果不能键盘切换输入焦点,那么不可避免的在切换输入焦点时需要反复的键盘鼠标切换操作,这是很繁琐的。
如果实现了页面加载完成即自动聚焦到第一个输入控件,并且可以键盘切换输入焦点标定位操作,那么对于用户来说整个页面的输入操作可能都不需要鼠标操作,或次数较少,这是一种便利。毕竟频繁的键盘鼠标切换操作是比较累人的。
对于有输入栏的对话框或网页,在不干预的情况下就应将当前控制焦点定位在待输入的输入栏上;如果输入栏在一般情况下不需要更改其中的内容,则应直接将焦点定在“确定”按钮上;在几个输入栏之间应支持tab,shift+tab切换操作,“确定”和“取消”应该是切换操作的终点,与具体所在位置无关。
2. 可用Enter(或Ctrl+Enter)键提交,确保和点击提交按钮的效果是相同的
不要在提交按钮上加入onClick=”…”这样的JavaScript代码。
用Enter键提交页面是原则1的自然延伸,而且这也是浏览器所缺省支持的。只所以单独列出来是因为实际上有些设计者设计的页面不能达到这种效果,结果导致使用Enter键提交和点击“确定”按钮提交带来的效果不一样。大部分情况下是设计者在“确定”按钮上加入了onClik=”…”这样的代码,通过点击“确定”按钮后,会执行一段JavaScript代码,比如对某些hidden类型的input元素设值。而使用Enter键提交时就不会执行这段代码。
正确的做法是把这段代码移到表单标签<form>中,以onSubmit=”…”属性引入。
对于<textarea>表单元素,它会消耗Enter键,因此会使得Enter键提交失效。可以引入JavaScript代码捕捉Ctrl+Enter复合键,一旦捕捉到即执行表单的submit()方法。对于需要频繁提交的场合,比如BBS上,这种代码是很有必要的。
3. 鼠标动作提示和回应
对用户的鼠标定位操作,当移动到可响应的位置上时,应给予视觉或听觉的提示。
动作回应的最简单形式就是鼠标ICON变成手状。浏览器只对具有href属性的HTML标签会自动进行这种变换ICON的行为。对于没有href属性(或没有设置href属性)的标签,可以通过JavaScript设置style属性的cursor为hand。
目标区域发生变化是更为主动的响应形式。当鼠标指针移到目标区域,此时指针图形改变或文字颜色发生改变均能较大的减轻用户搜索定位目标区域的注意力负担。在按钮上增添直观的图形,尽可能的增大按钮面积;按钮间保持适当的距离,太近增加了用户区别它们之间界限以防误操作的负担,太远增加了用户搜索定位按钮的负担。
4.尽可能早的在客户端完成输入数据合法性验证
输入数据的合法性检验应该在客户端使用JavaScript进行验证。除非验证只能在服务器端完成,否则验证工作应在最早能完成的情况下进行。
在客户端完成数据合法性验证,可以避免一次服务器请求和回复通讯,这种通讯是需要用户等待的,如果用户等待很长时间后从服务器返回的结果提示出现的错误是在输入时即可发现的,那么这种设计就是不友好的。诸如密码长度限制,用户名允许字符限制等等,显然应该在客户端提交前就应该进行验证。
5. 根据应用场景决定在表单页面和提交后返回页面间是否使用中间过渡页面
根据应用场景,决定是否显示接收表单页面(表单页面和提交后返回页面间的中间过渡页面),以及使用何种方式显示接收表单页面。
表单页面和接收表单页面是大部分WEB交互操作赖以实现的配合模式。关于表单页面和接收表单页面的相互关系的设计,要做如下几个方面的考虑。
一,对于需要频繁操作的场合,从操作便利和快捷性出发,尽可能的减少服务器和客户端交互次数,应该避免使用中间过渡页面。提交完毕直接返回原来的表单页面或默认页面。在这种情况下要考虑到数据安全和可恢复性。
如果因为用户输入的数据不合格,需要重新输入,那么,去除中间页面,把错误信息直接显示在原表单页面上的设计方式,将是最简洁的处理方式。用户只需要根据错误提示进行更正即可。当然这样做稍微增加了编程负担。在表单接收页面上需要包含原表单页面的内容,而且输入数据项都必须用服务器端代码或客户端JavaScript设置成用户输入的值。为了开发快捷,可以这样做:表单页面和接收表单页面用同一个服务器端脚本页面实现。这个页面按如下流程完成原来两个页面的工作:
页面脚本初始化
┃
检查“提交”变量是否设置
┠已设置,做数据验证
┃ ┠验证通过->业务逻辑处理->使用包含页面方式或重定向方式返回到特定页面
┃ ┗验证不通过->保存用户输入的数据->退出表单提交处理到表单页面流程中
┗未设置,做表单页面流程,如有来自提交流程中产生的用户输入数据,则显示出来
其中,使用包含页面方式返回到特定页面可以避免一次客户端重定向过程,比客户端重定向过程还要快捷和稳定一些。但是有些情况下因为代码变量冲突或其他原因,使用包含页面方式可能并不方便,这时候可以使用服务器端重定向技术,在ASP里是Server.Transfer方法,在Java Servlet里是RequestDispatcher.forward()方法。不要使用Response.Redirect或者HttpServletResponse.sendRedirect()这种客户端HTTP重定向方法。不使用中间过渡页面也就意味着用户不能后退浏览原先已经填好的表单页面,因为使用的是同一个URL。所以在验证不通过情况下保存用户输入的数据就是必不可少的。
不使用中间过渡页面带来的另一个问题就是使用包含页面方式或服务器端重定向方式返回会使得URL和页面内容不能一一对应。对于用户可能会直接用这个URL(会收藏这个URL)访问返回页面的情况,他会发现实际上到达的是表单页面,不是他想要的那个返回结果页面。所以,去除中间过渡页面,确实会带来URL和内容含混不清的情况,因而不适合需要URL和页面内容一一对应的场合。
二,从技术角度考虑,使用中间过渡页面能保证URL和页面内容一一对应,简化页面开发工作。
为了保证页面内容总是和固定的URL联系起来,必须使用客户端重定向:
提交 业务逻辑处理 (中间过渡页面)
表单页面――――->接收表单页面―――――――――>显示处理结果―――>客户端重定向到特定页面
客户端重定向分几种情况:1,使用HTTP Header重定向,Location:http://www.netall.com.cn,这种定向是最快的,在窗口一片空白的情况下就迅速访问(GET)另一个页面。这种方式实际上不能显示处理结果,只能说是向第一种快速重定向方式的一种折衷处理;2,HTML标签刷新,<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://www.netall.com.cn">,这种定向比较友好,在这个页面加载完毕后访问另一个页面。很多设计者把这个作为一个技巧使用,在载入一个大页面前放置一个缓冲页面以避免用户乏味的等待;3,JavaScript重定向。由于是用代码控制重定向,可以做的更灵活。比如根据用户习惯,控制操作完毕后的转向流程。4,被动式的重定向。在页面上放置按钮或链接,由用户手动决定返回到特定页面。这种情况适合于处理结果的显示页面包含相当多的信息,需要用户仔细浏览,而决定下一步的操作。
在使用中间过渡页面的情况下,不能再使用页面过期失效了。否则一旦出现错误,需要用户重新输入表单数据,用户就不能用后退按钮恢复此前填写的表单数据了。除非设计者有意禁止这种恢复。
6. 防止表单重复提交处理
对提交按钮点击后做变灰处理避免在网络响应较慢情况下用户重复提交同一个表单。使用页面过期失效避免用户后退浏览重复提交表单。
有些复杂的应用会导致需要较长时间的等待才会返回处理结果。而在较慢的网络环境中,这种情况更是频繁发生。焦急等待的用户往往会重复点击提交按钮。这种情况是设计者所不希望看到的。
使用JavaScript在点击提交按钮后使按钮失效变灰是一个最直接的办法(根据原则2这段代码应该放在<form>标签里onSubmit=”…”做)。此外,在表单页面上,用服务器端脚本设置HTTP Header的Expires为立即过期可以保证用户没办法使用后退浏览恢复表单页面。注意这样做的代价可能是用户辛辛苦苦填写很长的内容,结果一旦操作失误就没法恢复。所以应该避免在包含<textarea>表单元素的页面上使用页面过期失效。
应该说,更严格的方法是,服务器端脚本就应该具备抵抗重复提交的能力。例如,为这个表单分配一个唯一ID或一个使用一次即失效的验证码。此外,这个表单处理还应具有事务性质,如果表单不被接受,所做的改变还是能恢复的。在金融应用场合,重复提交同一笔交易是肯定不被允许的。能在重复提交中获利的一方总是会想办法绕过浏览器的限制,所以不能依赖于客户端的技术。
7. 页面链接是打开新窗口、使用原窗口还是弹出窗口的原则
一般而言,首页上链接可以使用target=”_blank”属性打开新窗口,而其他页面上的链接都应使用原窗口或弹出窗口。如果链接页面内容相对原页面来说不重要,是附属性质的,可以使用弹出窗口方式。
一般情况下应该使用原窗口,把是否保留原窗口内容的权利留给用户。除非设计者相信原页面是如此重要,在用户发出点击指令后还有使用上的价值,以至于不能被随便更新或覆盖。一般来说,只有首页才会处于这样一个地位,用户在首页上打开一个链接后,一般还会在这个首页上去打开另一个链接。比如首页包含极多链接的门户网站,或者搜索引擎的搜索结果页面。Google.com以前的搜索结果页面上的链接是使用原窗口的,后来他们意识到用户会反复使用这个页面,而改成打开新窗口了。一般的网站如果首页链接不多,就不必使用新窗口,这是用户友好的设计原则。
上述情形的一个极端情况就是新页面内容比起原页面内容的重要性差很多,以至于都未必需要打开一个新页面。这时候使用弹出窗口比较合适。用JavaScript弹出窗口有好几种:一个是window.open()函数。这里有个技巧。应该使用window.open()先打开一个空白窗口,再使用location.replace()用目标页面替换。这样做可以避免在打开新页面的过程中导致原页面失去响应。Window.open()将打开一个新的浏览器窗口进程,因此资源消耗比较大。另一个是由微软DynamicHTML规范中扩充的方法createPopup()。createPopup()可以创建无边框的弹出窗口,消耗系统资源较小。还有一个就是用页面中隐藏的层<div>来模拟一个弹出页面。后两种可以使用JavaScript代码填充弹出窗口内容。如果需要下载网页作为其内容的话,需要微软DynamicHTML规范中的<download>标签。
8. 尽可能少的排列可选项,尽可能少的安排操作步骤
根据用户操作习惯安排尽可能少的操作菜单选项,同时要保证尽可能少的操作步骤。
在不降低功能多样性的前提下减少菜单项和操作步骤是用户友好的设计。要做到这一点很不容易。要从用户出发考虑他们最频繁的操作是什么。正常情况下一个用户需要的操作总可以归类为5个以下的种类,如果出现更多的种类,那一定是没有针对用户兴趣去区分主次。一个用户同时有5个以上的强烈兴趣中心是难以想像的,走马观花似的随意点击浏览的用户,是不大可能在某个种类上进行深入的交互操作的。在这5个种类中,每个种类都可能有若干个可操作的二级种类。如果这些二级操作项是不可见的,那么意味着要做两次选择才能进入可操作页面。这就违背了“尽可能少的安排操作步骤”这一原则。如果使用JavaScript制作二级菜单,避免请求服务器,会好一些。如果二级菜单项总共不超过20个左右,不妨将二级菜单直接显示出来,比如放在左列一字向下排开,这样只需要一次选择到可操作项,更加明了方便。
9. 操作逻辑无漏洞,保证数据是操作安全的
多个页面间的操作和同个页面上的多个操作间的逻辑关系在设计上是安全和严谨的。保证不会出现不被允许的用户操作组合,至少不会因为用户的不适当的操作导致出错。
这最典型的表现则是在页面上广泛采用的所谓联动下拉框设计。一个下拉框中允许的选项受另一个下拉框中的选择而变。另外一个例子是根据选择使表单元素有效或者失效。如果在多个页面间也要维持某种合法性逻辑,那么就需要服务器端脚本的参与。这样会使表单设计跟操作有关,应该说这不是一个好的设计。可以通过变更操作步骤顺序、组合方式来尽可能避免这种情况出现。
操作逻辑的设计既要保证用户任意的输入不会导致错误,也要保证是用户输入的数据能购被安全处理。在Session控制下的表单中输入大幅文字可能会导致超时出错,这时候往往还伴随重定向过程,导致用户的长篇输入荡然无存。用JavaScript提醒用户已超时,请保存输入后重新提交,是一个好办法。某些表单元素如<input type=”text”>接受ESC键清除数据,并且无法撤销,这也是很危险的。在中文输入法中常常使用ESC键清楚输入的码位,一旦不小心多按一下ESC就会使得输入数据消失。因此有必要用JavaScript禁用<input>和<textarea>的ESC键处理过程。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=413028
1.下载
FCKeditor2.3 (FCKeditot for java)
FCKeditor2.4 (FCKeditor基本文件)
以下是下载地址:
http://www.fckeditor.net/download/default.html
2.建立项目:
建立项目tomcat/webapps/TestFCKeditor.
3.将FCKeditor2.4解压缩
将FCKeditor2.4解压缩,将整个目录FCKeditor复制到项目的根目录下,并将解压缩出来的文件夹fckeditor重命名为FCKeditor
目录结构为:tomcat/webapps/TestFCKeditor/FCKeditor
然后将FCKeditor-2.3.zip(java)压缩包中\web\WEB-INF\lib\目录下的两个jar文件拷到项目的\WEB-INF\ lib\目录下。把其中的src目录下的FCKeditor.tld文件copy到TestFCKedit/WEB-INF/下
4.合并web.xml:
将FCKeditor-2.3.zip压缩包中\web\WEB-INF\目录下的web.xml文件合并到项目的\WEB-INF\目录下的web.xml文件中。
5. 修改合并后的web.xml文件
修改合并后的web.xml文件,将名为SimpleUploader的Servlet的enabled参数值改为true,
以允许上传功能,Connector Servlet的baseDir参数值用于设置上传文件存放的位置。
在web.xml最后添加标签定义:
<taglib>
<taglib-uri>/TestFCKeditor</taglib-uri>
<taglib-location>/WEB-INF/FCKeditor.tld</taglib-location>
</taglib>
现在的web.xml文件没有<taglib>标签了,应该直接在jsp文件中使用:<%@ taglib uri="http://fckeditor.net/tags-fckeditor" prefix="FCK" %>
6. 映射:
上面文件中两个servlet的映射分别为:/editor/filemanager/browser/default/connectors/jsp/connector
和/editor/filemanager/upload/simpleuploader,需要在两个映射前面加上/FCKeditor,
即改为/FCKeditor/editor/filemanager/browser/default/connectors/jsp/connector和
/FCKeditor/editor/filemanager/upload/simpleuploader。
这两个名字根据你放在工程中的FCKeditor文件夹名称而定。。
7.修改skin文件夹
进入skin文件夹,如果你想使用fckeditor默认的这种奶黄色,
那就把除了default文件夹外的另两个文件夹直接删除.(建议不删除,以后要用到其中的一个文件夹)
8.删除无用文件
删除/FCKeditor/目录下除fckconfig.js, fckeditor.js, fckstyles.xml, fcktemplates.xml四个文件以外的所有文件,保留文件夹editor
删除目录/editor/_source,
删除/editor/filemanager/browser/default/connectors/下的所有文件
删除/editor/filemanager/upload/下的所有文件
删除/editor/lang/下的除了fcklanguagemanager.js(我下载的没有这个文件), en.js, zh.js, zh-cn.js四个文件的所有文件
9.修改配置:
打开/FCKeditor/fckconfig.js
修改 FCKConfig.DefaultLanguage = 'zh-cn' ;
把FCKConfig.LinkBrowserURL等的值替换成以下内容:
FCKConfig.LinkBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Connector=connectors/jsp/connector" ;
FCKConfig.ImageBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Image&Connector=connectors/jsp/connector" ;
FCKConfig.FlashBrowserURL
= FCKConfig.BasePath + "filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/jsp/connector" ;
FCKConfig.LinkUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=File' ;
FCKConfig.FlashUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Flash' ;
FCKConfig.ImageUploadURL = FCKConfig.BasePath + 'filemanager/upload/simpleuploader?Type=Image' ;
10.其它
fckconfig.js总配置文件,可用记录本打开,修改后将文件存为utf-8 编码格式。找到:
FCKConfig.TabSpaces = 0 ; 改为FCKConfig.TabSpaces = 1 ; 即在编辑器域内可以使用Tab键。
如果你的编辑器还用在网站前台的话,比如说用于留言本或是日记回复时,那就不得不考虑安全了,
在前台千万不要使用Default的toolbar,要么自定义一下功能,要么就用系统已经定义好的Basic,
也就是基本的toolbar,找到:
FCKConfig.ToolbarSets["Basic"] = [
['Bold','Italic','-','OrderedList','UnorderedList','-',/*'Link',*/'Unlink','-','Style','FontSize','TextColor','BGColor','-',
'Smiley','SpecialChar','Replace','Preview'] ] ;
这是改过的Basic,把图像功能去掉,把添加链接功能去掉,因为图像和链接和flash和图像按钮添加功能都能让前台
页直接访问和上传文件, fckeditor还支持编辑域内的鼠标右键功能。
FCKConfig.ContextMenu = ['Generic',/*'Link',*/'Anchor',/*'Image',*/'Flash','Select','Textarea','Checkbox','Radio','TextField','HiddenField',
/*'ImageButton',*/'Button','BulletedList','NumberedList','TableCell','Table','Form'] ;
这也是改过的把鼠标右键的“链接、图像,FLASH,图像按钮”功能都去掉。
找到: FCKConfig.FontNames = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
加上几种我们常用的字体
FCKConfig.FontNames
= '宋体;黑体;隶书;楷体_GB2312;Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
11.添加文件
添加文件 /TestFCKeditor/test.jsp:
<%@ page language="java" import="com.fredck.FCKeditor.*" %>
<%@ taglib uri="/TestFCKeditor" prefix="FCK" %>
<script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"></script>
<%--
三种方法调用FCKeditor
1.FCKeditor自定义标签 (必须加头文件 <%@ taglib uri="/TestFCKeditor" prefix="FCK" %> )
2.script脚本语言调用 (必须引用 脚本文件 <script type="text/javascript" src="/TestFCKeditor/FCKeditor/fckeditor.js"></script> )
3.FCKeditor API 调用 (必须加头文件 <%@ page language="java" import="com.fredck.FCKeditor.*" %> )
--%>
//标签调用方式
<%--
<form action="show.jsp" method="post" target="_blank">
<FCK:editor id="content" basePath="/TestFCKeditor/FCKeditor/"
width="700"
height="500"
skinPath="/TestFCKeditor/FCKeditor/editor/skins/silver/"
toolbarSet = "Default"
>
input
</FCK:editor>
<input type="submit" value="Submit">
</form>
--%>
//JS调用方式
<form action="show.jsp" method="post" target="_blank">
<table border="0" width="700"><tr><td>
<textarea id="content" name="content" style="WIDTH: 100%; HEIGHT: 400px">input</textarea>
<script type="text/javascript">
var oFCKeditor = new FCKeditor('content') ;
oFCKeditor.BasePath = "/TestFCKeditor/FCKeditor/" ;
oFCKeditor.Height = 400;
oFCKeditor.ToolbarSet = "Default" ;
oFCKeditor.ReplaceTextarea();
</script>
<input type="submit" value="Submit">
</td></tr></table>
</form>
//FCKeditor API 调用
<%--
<form action="show.jsp" method="post" target="_blank">
<%
FCKeditor oFCKeditor ;
oFCKeditor = new FCKeditor( request, "content" ) ;
oFCKeditor.setBasePath( "/TestFCKeditor/FCKeditor/" ) ;
oFCKeditor.setValue( "input" );
out.println( oFCKeditor.create() ) ;
%>
<br>
<input type="submit" value="Submit">
</form>
--%>
添加文件/TestFCKeditor/show.jsp:
<%
String content = request.getParameter("content");
out.print(content);
%>
12.测试
浏览http://localhost:8080/TestFCKeditor/test.jsp
最后注意。。不同的版本 变量名称可能不一样。请参考你使用的API文档
配置选项:
AutoDetectLanguage=true/false 自动检测语言
BaseHref="" 相对链接的基地址
ContentLangDirection="ltr/rtl" 默认文字方向
ContextMenu=字符串数组,右键菜单的内容
CustomConfigurationsPath="" 自定义配置文件路径和名称
Debug=true/false 是否开启调试功能,这样,当调用FCKDebug.Output()时,会在调试窗中输出内容
DefaultLanguage="" 缺省语言
EditorAreaCss="" 编辑区的样式表文件
EnableSourceXHTML=true/false 为TRUE时,当由可视化界面切换到代码页时,把HTML处理成XHTML
EnableXHTML=true/false 是否允许使用XHTML取代HTML
FillEmptyBlocks=true/false 使用这个功能,可以将空的块级元素用空格来替代
FontColors="" 设置显示颜色拾取器时文字颜色列表
FontFormats="" 设置显示在文字格式列表中的命名
FontNames="" 字体列表中的字体名
FontSizes="" 字体大小中的字号列表
ForcePasteAsPlainText=true/false 强制粘贴为纯文本
ForceSimpleAmpersand=true/false 是否不把&符号转换为XML实体
FormatIndentator="" 当在源码格式下缩进代码使用的字符
FormatOutput=true/false 当输出内容时是否自动格式化代码
FormatSource=true/false 在切换到代码视图时是否自动格式化代码
FullPage=true/false 是否允许编辑整个HTML文件,还是仅允许编辑BODY间的内容
GeckoUseSPAN=true/false 是否允许SPAN标记代替B,I,U标记
IeSpellDownloadUrl=""下载拼写检查器的网址
ImageBrowser=true/false 是否允许浏览服务器功能
ImageBrowserURL="" 浏览服务器时运行的URL
ImageBrowserWindowHeight="" 图像浏览器窗口高度
ImageBrowserWindowWidth="" 图像浏览器窗口宽度
LinkBrowser=true/false 是否允许在插入链接时浏览服务器
LinkBrowserURL="" 插入链接时浏览服务器的URL
LinkBrowserWindowHeight=""链接目标浏览器窗口高度
LinkBrowserWindowWidth=""链接目标浏览器窗口宽度
Plugins=object 注册插件
PluginsPath="" 插件文件夹
ShowBorders=true/false 合并边框
SkinPath="" 皮肤文件夹位置
SmileyColumns=12 图符窗列数
SmileyImages=字符数组 图符窗中图片文件名数组
SmileyPath="" 图符文件夹路径
SmileyWindowHeight 图符窗口高度
SmileyWindowWidth 图符窗口宽度
SpellChecker="ieSpell/Spellerpages" 设置拼写检查器
StartupFocus=true/false 开启时FOCUS到编辑器
StylesXmlPath="" 设置定义CSS样式列表的XML文件的位置
TabSpaces=4 TAB键产生的空格字符数
ToolBarCanCollapse=true/false 是否允许展开/折叠工具栏
ToolbarSets=object 允许使用TOOLBAR集合
ToolbarStartExpanded=true/false 开启是TOOLBAR是否展开
UseBROnCarriageReturn=true/false 当回车时是产生BR标记还是P或者DIV标记
解决上传乱码:
在SimpleUploaderServlet.java和ConnectorServlet.java两个文件里找到
DiskFileUpload upload = new DiskFileUpload();
分别在其后加入 upload.setHeaderEncoding("utf-8");
这样解决了文件上传的中文乱码问题.
但是在控制台显示的中文内容还是乱码,但是没关系,我们没必要去看控制台下的中文
----------------------------------------------------------------another
FCKeditor2.4.2 Java版使用说明
下载地址以及基本配置请参考:http://hi.baidu.com/wain19/blog/item/c33fb0fab74f24dfb48f312d.html
我的开发环境是ubuntu7.04, 系统默认编码是utf-8,
期间,本人遇到了下面这些问题:
问题一:XML request error: Internel Server Error(500)
出现错误的地方是在:点插入图片,点Browse按钮的时候:
XML request error: Internel Server Error(500)
找资料:http://lamono.javaeye.com/blog/49135
拷贝xalan.jar和serialize.jar到/WEB-INF/lib,问题解决。
FCKeditor-java没有很好的解决中文问题。需要我们修改它的源代码后重新编译打包。打包过程如下:
1。 新建一个web工程名字为FCKeditor-java-2.3,然后把FCKeditor-2.3-java.zip解压缩后的代码拷贝到工程目录下。
2。如果是用的Eclipse,使用快捷键Ctrl+Shift+R
在SimpleUploaderServlet.java和ConnectorServlet.java两个文件里找到
DiskFileUpload upload = new DiskFileUpload();
分别在其后加入 upload.setHeaderEncoding("utf-8");
现在如果直接运行ant任务,会报下面的错误:
taskdef class org.apache.catalina.ant.DeployTask cannot be found
3。 把tomcat安装目录下/server/lib中的catalina-ant.jar拷贝到/WEB-INF/lib目录 下。
4。 打开build.xml
找到
<property name="catalina.home"
修改成你自己的tomcat安装目录
<property name="catalina.home" value="/home/uniquejava/tool/tomcat5028/"/>
找到
<taskdef name="deploy"
修改成如下内容
<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask">
<classpath refid="compile.classpath">
</classpath>
</taskdef>
<taskdef name="list" classname="org.apache.catalina.ant.ListTask">
<classpath refid="compile.classpath">
</classpath>
</taskdef>
<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
<classpath refid="compile.classpath">
</classpath>
</taskdef>
<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask">
<classpath refid="compile.classpath">
</classpath>
</taskdef>
运行ant任务dist, 就可以生成新的FCKeditor-2.3.jar包
问题三: 上传时新建的中文目录全部乱码。 虽然上传到服务器上的文件名正常,但在JSP页面点下载链接时文件名乱码导致不能正常下载。
查找资料:TOMCAT 链接参数有中文时,乱码解决方法
http://hi.baidu.com/jadestone/blog/item/7564deefc9192d36acafd5be.html
修改tomcat-home/conf/server.xml
方法一:
在两处地方加上URIEncoding="utf-8":
<Connector port="8080"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
debug="0" connectionTimeout="20000"
disableUploadTimeout="true" URIEncoding="utf-8" />
<Connector port="8009"
enableLookups="false" redirectPort="8443" debug="0"
protocol="AJP/1.3" URIEncoding="utf-8" />
方法二:
使用useBodyEncodingForURI="true". 这个方法适合你的TOMCAT实例下需要跑多个不同Encoding的程序时。(有点怀疑?!)
<... maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" redirectPort="8443" acceptCount="100"
connectionTimeout="20000" disableUploadTimeout="true" useBodyEncodingForURI="true" />
enableLookups="false" redirectPort="8443" protocol="AJP/1.3" useBodyEncodingForURI="true" /
我只试了方法一,问题解决!
这样, FCKeditor终于可以正常使用了。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
=================================================================
以下为个人原创 http://blog.csdn.net/nickshen3/
怎么将FCKeditor2.4使用在自己的web中。
1. 在webapps创建test文件夹。webapps\test
2. 将下载的FCKeditor2.3的Java包FCKeditor-2.3.zip解压缩,并将web文件夹下的两个文件夹_samples,WEB-INF拷贝到刚才建立的webapps\test下。再将src文件夹下的FCKeditor.tld拷贝到WEB-INF下。
3. 在webapps\test\下建立文件夹FCKeditor 。
4. 将刚才下载的 FCKeditor_2.4.3.zip 解压缩,然后将fckeditor文件夹下的 editor(文件夹),fckconfig.js,fckeditor.js,fckstyles.xml,fcktemplates.xml。四个文件拷贝到刚才建立的文件夹FCKeditor下。
5.修改test\_samples\jsp\sample02.jsp文件,将原来的
<FCK:editor id="EditorDefault" basePath="/FCKeditor/"
改为<FCK:editor id="EditorDefault" basePath="/test/FCKeditor/"。以后使用的时候只需将test换成项目的名称即可。
6.打开tomcat。测试Http://localhost:8080/test/_samples/jsp/sample02.jsp。
ok。
另外 : http://www.blogjava.net/youxia/archive/2007/03/15/104077.html
一、数组转成字符串:
1、 将数组中的字符转换为一个字符串
将数组中的字符转换为一个字符串
@param strToConv 要转换的字符串 ,默认以逗号分隔
@return 返回一个字符串
String[3] s={"a","b","c"}
StringUtil.convString(s)="a,b,c"
2、 static public String converString(String strToConv)
@param strToConv 要转换的字符串 ,
@param conv 分隔符,默认以逗号分隔
@return 同样返回一个字符串
String[3] s={"a","b","c"}
StringUtil.convString(s,"@")="a@b@c"
static public String converString(String strToConv, String conv)
二、空值检测:
3、
Checks if a String is empty ("") or null.
判断一个字符串是否为空,空格作非空处理。 StringUtils.isEmpty(null) = true StringUtils.isEmpty("") = true StringUtils.isEmpty(" ") = false StringUtils.isEmpty("bob") = false StringUtils.isEmpty(" bob ") = false
NOTE: This method changed in Lang version 2.0.
It no longer trims the String.
That functionality is available in isBlank().
@param str the String to check, may be null
@return true if the String is empty or null
public static boolean isEmpty(String str)
三、非空处理:
4、
Checks if a String is not empty ("") and not null.
判断一个字符串是否非空,空格作非空处理. StringUtils.isNotEmpty(null) = false StringUtils.isNotEmpty("") = false StringUtils.isNotEmpty(" ") = true StringUtils.isNotEmpty("bob") = true StringUtils.isNotEmpty(" bob ") = true
@param str the String to check, may be null
@return true if the String is not empty and not null
public static boolean isNotEmpty(String str)
5、
Checks if a String is not empty (""), not null and not whitespace only.
判断一个字符串是否非空,空格作空处理. StringUtils.isNotBlank(null) = false StringUtils.isNotBlank("") = false StringUtils.isNotBlank(" ") = false StringUtils.isNotBlank("bob") = true StringUtils.isNotBlank(" bob ") = true
@param str the String to check, may be null
@return true if the String is
not empty and not null and not whitespace
@since 2.0
public static boolean isNotBlank(String str)
四、 空格处理
6、
Removes control characters (char <= 32) from both
ends of this String, handling null by returning
null.
The String is trimmed using {@link String#trim()}.
Trim removes start and end characters <= 32.
To strip whitespace use {@link //strip(String)}.
To trim your choice of characters, use the
{@link //strip(String, String)} methods.
格式化一个字符串中的空格,有非空判断处理; StringUtils.trim(null) = null StringUtils.trim("") = "" StringUtils.trim(" ") = "" StringUtils.trim("abc") = "abc" StringUtils.trim(" abc ") = "abc"
@param str the String to be trimmed, may be null
@return the trimmed string, null if null String input
public static String trim(String str)
7、
Removes control characters (char <= 32) from both
ends of this String returning null if the String is
empty ("") after the trim or if it is null.
The String is trimmed using {@link String#trim()}.
Trim removes start and end characters <= 32.
To strip whitespace use {@link /stripToNull(String)}.
格式化一个字符串中的空格,有非空判断处理,如果为空返回null; StringUtils.trimToNull(null) = null StringUtils.trimToNull("") = null StringUtils.trimToNull(" ") = null StringUtils.trimToNull("abc") = "abc" StringUtils.trimToNull(" abc ") = "abc"
@param str the String to be trimmed, may be null
@return the trimmed String,
null if only chars <= 32, empty or null String input
@since 2.0
public static String trimToNull(String str)
8、
Removes control characters (char <= 32) from both
ends of this String returning an empty String ("") if the String
is empty ("") after the trim or if it is null.
The String is trimmed using {@link String#trim()}.
Trim removes start and end characters <= 32.
To strip whitespace use {@link /stripToEmpty(String)}.
格式化一个字符串中的空格,有非空判断处理,如果为空返回""; StringUtils.trimToEmpty(null) = "" StringUtils.trimToEmpty("") = "" StringUtils.trimToEmpty(" ") = "" StringUtils.trimToEmpty("abc") = "abc" StringUtils.trimToEmpty(" abc ") = "abc"
@param str the String to be trimmed, may be null
@return the trimmed String, or an empty String if null input
@since 2.0
public static String trimToEmpty(String str)
五、 字符串比较:
9、
Compares two Strings, returning true if they are equal.
nulls are handled without exceptions. Two null
references are considered to be equal. The comparison is case sensitive.
判断两个字符串是否相等,有非空处理。 StringUtils.equals(null, null) = true StringUtils.equals(null, "abc") = false StringUtils.equals("abc", null) = false StringUtils.equals("abc", "abc") = true StringUtils.equals("abc", "ABC") = false
@param str1 the first String, may be null
@param str2 the second String, may be null
@return true if the Strings are equal, case sensitive, or
both null
@see java.lang.String#equals(Object)
public static boolean equals(String str1, String str2)
10、
Compares two Strings, returning true if they are equal ignoring
the case.
nulls are handled without exceptions. Two null
references are considered equal. Comparison is case insensitive.
判断两个字符串是否相等,有非空处理。忽略大小写 StringUtils.equalsIgnoreCase(null, null) = true StringUtils.equalsIgnoreCase(null, "abc") = false StringUtils.equalsIgnoreCase("abc", null) = false StringUtils.equalsIgnoreCase("abc", "abc") = true StringUtils.equalsIgnoreCase("abc", "ABC") = true
@param str1 the first String, may be null
@param str2 the second String, may be null
@return true if the Strings are equal, case insensitive, or
both null
@see java.lang.String#equalsIgnoreCase(String)
public static boolean equalsIgnoreCase(String str1, String str2)
六、 IndexOf 处理
11、
Finds the first index within a String, handling null.
This method uses {@link String#indexOf(String)}.
A null String will return -1.
返回要查找的字符串所在位置,有非空处理 StringUtils.indexOf(null, *) = -1 StringUtils.indexOf(*, null) = -1 StringUtils.indexOf("", "") = 0 StringUtils.indexOf("aabaabaa", "a") = 0 StringUtils.indexOf("aabaabaa", "b") = 2 StringUtils.indexOf("aabaabaa", "ab") = 1 StringUtils.indexOf("aabaabaa", "") = 0
@param str the String to check, may be null
@param searchStr the String to find, may be null
@return the first index of the search String,
-1 if no match or null string input
@since 2.0
public static int indexOf(String str, String searchStr)
12、
Finds the first index within a String, handling null.
This method uses {@link String#indexOf(String, int)}.
A null String will return -1.
A negative start position is treated as zero.
An empty ("") search String always matches.
A start position greater than the string length only matches
an empty search String.
返回要由指定位置开始查找的字符串所在位置,有非空处理 StringUtils.indexOf(null, *, *) = -1 StringUtils.indexOf(*, null, *) = -1 StringUtils.indexOf("", "", 0) = 0 StringUtils.indexOf("aabaabaa", "a", 0) = 0 StringUtils.indexOf("aabaabaa", "b", 0) = 2 StringUtils.indexOf("aabaabaa", "ab", 0) = 1 StringUtils.indexOf("aabaabaa", "b", 3) = 5 StringUtils.indexOf("aabaabaa", "b", 9) = -1 StringUtils.indexOf("aabaabaa", "b", -1) = 2 StringUtils.indexOf("aabaabaa", "", 2) = 2 StringUtils.indexOf("abc", "", 9) = 3
@param str the String to check, may be null
@param searchStr the String to find, may be null
@param startPos the start position, negative treated as zero
@return the first index of the search String,
-1 if no match or null string input
@since 2.0
public static int indexOf(String str, String searchStr, int startPos)
七、 子字符串处理:
13、
Gets a substring from the specified String avoiding exceptions.
A negative start position can be used to start n
characters from the end of the String.
A null String will return null.
An empty ("") String will return "".
返回指定位置开始的字符串中的所有字符 StringUtils.substring(null, *) = null StringUtils.substring("", *) = "" StringUtils.substring("abc", 0) = "abc" StringUtils.substring("abc", 2) = "c" StringUtils.substring("abc", 4) = "" StringUtils.substring("abc", -2) = "bc" StringUtils.substring("abc", -4) = "abc"
@param str the String to get the substring from, may be null
@param start the position to start from, negative means
count back from the end of the String by this many characters
@return substring from start position, null if null String input
public static String substring(String str, int start)
14、
Gets a substring from the specified String avoiding exceptions.
A negative start position can be used to start/end n
characters from the end of the String.
The returned substring starts with the character in the start
position and ends before the end position. All postion counting is
zero-based -- i.e., to start at the beginning of the string use
start = 0. Negative start and end positions can be used to
specify offsets relative to the end of the String.
If start is not strictly to the left of end, ""
is returned.
返回由开始位置到结束位置之间的子字符串 StringUtils.substring(null, *, *) = null StringUtils.substring("", * , *) = ""; StringUtils.substring("abc", 0, 2) = "ab" StringUtils.substring("abc", 2, 0) = "" StringUtils.substring("abc", 2, 4) = "c" StringUtils.substring("abc", 4, 6) = "" StringUtils.substring("abc", 2, 2) = "" StringUtils.substring("abc", -2, -1) = "b" StringUtils.substring("abc", -4, 2) = "ab"
@param str the String to get the substring from, may be null
@param start the position to start from, negative means
count back from the end of the String by this many characters
@param end the position to end at (exclusive), negative means
count back from the end of the String by this many characters
@return substring from start position to end positon,
null if null String input
public static String substring(String str, int start, int end)
15、 SubStringAfter/SubStringBefore(前后子字符串处理:
Gets the substring before the first occurance of a separator.
The separator is not returned.
A null string input will return null.
An empty ("") string input will return the empty string.
A null separator will return the input string.
返回指定字符串之前的所有字符 StringUtils.substringBefore(null, *) = null StringUtils.substringBefore("", *) = "" StringUtils.substringBefore("abc", "a") = "" StringUtils.substringBefore("abcba", "b") = "a" StringUtils.substringBefore("abc", "c") = "ab" StringUtils.substringBefore("abc", "d") = "abc" StringUtils.substringBefore("abc", "") = "" StringUtils.substringBefore("abc", null) = "abc"
@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring before the first occurance of the separator,
null if null String input
@since 2.0
public static String substringBefore(String str, String separator)
16、
Gets the substring after the first occurance of a separator.
The separator is not returned.
A null string input will return null.
An empty ("") string input will return the empty string.
A null separator will return the empty string if the
input string is not null.
返回指定字符串之后的所有字符 StringUtils.substringAfter(null, *) = null StringUtils.substringAfter("", *) = "" StringUtils.substringAfter(*, null) = "" StringUtils.substringAfter("abc", "a") = "bc" StringUtils.substringAfter("abcba", "b") = "cba" StringUtils.substringAfter("abc", "c") = "" StringUtils.substringAfter("abc", "d") = "" StringUtils.substringAfter("abc", "") = "abc"
@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring after the first occurance of the separator,
null if null String input
@since 2.0
public static String substringAfter(String str, String separator)
17、
Gets the substring before the last occurance of a separator.
The separator is not returned.
A null string input will return null.
An empty ("") string input will return the empty string.
An empty or null separator will return the input string.
返回最后一个指定字符串之前的所有字符 StringUtils.substringBeforeLast(null, *) = null StringUtils.substringBeforeLast("", *) = "" StringUtils.substringBeforeLast("abcba", "b") = "abc" StringUtils.substringBeforeLast("abc", "c") = "ab" StringUtils.substringBeforeLast("a", "a") = "" StringUtils.substringBeforeLast("a", "z") = "a" StringUtils.substringBeforeLast("a", null) = "a" StringUtils.substringBeforeLast("a", "") = "a"
@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring before the last occurance of the separator,
null if null String input
@since 2.0
public static String substringBeforeLast(String str, String separator)
18、
Gets the substring after the last occurance of a separator.
The separator is not returned.
A null string input will return null.
An empty ("") string input will return the empty string.
An empty or null separator will return the empty string if
the input string is not null.
返回最后一个指定字符串之后的所有字符 StringUtils.substringAfterLast(null, *) = null StringUtils.substringAfterLast("", *) = "" StringUtils.substringAfterLast(*, "") = "" StringUtils.substringAfterLast(*, null) = "" StringUtils.substringAfterLast("abc", "a") = "bc" StringUtils.substringAfterLast("abcba", "b") = "a" StringUtils.substringAfterLast("abc", "c") = "" StringUtils.substringAfterLast("a", "a") = "" StringUtils.substringAfterLast("a", "z") = ""
@param str the String to get a substring from, may be null
@param separator the String to search for, may be null
@return the substring after the last occurance of the separator,
null if null String input
@since 2.0
public static String substringAfterLast(String str, String separator)
八、 Replacing(字符串替换)
19、
Replaces all occurances of a String within another String.
A null reference passed to this method is a no-op.
以指定字符串替换原来字符串的的指定字符串 StringUtils.replace(null, *, *) = null StringUtils.replace("", *, *) = "" StringUtils.replace("aba", null, null) = "aba" StringUtils.replace("aba", null, null) = "aba" StringUtils.replace("aba", "a", null) = "aba" StringUtils.replace("aba", "a", "") = "aba" StringUtils.replace("aba", "a", "z") = "zbz"
@param text text to search and replace in, may be null
@param repl the String to search for, may be null
@param with the String to replace with, may be null
@return the text with any replacements processed,
null if null String input
@see #replace(String text, String repl, String with, int max)
public static String replace(String text, String repl, String with)
20、
Replaces a String with another String inside a larger String,
for the first max values of the search String.
A null reference passed to this method is a no-op.
以指定字符串最大替换原来字符串的的指定字符串 StringUtils.replace(null, *, *, *) = null StringUtils.replace("", *, *, *) = "" StringUtils.replace("abaa", null, null, 1) = "abaa" StringUtils.replace("abaa", null, null, 1) = "abaa" StringUtils.replace("abaa", "a", null, 1) = "abaa" StringUtils.replace("abaa", "a", "", 1) = "abaa" StringUtils.replace("abaa", "a", "z", 0) = "abaa" StringUtils.replace("abaa", "a", "z", 1) = "zbaa" StringUtils.replace("abaa", "a", "z", 2) = "zbza" StringUtils.replace("abaa", "a", "z", -1) = "zbzz"
@param text text to search and replace in, may be null
@param repl the String to search for, may be null
@param with the String to replace with, may be null
@param max maximum number of values to replace, or -1 if no maximum
@return the text with any replacements processed,
null if null String input
public static String replace(String text, String repl, String with, int max)
九、 Case conversion(大小写转换)
21、
Converts a String to upper case as per {@link String#toUpperCase()}.
A null input String returns null.
将一个字符串变为大写 StringUtils.upperCase(null) = null StringUtils.upperCase("") = "" StringUtils.upperCase("aBc") = "ABC"
@param str the String to upper case, may be null
@return the upper cased String, null if null String input
public static String upperCase(String str) 22、
Converts a String to lower case as per {@link String#toLowerCase()}.
A null input String returns null.
将一个字符串转换为小写 StringUtils.lowerCase(null) = null StringUtils.lowerCase("") = "" StringUtils.lowerCase("aBc") = "abc"
@param str the String to lower case, may be null
@return the lower cased String, null if null String input
public static String lowerCase(String str) 23、
Capitalizes a String changing the first letter to title case as
per {@link Character#toTitleCase(char)}. No other letters are changed.
For a word based alorithm, see {@link /WordUtils#capitalize(String)}.
A null input String returns null.
StringUtils.capitalize(null) = null StringUtils.capitalize("") = "" StringUtils.capitalize("cat") = "Cat" StringUtils.capitalize("cAt") = "CAt"
@param str the String to capitalize, may be null
@return the capitalized String, null if null String input
@see /WordUtils#capitalize(String)
@see /uncapitalize(String)
@since 2.0
将字符串中的首字母大写
public static String capitalize(String str)